接口选项,分组选项,分组路径,屏蔽备份

This commit is contained in:
mxd 2021-12-31 21:39:54 +08:00
parent 663a7d9588
commit a4c3dcd3c7
9 changed files with 58 additions and 231 deletions

View File

@ -71,7 +71,6 @@ import org.ssssssss.script.reflection.JavaReflection;
import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
@ -398,13 +397,6 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
};
}
@Bean
@ConditionalOnMissingBean(MagicBackupService.class)
@ConditionalOnProperty(prefix = "magic-api", name = "backup-config.resource-type", havingValue = "file", matchIfMissing = true)
public MagicBackupService magicFileBackupService() {
return new MagicFileBackupService(new File(properties.getBackupConfig().getLocation()));
}
/**
* 注入API调用Service
*/
@ -538,7 +530,7 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
MagicAPIService magicAPIService,
MagicNotifyService magicNotifyService,
RequestMagicDynamicRegistry requestMagicDynamicRegistry,
MagicBackupService magicBackupService) throws NoSuchMethodException {
@Autowired(required = false) MagicBackupService magicBackupService) throws NoSuchMethodException {
logger.info("magic-api工作目录:{}", magicResource);
AsyncCall.setThreadPoolExecutorSize(properties.getThreadPoolExecutorSize());
DataType.DATE_PATTERNS = properties.getDatePattern();

View File

@ -54,7 +54,7 @@ public class MagicConfiguration {
private MagicBackupService magicBackupService;
private MagicResourceService magicResourceService;
private static MagicResourceService magicResourceService;
private List<MagicDynamicRegistry<? extends MagicEntity>> magicDynamicRegistries;
@ -177,12 +177,12 @@ public class MagicConfiguration {
this.magicDynamicDataSource = magicDynamicDataSource;
}
public MagicResourceService getMagicResourceService() {
return magicResourceService;
public static MagicResourceService getMagicResourceService() {
return MagicConfiguration.magicResourceService;
}
public void setMagicResourceService(MagicResourceService magicResourceService) {
this.magicResourceService = magicResourceService;
MagicConfiguration.magicResourceService = magicResourceService;
}
public List<MagicDynamicRegistry<? extends MagicEntity>> getMagicDynamicRegistries() {

View File

@ -108,11 +108,11 @@ public class RequestHandler extends MagicController {
}
requestEntity.setHeaders(headers);
List<Path> paths = new ArrayList<>(info.getPaths());
// MappingHandlerMapping.findGroups(info.getGroupId())
// .stream()
// .flatMap(it -> it.getPaths().stream())
// .filter(it -> !paths.contains(it))
// .forEach(paths::add);
MagicConfiguration.getMagicResourceService().getGroupsByFileId(info.getId())
.stream()
.flatMap(it -> it.getPaths().stream())
.filter(it -> !paths.contains(it))
.forEach(paths::add);
Object bodyValue = readRequestBody(requestEntity.getRequest());
requestEntity.setRequestBody(bodyValue);
String scriptName = requestMagicDynamicRegistry.getMagicResourceStorage().buildScriptName(info);

View File

@ -2,6 +2,7 @@ package org.ssssssss.magicapi.model;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import org.ssssssss.magicapi.config.MagicConfiguration;
import org.ssssssss.magicapi.utils.JsonUtils;
import java.util.*;
@ -24,7 +25,7 @@ public class ApiInfo extends PathMagicEntity {
/**
* 设置的接口选项
*/
private List<Option> option = new ArrayList<>();
private List<Option> options = new ArrayList<>();
/**
* 请求体
@ -128,12 +129,12 @@ public class ApiInfo extends PathMagicEntity {
this.description = description;
}
public List<Option> getOption() {
return option;
public List<Option> getOptions() {
return options;
}
public void setOption(List<Option> option) {
this.option = option;
public void setOption(List<Option> options) {
this.options = options;
}
public List<Parameter> getParameters() {
@ -162,28 +163,18 @@ public class ApiInfo extends PathMagicEntity {
}
public String getOptionValue(String key) {
if (this.jsonNode == null) {
return null;
}
if (this.jsonNode.isArray()) {
for (JsonNode node : this.jsonNode) {
if (node.isObject() && Objects.equals(key, node.get("name").asText())) {
return node.get("value").asText();
}
}
} else if (this.jsonNode.isObject()) {
JsonNode node = this.jsonNode.get(key);
if (node != null) {
return node.asText();
}
}
return null;
// return MagicRequestDynamicMappingRegistry.findGroups(this.groupId)
// .stream()
// .flatMap(it -> it.getOptions().stream())
// .filter(it -> key.equals(it.getName()))
// .findFirst()
// .map(it -> Objects.toString(it.getValue(), null)).orElse(null);
return this.options.stream()
.filter(it -> key.equals(it.getName()))
.findFirst()
.map(it -> Objects.toString(it.getValue(), null))
.orElseGet(() -> MagicConfiguration.getMagicResourceService().getGroupsByFileId(this.id)
.stream()
.flatMap(it -> it.getOptions().stream())
.filter(it -> key.equals(it.getName()))
.findFirst()
.map(it -> Objects.toString(it.getValue(), null)).orElse(null)
);
}
public BaseDefinition getRequestBodyDefinition() {
@ -222,7 +213,7 @@ public class ApiInfo extends PathMagicEntity {
Objects.equals(paths, apiInfo.paths) &&
Objects.equals(groupId, apiInfo.groupId) &&
Objects.equals(parameters, apiInfo.parameters) &&
Objects.equals(option, apiInfo.option) &&
Objects.equals(options, apiInfo.options) &&
Objects.equals(requestBody, apiInfo.requestBody) &&
Objects.equals(headers, apiInfo.headers) &&
Objects.equals(description, apiInfo.description) &&
@ -233,7 +224,7 @@ public class ApiInfo extends PathMagicEntity {
@Override
public int hashCode() {
return Objects.hash(id, method, path, script, name, groupId, parameters, option, requestBody, headers, responseBody, description, requestBodyDefinition, responseBodyDefinition);
return Objects.hash(id, method, path, script, name, groupId, parameters, options, requestBody, headers, responseBody, description, requestBodyDefinition, responseBodyDefinition);
}
@Override

View File

@ -34,7 +34,7 @@ public class Backup {
/**
* 备份内容
*/
private String content;
private byte[] content;
/**
* 操作人取用户名空为系统记录
@ -45,7 +45,7 @@ public class Backup {
public Backup() {
}
public Backup(String id, String type, String name, String content) {
public Backup(String id, String type, String name, byte[] content) {
this.id = id;
this.type = type;
this.name = name;
@ -84,11 +84,11 @@ public class Backup {
this.id = id;
}
public String getContent() {
public byte[] getContent() {
return content;
}
public void setContent(String content) {
public void setContent(byte[] content) {
this.content = content;
}

View File

@ -1,7 +1,9 @@
package org.ssssssss.magicapi.provider;
import org.ssssssss.magicapi.model.*;
import org.ssssssss.magicapi.utils.JsonUtils;
import org.ssssssss.magicapi.model.ApiInfo;
import org.ssssssss.magicapi.model.Backup;
import org.ssssssss.magicapi.model.DataSourceInfo;
import org.ssssssss.magicapi.model.FunctionInfo;
import java.util.List;
@ -20,7 +22,7 @@ public interface MagicBackupService {
* @param apiInfo 接口信息
*/
default void backup(ApiInfo apiInfo) {
doBackup(new Backup(apiInfo.getId(), Constants.PATH_API, apiInfo.getName(), JsonUtils.toJsonString(apiInfo)));
// doBackup(new Backup(apiInfo.getId(), Constants.PATH_API, apiInfo.getName(), JsonUtils.toJsonString(apiInfo)));
}
/**
@ -29,7 +31,7 @@ public interface MagicBackupService {
* @param functionInfo 函数信息
*/
default void backup(FunctionInfo functionInfo) {
doBackup(new Backup(functionInfo.getId(), Constants.PATH_FUNCTION, functionInfo.getName(), JsonUtils.toJsonString(functionInfo)));
// doBackup(new Backup(functionInfo.getId(), Constants.PATH_FUNCTION, functionInfo.getName(), JsonUtils.toJsonString(functionInfo)));
}
/**

View File

@ -1,176 +0,0 @@
package org.ssssssss.magicapi.provider.impl;
import org.ssssssss.magicapi.model.Backup;
import org.ssssssss.magicapi.provider.MagicBackupService;
import org.ssssssss.magicapi.utils.IoUtils;
import org.ssssssss.magicapi.utils.JsonUtils;
import org.ssssssss.magicapi.utils.MD5Utils;
import org.ssssssss.magicapi.utils.WebUtils;
import java.io.File;
import java.io.FilenameFilter;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 文件备份实现
*
* @author mxd
*/
public class MagicFileBackupService implements MagicBackupService {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
private static final String SUFFIX = ".json";
/**
* 保存路径
*/
private final File backupDirectory;
public MagicFileBackupService(File backupDirectory) {
this.backupDirectory = backupDirectory;
if (!backupDirectory.exists()) {
backupDirectory.mkdirs();
}
}
@Override
public void doBackup(Backup backup) {
if (backup.getCreateDate() == 0) {
backup.setCreateDate(System.currentTimeMillis());
}
if (backup.getCreateBy() == null) {
backup.setCreateBy(WebUtils.currentUserName());
}
File directory = new File(backupDirectory, Instant.ofEpochMilli(backup.getCreateDate()).atZone(ZoneOffset.ofHours(8)).toLocalDate().format(FORMATTER));
if (!directory.exists()) {
directory.mkdirs();
}
IoUtils.write(new File(directory, getFilename(backup)), JsonUtils.toJsonString(backup));
}
@Override
public List<Backup> backupList(long timestamp) {
File[] fileArray = backupDirectory.listFiles();
List<Backup> records = new ArrayList<>(FETCH_SIZE);
if (fileArray != null) {
List<File> dirs = Stream.of(fileArray).sorted(Comparator.comparing(File::getName).reversed()).collect(Collectors.toList());
outer:
for (File dir : dirs) {
fileArray = dir.listFiles((directory, name) -> getTimestampFromFilename(name) < timestamp);
if (fileArray != null) {
for (File file : fileArray) {
records.add(JsonUtils.readValue(IoUtils.string(file), Backup.class));
if (records.size() >= FETCH_SIZE) {
break outer;
}
}
}
}
}
return records.stream()
.sorted(Comparator.comparing(Backup::getCreateDate).reversed())
.map(Backup::small)
.collect(Collectors.toList());
}
@Override
public List<Backup> backupById(String id) {
return backupByFilenameFilter((dir, name) -> name.endsWith(id + SUFFIX))
.stream()
.sorted(Comparator.comparing(Backup::getCreateDate).reversed())
.collect(Collectors.toList());
}
@Override
public Backup backupInfo(String id, long timestamp) {
File directory = new File(backupDirectory, Instant.ofEpochMilli(timestamp).atZone(ZoneOffset.ofHours(8)).toLocalDate().format(FORMATTER));
if (directory.exists()) {
File[] files = directory.listFiles((dir, name) -> name.startsWith("" + timestamp) && name.endsWith(id + SUFFIX));
if (files != null && files.length > 0) {
return JsonUtils.readValue(IoUtils.string(files[0]), Backup.class);
}
}
return null;
}
@Override
public List<Backup> backupByTag(String tag) {
String tagId = MD5Utils.encrypt(tag);
return backupByFilenameFilter((dir, name) -> name.endsWith(SUFFIX) && name.contains("-" + tagId + "-"));
}
@Override
public long removeBackup(String id) {
return getFilesByFilenameFilter((dir, name) -> name.endsWith(id + SUFFIX))
.stream()
.filter(File::delete)
.count();
}
@Override
public long removeBackup(List<String> idList) {
List<String> filenames = idList.stream().map(it -> it + SUFFIX).collect(Collectors.toList());
return getFilesByFilenameFilter((dir, name) -> filenames.stream().anyMatch(name::endsWith))
.stream()
.filter(File::delete)
.count();
}
@Override
public long removeBackupByTimestamp(long timestamp) {
long count = getFilesByFilenameFilter((dir, name) -> name.contains("-") && name.endsWith(".json") && name.length() == 32 + 32 + 13 + 2 + 5 && getTimestampFromFilename(name) < timestamp)
.stream()
.filter(File::delete)
.count();
// 删除空目录
File[] files = backupDirectory.listFiles(File::isDirectory);
if (files != null) {
for (File file : files) {
String[] list = file.list();
if (list == null || list.length == 0) {
file.delete();
}
}
}
return count;
}
private String getFilename(Backup backup) {
return String.format("%s-%s-%s.json", backup.getCreateDate(), MD5Utils.encrypt(Objects.toString(backup.getTag(), "")), backup.getId());
}
private Long getTimestampFromFilename(String filename) {
return Long.valueOf(filename.substring(0, 13));
}
private List<File> getFilesByFilenameFilter(FilenameFilter filenameFilter) {
List<File> list = new ArrayList<>();
File[] dirs = backupDirectory.listFiles();
if (dirs != null) {
for (File dir : dirs) {
if (dir.isDirectory()) {
File[] files = dir.listFiles(filenameFilter);
if (files != null) {
list.addAll(Arrays.asList(files));
}
}
}
}
return list;
}
private List<Backup> backupByFilenameFilter(FilenameFilter filenameFilter) {
return getFilesByFilenameFilter(filenameFilter).stream()
.map(IoUtils::string)
.map(it -> JsonUtils.readValue(it, Backup.class).small())
.collect(Collectors.toList());
}
}

View File

@ -45,6 +45,8 @@ public interface MagicResourceService {
*/
Map<String, TreeNode<Group>> tree();
List<Group> getGroupsByFileId(String id);
/**
* 获取分组 Resource
*

View File

@ -328,6 +328,22 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
return readLock(() -> groupCache.values().stream().collect(Collectors.groupingBy(Group::getType, Collectors.collectingAndThen(Collectors.toList(), this::convertToTree))));
}
@Override
public List<Group> getGroupsByFileId(String id) {
return readLock(() -> {
List<Group> groups = new ArrayList<>();
MagicEntity entity = fileCache.get(id);
if (entity != null) {
Group group = groupCache.get(entity.getGroupId());
while (group != null) {
groups.add(group);
group = groupCache.get(group.getParentId());
}
}
return groups;
});
}
private TreeNode<Group> convertToTree(List<Group> groups) {
TreeNode<Group> root = new TreeNode<>();
root.setNode(new Group("0", "root"));