Files
EasyFlow/easyflow-api/easyflow-api-public/src/main/java/tech/easyflow/publicapi/SyncApis.java
2026-02-22 18:56:10 +08:00

189 lines
8.4 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package tech.easyflow.publicapi;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.MemberValuePair;
import com.github.javaparser.ast.expr.NormalAnnotationExpr;
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
import com.mybatisflex.core.MybatisFlexBootstrap;
import com.mybatisflex.core.query.QueryWrapper;
import com.zaxxer.hikari.HikariDataSource;
import tech.easyflow.system.entity.SysApiKeyResource;
import tech.easyflow.system.mapper.SysApiKeyResourceMapper;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 同步接口到数据库
*/
public class SyncApis {
public static void main(String[] args) throws Exception {
try (HikariDataSource dataSource = new HikariDataSource()) {
dataSource.setJdbcUrl("jdbc:mysql://192.168.2.10:3306/easyflow-v2?useInformationSchema=true&characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("123456");
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance();
bootstrap.setDataSource(dataSource);
bootstrap.addMapper(SysApiKeyResourceMapper.class);
bootstrap.start();
SysApiKeyResourceMapper mapper = bootstrap.getMapper(SysApiKeyResourceMapper.class);
String dir = System.getProperty("user.dir") + "/easyflow-api/easyflow-api-public/src/main/java/tech/easyflow/publicapi/controller";
List<String> filePath = getAllFilePaths(dir);
for (String path : filePath) {
extractCommentsFromFile(path, mapper);
}
}
}
public static List<String> getAllFilePaths(String directoryPath) throws IOException {
Path startPath = Paths.get(directoryPath);
try (Stream<Path> stream = Files.walk(startPath)) {
return stream
.filter(Files::isRegularFile) // 只获取文件,排除目录
.map(Path::toAbsolutePath) // 转换为绝对路径
.map(Path::toString) // 转换为字符串
.collect(Collectors.toList());
}
}
public static void extractCommentsFromFile(String filePath, SysApiKeyResourceMapper mapper) throws Exception {
System.out.println("正在解析文件: " + filePath);
FileInputStream in = new FileInputStream(filePath);
com.github.javaparser.JavaParser parser = new com.github.javaparser.JavaParser();
parser.getParserConfiguration().setLanguageLevel(com.github.javaparser.ParserConfiguration.LanguageLevel.JAVA_17);
CompilationUnit cu = parser.parse(in).getResult().orElseThrow();
cu.findAll(ClassOrInterfaceDeclaration.class).forEach(c -> {
// 1. 获取类级别的 RequestMapping 路径
String classPath = "";
Optional<AnnotationExpr> classMapping = c.getAnnotationByName("RequestMapping");
if (classMapping.isPresent()) {
classPath = getAnnotationValue(classMapping.get());
}
String finalClassPath = classPath; //用于lambda中使用
String className = c.getNameAsString();
String classComment = c.getJavadoc().map(d -> d.getDescription().toText()).orElse("");
System.out.println("=========================================");
System.out.println("类名: " + className);
System.out.println("类注释: " + classComment);
System.out.println("类路径: " + finalClassPath);
// 2. 遍历方法
c.getMethods().forEach(method -> {
// 查找常见的 Mapping 注解
String[] mappingTypes = {"GetMapping", "PostMapping", "PutMapping", "DeleteMapping", "PatchMapping", "RequestMapping"};
for (String mappingType : mappingTypes) {
Optional<AnnotationExpr> methodMapping = method.getAnnotationByName(mappingType);
if (methodMapping.isPresent()) {
// 获取方法上的路径
String methodPath = getAnnotationValue(methodMapping.get());
// 拼接完整 URI
String fullUri = combinePaths(finalClassPath, methodPath);
// 获取请求方式 (如果是 RequestMapping通常默认为 All 或者需要进一步解析 method 属性,这里简单处理)
String httpMethod = mappingType.replace("Mapping", "").toUpperCase();
if (httpMethod.equals("REQUEST")) httpMethod = "ALL";
// 获取方法注释
String methodComment = method.getJavadoc().map(doc -> doc.getDescription().toText()).orElse("");
System.out.println("--------------------------------");
System.out.println(" 方法名: " + method.getNameAsString());
System.out.println(" 类型: " + httpMethod);
System.out.println(" 完整URI: " + fullUri);
System.out.println(" 方法注释: " + methodComment);
// 可以在这里调用 mapper 存入数据库
QueryWrapper w = QueryWrapper.create();
w.eq(SysApiKeyResource::getRequestInterface, fullUri);
SysApiKeyResource record = mapper.selectOneByQuery(w);
if (record != null) {
record.setTitle(methodComment);
mapper.insertOrUpdate(record);
} else {
record = new SysApiKeyResource();
record.setRequestInterface(fullUri);
record.setTitle(methodComment);
mapper.insert(record);
}
}
}
});
});
}
/**
* 解析注解中的 value 或 path 值
* 处理几种情况:
* 1. @GetMapping("/api") -> SingleMemberAnnotationExpr
* 2. @GetMapping(value = "/api") -> NormalAnnotationExpr
* 3. @GetMapping(path = "/api") -> NormalAnnotationExpr
* 4. @GetMapping -> 默认为空字符串
*/
private static String getAnnotationValue(AnnotationExpr annotation) {
// 情况 1: @GetMapping("/path")
if (annotation instanceof SingleMemberAnnotationExpr) {
String value = ((SingleMemberAnnotationExpr) annotation).getMemberValue().toString();
return removeQuotes(value);
}
// 情况 2: @GetMapping(value="/path") 或 @GetMapping(path="/path")
else if (annotation instanceof NormalAnnotationExpr) {
NormalAnnotationExpr normal = (NormalAnnotationExpr) annotation;
for (MemberValuePair pair : normal.getPairs()) {
String key = pair.getNameAsString();
if ("value".equals(key) || "path".equals(key)) {
return removeQuotes(pair.getValue().toString());
}
}
}
// 情况 3: @GetMapping (没有参数)
return "";
}
/**
* 去除 JavaParser 解析出的字符串中的双引号
*/
private static String removeQuotes(String value) {
if (value == null) return "";
return value.replace("\"", "").trim();
}
/**
* 拼接类路径和方法路径,处理斜杠
*/
private static String combinePaths(String classPath, String methodPath) {
if (classPath == null) classPath = "";
if (methodPath == null) methodPath = "";
// 确保以 / 开头
if (!classPath.startsWith("/") && !classPath.isEmpty()) classPath = "/" + classPath;
if (!methodPath.startsWith("/") && !methodPath.isEmpty()) methodPath = "/" + methodPath;
// 如果 classPath 只有 /,去掉它,避免 //method
if (classPath.equals("/")) classPath = "";
String full = classPath + methodPath;
// 处理重复斜杠 (例如 class=/api/ method=/list -> /api//list)
return full.replace("//", "/");
}
}