|
|
package com.dsideal.base;
|
|
|
|
|
|
import cn.hutool.core.io.FileUtil;
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.dsideal.base.Plugin.PostmanDocPlugin;
|
|
|
import com.google.gson.Gson;
|
|
|
import com.google.gson.GsonBuilder;
|
|
|
import com.jfinal.aop.Before;
|
|
|
import com.jfinal.core.Controller;
|
|
|
import com.jfinal.ext.interceptor.GET;
|
|
|
import com.jfinal.ext.interceptor.POST;
|
|
|
import io.github.yedaxia.apidocs.DocContext;
|
|
|
import io.github.yedaxia.apidocs.Docs;
|
|
|
import io.github.yedaxia.apidocs.DocsConfig;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.lang.reflect.Method;
|
|
|
import java.lang.reflect.Modifier;
|
|
|
import java.util.*;
|
|
|
|
|
|
/**
|
|
|
* JApiDocs 无需额外注解的 API 文档生成工具
|
|
|
* <p>
|
|
|
* 源码 https://github.com/YeDaxia/JApiDocs
|
|
|
* 文档 https://japidocs.agilestudio.cn/#/zh-cn/
|
|
|
*
|
|
|
* @author zxd 2022-02-17
|
|
|
*/
|
|
|
public class JApiDocsGenerator {
|
|
|
|
|
|
private static String getHttpType(Before before) {
|
|
|
if (before.value().length > 0) {
|
|
|
for (Class<?> interceptClass : before.value()) {
|
|
|
if (interceptClass.equals(GET.class)) {
|
|
|
return "GET";
|
|
|
} else if (interceptClass.equals(POST.class)) {
|
|
|
return "POST";
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return "UNKNOWN";
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取指定目录下所有JAVA文件
|
|
|
* @param directory 指定目录
|
|
|
* @return 所有Java文件
|
|
|
*/
|
|
|
public static List<File> findJavaFiles(File directory) {
|
|
|
List<File> javaFiles = new ArrayList<>();
|
|
|
File[] files = directory.listFiles();
|
|
|
if (files != null) {
|
|
|
for (File file : files) {
|
|
|
if (file.isDirectory()) {
|
|
|
javaFiles.addAll(findJavaFiles(file)); // 递归遍历子目录
|
|
|
} else if (file.getName().endsWith(".java")) {
|
|
|
javaFiles.add(file); // 添加Java文件
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return javaFiles;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 功能:获取所有 Controller 名称
|
|
|
*
|
|
|
* @param sourceJava JAVA目录
|
|
|
* @return Controller名称集合
|
|
|
*/
|
|
|
public static Map<String, String> getControllMap(String sourceJava) {
|
|
|
Map<String, String> res = new HashMap<>();
|
|
|
List<File> files = findJavaFiles(new File(sourceJava));
|
|
|
for (File file : files) {
|
|
|
String className = file.getAbsolutePath().replace("\\", "/").replace(sourceJava + "/", "");
|
|
|
className = className.replace("/", ".");
|
|
|
className = className.replace(".java", "");
|
|
|
try {
|
|
|
// 去掉.class后缀并加载类
|
|
|
Class<?> cls = Class.forName(className);
|
|
|
if (Controller.class.isAssignableFrom(cls) && !Modifier.isAbstract(cls.getModifiers())) {
|
|
|
// 获取类上的所有方法
|
|
|
Method[] methods = cls.getDeclaredMethods();
|
|
|
for (Method method : methods) {
|
|
|
// 检查方法上是否有@Before注解
|
|
|
var before = method.getAnnotation(Before.class);
|
|
|
if (before != null) {
|
|
|
String httpType = getHttpType(before);
|
|
|
res.put(cls.getSimpleName() + "." + method.getName(), httpType);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
}
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* JApiDocs 生成器
|
|
|
* 如果报错,做如下检查:
|
|
|
* 1 javadoc @param 后是否有注释
|
|
|
* 2 src.main.java 目录中非 .java 扩展名文件的内容要 // 注释起来
|
|
|
* 3 删除 config.setDocsPath 目录中的文件,再生成试试
|
|
|
* <p>
|
|
|
* 如果生成的 api 文档不是预期的,作如下检查:
|
|
|
* 1 必须在 configRoute(Routes me) 中已该方式 me.add("/xx/yy", xx.class, "/"); 定义 Controller
|
|
|
* 2 在需要生成 api 的 Controller 中添加 @ApiDoc 注解
|
|
|
* 3 如果要忽略某 action,在 action 上添加 @Ignore
|
|
|
* https://jfinal.com/share/2528
|
|
|
* <p>
|
|
|
* 在需要生成Doc文档的Controller类上面加上@ApiDoc注解
|
|
|
* <p>
|
|
|
* https://japidocs.agilestudio.cn/#/zh-cn/
|
|
|
*/
|
|
|
public static void main(String[] args) {
|
|
|
//可以限制只生成哪个接口,数组内容为空,则表示生成全部
|
|
|
//String[] generateInterfacesList = {"getWxTj"};
|
|
|
String[] generateInterfacesList = {};
|
|
|
String projectPath = System.getProperty("user.dir");
|
|
|
projectPath = projectPath.replace("\\", "/");
|
|
|
String projectName = projectPath.substring(projectPath.lastIndexOf("/") + 1);
|
|
|
DocsConfig config = new DocsConfig();
|
|
|
String sourceJava = projectPath + "/src/main/java";
|
|
|
config.setProjectPath(sourceJava); // root project path
|
|
|
config.setProjectName(projectName); // project name
|
|
|
String version = "v1.0";
|
|
|
config.setApiVersion(version); // api version
|
|
|
String docPath = projectPath + "/Doc";
|
|
|
config.setDocsPath(docPath); // api docs target path
|
|
|
config.addPlugin(new PostmanDocPlugin());
|
|
|
config.setAutoGenerate(Boolean.FALSE); // auto generate
|
|
|
config.setMvcFramework("JFinal");
|
|
|
Docs.buildHtmlDocs(config); // execute to generate
|
|
|
|
|
|
// 获取项目路径
|
|
|
Map<String, String> map = getControllMap(sourceJava);
|
|
|
//修正一下 postman 的请求方式
|
|
|
String docFileName = String.format("%s-%s-api-docs.json", DocContext.getDocsConfig().getProjectName(), DocContext.getDocsConfig().getApiVersion());
|
|
|
String jsonPath = docPath + "/" + version + "/" + docFileName;
|
|
|
String jsonContent = FileUtil.readUtf8String(jsonPath);
|
|
|
JSONObject jo = JSONObject.parseObject(jsonContent);
|
|
|
//第一层item
|
|
|
for (Object item : jo.getJSONArray("item")) {
|
|
|
JSONObject j2 = (JSONObject) item;
|
|
|
//Controller类名
|
|
|
String className = j2.getString("name");
|
|
|
//第二层item
|
|
|
for (Object o : j2.getJSONArray("item")) {
|
|
|
JSONObject j3 = (JSONObject) o;
|
|
|
JSONObject jRequest = j3.getJSONObject("request");
|
|
|
String x = jRequest.getJSONObject("url").getString("raw");
|
|
|
x = x.substring(x.lastIndexOf("/") + 1);
|
|
|
jRequest.put("method", map.get(className + "." + x));
|
|
|
}
|
|
|
}
|
|
|
//限制只生成哪个接口
|
|
|
Set<String> _set = new HashSet<>();
|
|
|
Collections.addAll(_set, generateInterfacesList);
|
|
|
|
|
|
// 获取JSONArray
|
|
|
jo = jo.getJSONArray("item").getJSONObject(0);
|
|
|
JSONArray jsonArray = jo.getJSONArray("item");
|
|
|
|
|
|
if (!_set.isEmpty()) {
|
|
|
// 遍历JSONArray
|
|
|
for (int i = 0; i < jsonArray.size(); i++) {
|
|
|
// 获取当前的JSONObject
|
|
|
JSONObject obj = jsonArray.getJSONObject(i);
|
|
|
JSONObject jRequest = obj.getJSONObject("request");
|
|
|
// 检查条件,例如,如果名字不是"John",则删除这个条目
|
|
|
String x = jRequest.getJSONObject("url").getString("raw");
|
|
|
x = x.substring(x.lastIndexOf("/") + 1);
|
|
|
if (!_set.contains(x)) {
|
|
|
// 从JSONArray中移除当前条目
|
|
|
jsonArray.remove(i);
|
|
|
// 由于移除操作会改变数组的长度和索引,所以i需要减1以保持正确的索引位置
|
|
|
i--;
|
|
|
}
|
|
|
}
|
|
|
// 将修改后的JSONArray重新设置回JSONObject
|
|
|
jo.put("item", jsonArray);
|
|
|
}
|
|
|
//美化JSON格式化保存
|
|
|
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
|
|
String jsonString = gson.toJson(jo);
|
|
|
FileUtil.writeUtf8String(jsonString, jsonPath);
|
|
|
System.out.println("恭喜,文档JSON处理完成!");
|
|
|
}
|
|
|
} |