mirror of
https://gitee.com/ssssssss-team/magic-api.git
synced 2026-06-01 03:21:25 +08:00
上传、备份还原、注册日志
This commit is contained in:
@@ -82,7 +82,7 @@ public class ZipResource implements Resource {
|
||||
public String name() {
|
||||
String name = this.path;
|
||||
if (isDirectory()) {
|
||||
name = this.path.substring(0, name.length() - 1);
|
||||
name = this.path.length() > 0 ? this.path.substring(0, name.length() - 1) : "";
|
||||
}
|
||||
int index = name.lastIndexOf("/");
|
||||
return index > -1 ? name.substring(index + 1) : name;
|
||||
|
||||
@@ -4,15 +4,17 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.ssssssss.magicapi.config.MagicConfiguration;
|
||||
import org.ssssssss.magicapi.model.Backup;
|
||||
import org.ssssssss.magicapi.model.JsonBean;
|
||||
import org.ssssssss.magicapi.model.*;
|
||||
import org.ssssssss.magicapi.provider.MagicBackupService;
|
||||
import org.ssssssss.magicapi.service.MagicDynamicRegistry;
|
||||
import org.ssssssss.magicapi.utils.JsonUtils;
|
||||
import org.ssssssss.magicapi.utils.WebUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class MagicBackupController extends MagicController {
|
||||
public class MagicBackupController extends MagicController implements MagicExceptionHandler{
|
||||
|
||||
private final MagicBackupService service;
|
||||
|
||||
@@ -27,18 +29,45 @@ public class MagicBackupController extends MagicController {
|
||||
return new JsonBean<>(service.backupList(timestamp == null ? System.currentTimeMillis() : timestamp));
|
||||
}
|
||||
|
||||
@PostMapping("/backup")
|
||||
@GetMapping("/backup/rollback")
|
||||
@ResponseBody
|
||||
public JsonBean<Boolean> doBackup(String tag) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
MagicConfiguration.getMagicResourceService().export(null, null, baos);
|
||||
Backup backup = new Backup();
|
||||
backup.setId("full");
|
||||
backup.setType("full");
|
||||
backup.setName("全量备份");
|
||||
backup.setContent(baos.toByteArray());
|
||||
backup.setTag(tag);
|
||||
service.doBackup(backup);
|
||||
public JsonBean<Boolean> rollback(String id, Long timestamp) throws IOException {
|
||||
Backup backup = service.backupInfo(id, timestamp);
|
||||
if("full".equals(id)){
|
||||
service.doBackupAll("还原全量备份前,系统自动全量备份", WebUtils.currentUserName());
|
||||
configuration.getMagicAPIService().upload(new ByteArrayInputStream(backup.getContent()), Constants.UPLOAD_MODE_FULL);
|
||||
return new JsonBean<>(true);
|
||||
}
|
||||
if(backup.getType().endsWith("-group")){
|
||||
Group group = JsonUtils.readValue(backup.getContent(), Group.class);
|
||||
return new JsonBean<>(MagicConfiguration.getMagicResourceService().saveGroup(group));
|
||||
}
|
||||
MagicEntity entity = configuration.getMagicDynamicRegistries().stream()
|
||||
.map(MagicDynamicRegistry::getMagicResourceStorage)
|
||||
.filter(it -> it.folder().equals(backup.getType()))
|
||||
.map(it -> it.read(backup.getContent()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if(entity != null){
|
||||
return new JsonBean<>(MagicConfiguration.getMagicResourceService().saveFile(entity));
|
||||
}
|
||||
return new JsonBean<>(false);
|
||||
}
|
||||
|
||||
@GetMapping("/backup")
|
||||
@ResponseBody
|
||||
public JsonBean<String> backup(Long timestamp, String id) {
|
||||
notBlank(id, PARAMETER_INVALID);
|
||||
notNull(timestamp, PARAMETER_INVALID);
|
||||
Backup backup = service.backupInfo(id, timestamp);
|
||||
MagicEntity entity = JsonUtils.readValue(backup.getContent(), MagicEntity.class);
|
||||
return new JsonBean<>(entity == null ? null : entity.getScript());
|
||||
}
|
||||
|
||||
@PostMapping("/backup/full")
|
||||
@ResponseBody
|
||||
public JsonBean<Boolean> doBackup() throws IOException {
|
||||
service.doBackupAll("主动全量备份", WebUtils.currentUserName());
|
||||
return new JsonBean<>(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,8 +244,7 @@ public class MagicWorkbenchController extends MagicController implements MagicEx
|
||||
@ResponseBody
|
||||
public JsonBean<Boolean> upload(MultipartFile file, String mode) throws IOException {
|
||||
notNull(file, FILE_IS_REQUIRED);
|
||||
magicAPIService.upload(file.getInputStream(), mode);
|
||||
return new JsonBean<>(SUCCESS, true);
|
||||
return new JsonBean<>(magicAPIService.upload(file.getInputStream(), mode));
|
||||
}
|
||||
|
||||
@RequestMapping("/push")
|
||||
|
||||
@@ -2,5 +2,5 @@ package org.ssssssss.magicapi.event;
|
||||
|
||||
public enum EventAction {
|
||||
|
||||
CREATE, SAVE, DELETE, MOVE, LOAD, WS_C_S, WS_S_C, RELOAD
|
||||
CREATE, SAVE, DELETE, MOVE, LOAD, WS_C_S, WS_S_C, RELOAD, CLEAR
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ public interface JsonCodeConstants {
|
||||
|
||||
JsonCode PATH_CONFLICT = new JsonCode(0, "该路径已被使用,请换一个路径在试");
|
||||
|
||||
JsonCode RESOURCE_PATH_CONFLICT = new JsonCode(0, "资源中[%s]有冲突,请检查");
|
||||
|
||||
JsonCode MOVE_PATH_CONFLICT = new JsonCode(0, "移动后路径会冲突,请换一个路径在试");
|
||||
|
||||
JsonCode FUNCTION_PATH_CONFLICT = new JsonCode(0, "该路径已被映射,请换一个请求方法或路径");
|
||||
|
||||
@@ -83,7 +83,7 @@ public interface MagicAPIService extends MagicModule {
|
||||
/**
|
||||
* 上传
|
||||
*/
|
||||
void upload(InputStream inputStream, String mode) throws IOException;
|
||||
boolean upload(InputStream inputStream, String mode) throws IOException;
|
||||
|
||||
/**
|
||||
* 下载
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.ssssssss.magicapi.provider;
|
||||
|
||||
import org.ssssssss.magicapi.model.Backup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -20,6 +21,8 @@ public interface MagicBackupService {
|
||||
*/
|
||||
void doBackup(Backup backup);
|
||||
|
||||
void doBackupAll(String name, String createBy) throws IOException;
|
||||
|
||||
/**
|
||||
* 根据时间戳查询最近的 FETCH_SIZE 条记录
|
||||
*
|
||||
|
||||
@@ -12,6 +12,8 @@ import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.ssssssss.magicapi.config.WebSocketSessionManager;
|
||||
import org.ssssssss.magicapi.controller.MagicWebSocketDispatcher;
|
||||
import org.ssssssss.magicapi.event.EventAction;
|
||||
import org.ssssssss.magicapi.event.MagicEvent;
|
||||
import org.ssssssss.magicapi.exception.MagicResourceNotFoundException;
|
||||
import org.ssssssss.magicapi.model.*;
|
||||
import org.ssssssss.magicapi.provider.MagicAPIService;
|
||||
@@ -132,7 +134,8 @@ public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstant
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(InputStream inputStream, String mode) throws IOException {
|
||||
public boolean upload(InputStream inputStream, String mode) throws IOException {
|
||||
return resourceService.upload(inputStream, Constants.UPLOAD_MODE_FULL.equals(mode));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,6 +187,8 @@ public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstant
|
||||
return processWebSocketMessageReceived(magicNotify.getSessionId(), magicNotify.getContent());
|
||||
case WS_S_C:
|
||||
return processWebSocketSendMessage(magicNotify.getSessionId(), magicNotify.getContent());
|
||||
case CLEAR:
|
||||
publisher.publishEvent(new MagicEvent("clear", EventAction.CLEAR, Constants.EVENT_SOURCE_NOTIFY));
|
||||
}
|
||||
return resourceService.processNotify(magicNotify);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.ssssssss.magicapi.config.MagicConfiguration;
|
||||
import org.ssssssss.magicapi.event.FileEvent;
|
||||
import org.ssssssss.magicapi.event.GroupEvent;
|
||||
import org.ssssssss.magicapi.model.Backup;
|
||||
@@ -14,6 +15,8 @@ import org.ssssssss.magicapi.provider.MagicBackupService;
|
||||
import org.ssssssss.magicapi.utils.JsonUtils;
|
||||
import org.ssssssss.magicapi.utils.WebUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -58,6 +61,19 @@ public class MagicDatabaseBackupService implements MagicBackupService {
|
||||
this.FIND_BY_ID_AND_TIMESTAMP = String.format("select * from %s where id = ? and create_date = ?", tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doBackupAll(String name, String createBy) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
MagicConfiguration.getMagicResourceService().export(null, null, baos);
|
||||
Backup backup = new Backup();
|
||||
backup.setId("full");
|
||||
backup.setType("full");
|
||||
backup.setName(name);
|
||||
backup.setCreateBy(createBy);
|
||||
backup.setContent(baos.toByteArray());
|
||||
doBackup(backup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doBackup(Backup backup) {
|
||||
try {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package org.ssssssss.magicapi.service;
|
||||
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.ssssssss.magicapi.event.EventAction;
|
||||
import org.ssssssss.magicapi.event.FileEvent;
|
||||
import org.ssssssss.magicapi.event.GroupEvent;
|
||||
import org.ssssssss.magicapi.event.MagicEvent;
|
||||
import org.ssssssss.magicapi.exception.MagicAPIException;
|
||||
import org.ssssssss.magicapi.model.MagicEntity;
|
||||
import org.ssssssss.magicapi.provider.MagicResourceStorage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -55,6 +57,17 @@ public abstract class AbstractMagicDynamicRegistry<T extends MagicEntity> implem
|
||||
return false;
|
||||
}
|
||||
|
||||
@EventListener(condition = "#event.action == T(org.ssssssss.magicapi.event.EventAction).CLEAR")
|
||||
public void clear(MagicEvent event){
|
||||
Iterator<Map.Entry<String, MappingNode<T>>> iterator = mappings.entrySet().iterator();
|
||||
while (iterator.hasNext()){
|
||||
Map.Entry<String, MappingNode<T>> entry = iterator.next();
|
||||
unregister(entry.getValue());
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void processEvent(FileEvent event) {
|
||||
T info = (T) event.getEntity();
|
||||
if (event.getAction() == EventAction.DELETE) {
|
||||
@@ -102,16 +115,6 @@ public abstract class AbstractMagicDynamicRegistry<T extends MagicEntity> implem
|
||||
|
||||
}
|
||||
|
||||
public boolean register(List<T> entities) {
|
||||
mappings.values().stream().distinct().forEach(node -> {
|
||||
unregister(node);
|
||||
mappings.remove(node.getMappingKey());
|
||||
mappings.remove(node.getEntity().getId());
|
||||
});
|
||||
entities.forEach(this::register);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected MappingNode<T> buildMappingNode(T entity) {
|
||||
MappingNode<T> mappingNode = new MappingNode<>(entity);
|
||||
mappingNode.setMappingKey(this.magicResourceStorage.buildKey(entity));
|
||||
|
||||
@@ -12,11 +12,6 @@ public interface MagicDynamicRegistry<T extends MagicEntity> {
|
||||
*/
|
||||
boolean register(T entity);
|
||||
|
||||
/**
|
||||
* 注册全部
|
||||
*/
|
||||
boolean register(List<T> entities);
|
||||
|
||||
/**
|
||||
* 取消注册
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.ssssssss.magicapi.adapter.Resource;
|
||||
import org.ssssssss.magicapi.model.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -98,6 +99,8 @@ public interface MagicResourceService {
|
||||
|
||||
boolean unlock(String id);
|
||||
|
||||
boolean upload(InputStream inputStream, boolean full) throws IOException;
|
||||
|
||||
|
||||
public String getGroupPath(String groupId);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.ssssssss.magicapi.service;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.ssssssss.magicapi.event.FileEvent;
|
||||
import org.ssssssss.magicapi.event.GroupEvent;
|
||||
import org.ssssssss.magicapi.event.MagicEvent;
|
||||
import org.ssssssss.magicapi.model.Constants;
|
||||
import org.ssssssss.magicapi.model.MagicNotify;
|
||||
import org.ssssssss.magicapi.provider.MagicNotifyService;
|
||||
@@ -47,4 +48,9 @@ public class MagicSynchronizationService {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener(condition = "#event.action == T(org.ssssssss.magicapi.event.EventAction).CLEAR && #event.source != T(org.ssssssss.magicapi.model.Constants).EVENT_SOURCE_NOTIFY")
|
||||
public void onClearEvent(MagicEvent event){
|
||||
magicNotifyService.sendNotify(new MagicNotify(instanceId, null, event.getAction(), null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import org.ssssssss.magicapi.provider.MagicResourceStorage;
|
||||
import org.ssssssss.magicapi.service.MagicResourceService;
|
||||
import org.ssssssss.magicapi.utils.PathUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class AbstractPathMagicResourceStorage<T extends PathMagicEntity> implements MagicResourceStorage<T> {
|
||||
|
||||
|
||||
@@ -25,6 +27,10 @@ public abstract class AbstractPathMagicResourceStorage<T extends PathMagicEntity
|
||||
this.magicResourceService = magicResourceService;
|
||||
}
|
||||
|
||||
public String buildMappingKey(T entity, String path) {
|
||||
return PathUtils.replaceSlash("/" + Objects.toString(path, "") + "/"+ Objects.toString(entity.getPath(), ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildScriptName(T entity) {
|
||||
String fullGroupName = magicResourceService.getGroupName(entity.getGroupId());
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.ssssssss.magicapi.service.impl;
|
||||
|
||||
import org.ssssssss.magicapi.model.ApiInfo;
|
||||
import org.ssssssss.magicapi.utils.PathUtils;
|
||||
|
||||
public class ApiInfoMagicResourceStorage extends AbstractPathMagicResourceStorage<ApiInfo> {
|
||||
|
||||
@@ -17,6 +16,7 @@ public class ApiInfoMagicResourceStorage extends AbstractPathMagicResourceStorag
|
||||
|
||||
@Override
|
||||
public String buildMappingKey(ApiInfo info) {
|
||||
return info.getMethod().toUpperCase() + ":" + PathUtils.replaceSlash("/" + magicResourceService.getGroupPath(info.getGroupId()) + "/" + info.getPath());
|
||||
return info.getMethod().toUpperCase() + ":" + buildMappingKey(info, magicResourceService.getGroupPath(info.getGroupId()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.ssssssss.magicapi.service.impl;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
@@ -25,6 +27,8 @@ public class DataSourceMagicDynamicRegistry extends AbstractMagicDynamicRegistry
|
||||
|
||||
private final MagicDynamicDataSource magicDynamicDataSource;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DataSourceMagicDynamicRegistry.class);
|
||||
|
||||
private static final ClassLoader CLASSLOADER = DataSourceMagicDynamicRegistry.class.getClassLoader();
|
||||
|
||||
// copy from DataSourceBuilder
|
||||
@@ -57,12 +61,14 @@ public class DataSourceMagicDynamicRegistry extends AbstractMagicDynamicRegistry
|
||||
}
|
||||
DataSource datasource = createDataSource(getDataSourceType(info.getType()), properties);
|
||||
magicDynamicDataSource.put(info.getId(), info.getKey(), info.getName(), datasource, info.getMaxRows());
|
||||
logger.debug("注册数据源:{}", info.getKey());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean unregister(DataSourceInfo info) {
|
||||
logger.debug("取消注册数据源:{}", info.getKey());
|
||||
return magicDynamicDataSource.delete(info.getKey());
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@ import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.ssssssss.magicapi.adapter.Resource;
|
||||
import org.ssssssss.magicapi.adapter.resource.ZipResource;
|
||||
import org.ssssssss.magicapi.event.EventAction;
|
||||
import org.ssssssss.magicapi.event.FileEvent;
|
||||
import org.ssssssss.magicapi.event.GroupEvent;
|
||||
import org.ssssssss.magicapi.event.MagicEvent;
|
||||
import org.ssssssss.magicapi.exception.InvalidArgumentException;
|
||||
import org.ssssssss.magicapi.model.*;
|
||||
import org.ssssssss.magicapi.provider.MagicResourceStorage;
|
||||
@@ -17,6 +19,7 @@ import org.ssssssss.magicapi.utils.JsonUtils;
|
||||
import org.ssssssss.magicapi.utils.WebUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
@@ -96,34 +99,37 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
|
||||
return false;
|
||||
}
|
||||
|
||||
private void init(){
|
||||
groupMappings.clear();
|
||||
groupCache.clear();
|
||||
fileMappings.clear();
|
||||
fileCache.clear();
|
||||
pathCache.clear();
|
||||
storages.forEach((key, registry) -> {
|
||||
if (registry.requirePath()) {
|
||||
pathCache.put(registry.folder(), new HashMap<>(32));
|
||||
}
|
||||
Resource folder = root.getDirectory(key);
|
||||
if (registry.allowRoot()) {
|
||||
String rootId = key + ":0";
|
||||
Group group = new Group();
|
||||
group.setId(rootId);
|
||||
group.setType(key);
|
||||
group.setParentId("0");
|
||||
putGroup(group, folder);
|
||||
}
|
||||
if (!folder.exists()) {
|
||||
folder.mkdir();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
writeLock(() -> {
|
||||
groupMappings.clear();
|
||||
groupCache.clear();
|
||||
fileMappings.clear();
|
||||
fileCache.clear();
|
||||
pathCache.clear();
|
||||
this.init();
|
||||
this.root.readAll();
|
||||
storages.forEach((key, registry) -> {
|
||||
if (registry.requirePath()) {
|
||||
pathCache.put(registry.folder(), new HashMap<>(32));
|
||||
}
|
||||
Resource folder = root.getDirectory(key);
|
||||
if (registry.allowRoot()) {
|
||||
String rootId = key + ":0";
|
||||
Group group = new Group();
|
||||
group.setId(rootId);
|
||||
group.setType(key);
|
||||
group.setParentId("0");
|
||||
putGroup(group, folder);
|
||||
}
|
||||
if (!folder.exists()) {
|
||||
folder.mkdir();
|
||||
} else {
|
||||
refreshGroup(folder, registry);
|
||||
}
|
||||
});
|
||||
storages.forEach((key, registry) -> refreshGroup(root.getDirectory(key), registry));
|
||||
fileCache.values().forEach(entity -> {
|
||||
Group group = groupCache.get(entity.getGroupId());
|
||||
publisher.publishEvent(new FileEvent(group.getType(), EventAction.LOAD, entity));
|
||||
@@ -173,9 +179,11 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
|
||||
}
|
||||
Resource groupResource;
|
||||
GroupEvent event = new GroupEvent(group.getType(), group.getId() == null ? EventAction.CREATE : EventAction.SAVE, group);
|
||||
if (group.getId() == null) {
|
||||
if (group.getId() == null || !groupCache.containsKey(group.getId())) {
|
||||
// 添加分组
|
||||
group.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
if(group.getId() == null){
|
||||
group.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
}
|
||||
groupResource = resource.getDirectory(group.getName());
|
||||
// 判断分组文件夹需要不存在
|
||||
isTrue(!groupResource.exists(), FILE_SAVE_FAILURE);
|
||||
@@ -186,7 +194,7 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
|
||||
groupResource = resource.getDirectory(group.getName());
|
||||
isTrue(oldResource != null && oldResource.exists(), GROUP_NOT_FOUND);
|
||||
// 名字不一样时重命名
|
||||
if (!oldResource.name().equals(resource.name())) {
|
||||
if (!oldResource.getFilePath().equals(resource.getFilePath())) {
|
||||
isTrue(oldResource.renameTo(groupResource), FILE_SAVE_FAILURE);
|
||||
}
|
||||
}
|
||||
@@ -433,13 +441,14 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
|
||||
String filename = entity.getName() + storage.suffix();
|
||||
// 获取修改前的信息
|
||||
Resource fileResource = groupResource.getResource(filename);
|
||||
if (entity.getId() == null) {
|
||||
isTrue(!fileResource.exists(), FILE_SAVE_FAILURE);
|
||||
// 新增操作赋值
|
||||
entity.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
if (entity.getId() == null || !fileCache.containsKey(entity.getId())) {
|
||||
if(entity.getId() == null){
|
||||
isTrue(!fileResource.exists(), FILE_SAVE_FAILURE);
|
||||
// 新增操作赋值
|
||||
entity.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
}
|
||||
entity.setCreateTime(System.currentTimeMillis());
|
||||
entity.setCreateBy(WebUtils.currentUserName());
|
||||
|
||||
} else {
|
||||
// 修改操作赋值
|
||||
entity.setUpdateTime(System.currentTimeMillis());
|
||||
@@ -612,6 +621,102 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
|
||||
return doLockResource(id, Constants.UNLOCK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean upload(InputStream inputStream, boolean full) throws IOException {
|
||||
try {
|
||||
ZipResource zipResource = new ZipResource(inputStream);
|
||||
Set<Group> groups = new LinkedHashSet<>();
|
||||
Set<MagicEntity> entities = new LinkedHashSet<>();
|
||||
return writeLock(() -> {
|
||||
readAllResource(zipResource, groups, entities, !full);
|
||||
if(full){
|
||||
// 全量模式先删除处理。
|
||||
root.delete();
|
||||
this.init();
|
||||
publisher.publishEvent(new MagicEvent("clear", EventAction.CLEAR));
|
||||
}
|
||||
for (Group group : groups) {
|
||||
saveGroup(group);
|
||||
}
|
||||
for (MagicEntity entity : entities) {
|
||||
saveFile(entity);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} finally {
|
||||
IoUtils.close(inputStream);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void readAllResource(Resource root, Set<Group> groups, Set<MagicEntity> entities, boolean checked){
|
||||
readAllResource(root, null, groups, entities, null, "/", checked);
|
||||
}
|
||||
|
||||
private void readAllResource(Resource root, MagicResourceStorage<? extends MagicEntity> storage, Set<Group> groups, Set<MagicEntity> entities, Set<String> mappingKeys, String path, boolean checked){
|
||||
storage = storage == null ? storages.get(root.name()) : storage;
|
||||
if(storage != null){
|
||||
mappingKeys = mappingKeys == null ? new HashSet<>() : mappingKeys;
|
||||
if(!storage.allowRoot()){
|
||||
Resource resource = root.getResource(Constants.GROUP_METABASE);
|
||||
// 分组信息不存在时,直接返回不处理
|
||||
if(resource.exists()){
|
||||
// 读取分组信息
|
||||
Group group = JsonUtils.readValue(resource.read(), Group.class);
|
||||
group.setType(mappingV1Type(group.getType()));
|
||||
groups.add(group);
|
||||
if(storage.requirePath()){
|
||||
path = path + Objects.toString(group.getPath(), "") + "/";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for(Resource file : root.files(storage.suffix())){
|
||||
MagicEntity entity = storage.read(file.read());
|
||||
if(storage.allowRoot()){
|
||||
entity.setGroupId(storage.folder() + ":0");
|
||||
}
|
||||
String mappingKey;
|
||||
if(storage instanceof AbstractPathMagicResourceStorage){
|
||||
mappingKey = ((AbstractPathMagicResourceStorage) storage).buildMappingKey((PathMagicEntity) entity, path);
|
||||
}else{
|
||||
mappingKey = storage.buildKey(entity);
|
||||
}
|
||||
if(checked){
|
||||
String groupId = entity.getGroupId();
|
||||
// 名字和路径冲突检查
|
||||
fileCache.values().stream()
|
||||
// 同一分组
|
||||
.filter(it -> Objects.equals(it.getGroupId(), groupId))
|
||||
// 非自身
|
||||
.filter(it -> !it.getId().equals(entity.getId()))
|
||||
.forEach(it -> isTrue(!Objects.equals(it.getName(), entity.getName()), RESOURCE_PATH_CONFLICT.format(entity.getName())));
|
||||
|
||||
}
|
||||
// 自检
|
||||
isTrue(mappingKeys.add(mappingKey), RESOURCE_PATH_CONFLICT.format(mappingKey));
|
||||
entities.add(entity);
|
||||
}
|
||||
|
||||
}
|
||||
for (Resource directory : root.dirs()) {
|
||||
readAllResource(directory, storage, groups, entities, mappingKeys, path, checked);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容1.x版本
|
||||
*/
|
||||
private String mappingV1Type(String type){
|
||||
if("1".equals(type)){
|
||||
return "api";
|
||||
} else if ("2".equals(type)){
|
||||
return "function";
|
||||
}
|
||||
return type;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupName(String groupId) {
|
||||
return findGroups(groupId).stream()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.ssssssss.magicapi.service.impl;
|
||||
|
||||
import org.ssssssss.magicapi.model.FunctionInfo;
|
||||
import org.ssssssss.magicapi.utils.PathUtils;
|
||||
|
||||
public class FunctionInfoMagicResourceStorage extends AbstractPathMagicResourceStorage<FunctionInfo> {
|
||||
|
||||
@@ -17,6 +16,6 @@ public class FunctionInfoMagicResourceStorage extends AbstractPathMagicResourceS
|
||||
|
||||
@Override
|
||||
public String buildMappingKey(FunctionInfo info) {
|
||||
return PathUtils.replaceSlash("/" + magicResourceService.getGroupPath(info.getGroupId()) + "/" + info.getPath());
|
||||
return buildMappingKey(info, magicResourceService.getGroupPath(info.getGroupId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.ssssssss.magicapi.service.impl;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.ssssssss.magicapi.event.FileEvent;
|
||||
import org.ssssssss.magicapi.event.GroupEvent;
|
||||
@@ -18,6 +20,8 @@ import java.util.function.Function;
|
||||
|
||||
public class FunctionMagicDynamicRegistry extends AbstractMagicDynamicRegistry<FunctionInfo> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FunctionMagicDynamicRegistry.class);
|
||||
|
||||
public FunctionMagicDynamicRegistry(MagicResourceStorage<FunctionInfo> magicResourceStorage) {
|
||||
super(magicResourceStorage);
|
||||
MagicResourceLoader.addFunctionLoader(this::lookupLambdaFunction);
|
||||
@@ -56,4 +60,14 @@ public class FunctionMagicDynamicRegistry extends AbstractMagicDynamicRegistry<F
|
||||
processEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean register(MappingNode<FunctionInfo> mappingNode) {
|
||||
logger.debug("注册函数:{}", mappingNode.getMappingKey());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregister(MappingNode<FunctionInfo> mappingNode) {
|
||||
logger.debug("取消注册函数:{}", mappingNode.getMappingKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,4 +158,13 @@ public class IoUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void close(Closeable closeable){
|
||||
try {
|
||||
if(closeable != null){
|
||||
closeable.close();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user