main
黄海 7 months ago
parent ca15f35d58
commit 62c0d6816c

@ -49,6 +49,12 @@
<artifactId>cos</artifactId>
<version>2022.2</version>
</dependency>
<!-- JApiDocs -->
<dependency>
<groupId>io.github.yedaxia</groupId>
<artifactId>japidocs</artifactId>
<version>1.4.4</version>
</dependency>
<!--生成PDF时写入中文名-->
<dependency>
<groupId>org.apache.pdfbox</groupId>

@ -0,0 +1,191 @@
package com.dsideal.QingLong;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dsideal.QingLong.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>
* DocController@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处理完成");
}
}

@ -0,0 +1,48 @@
package com.dsideal.QingLong.Plugin;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import io.github.yedaxia.apidocs.DocContext;
import io.github.yedaxia.apidocs.IPluginSupport;
import io.github.yedaxia.apidocs.Resources;
import io.github.yedaxia.apidocs.Utils;
import io.github.yedaxia.apidocs.parser.ControllerNode;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PostmanDocPlugin implements IPluginSupport {
public PostmanDocPlugin() {
}
public void execute(List<ControllerNode> controllerNodeList) {
FileWriter docFileWriter = null;
try {
Template ctrlTemplate = this.getDocTpl();
String docFileName = String.format("%s-%s-api-docs.json", DocContext.getDocsConfig().getProjectName(), DocContext.getDocsConfig().getApiVersion());
File docFile = new File(DocContext.getDocPath(), docFileName);
docFileWriter = new FileWriter(docFile);
Map<String, Object> data = new HashMap();
data.put("controllerNodes", controllerNodeList);
data.put("currentApiVersion", DocContext.getCurrentApiVersion());
data.put("projectName", DocContext.getDocsConfig().getProjectName());
data.put("i18n", DocContext.getI18n());
ctrlTemplate.process(data, docFileWriter);
} catch (IOException | TemplateException var10) {
var10.printStackTrace();
} finally {
Utils.closeSilently(docFileWriter);
}
}
private Template getDocTpl() throws IOException {
return Resources.getFreemarkerTemplate("postman-doc.json.ftl");
}
}

@ -0,0 +1,37 @@
{
"info": {
"_postman_id": "",
"name": "${projectName}",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
<#list controllerNodes as controller>
{
"name": "${controller.description}",
"item": [
<#list controller.requestNodes as reqNode>
{
"name": "${reqNode.description}",
"request": {
"url": {
"raw": "{{domain}}${reqNode.url}",
"query": [
<#if reqNode.paramNodes?size != 0>
<#list reqNode.paramNodes as paramNode>
{
"key": "${paramNode.name}",
"value": "",
"description": "${paramNode.description}"
}<#if paramNode_has_next>,</#if>
</#list>
</#if>
]
}
}
}<#if reqNode_has_next>,</#if>
</#list>
]
}<#if controller_has_next>,</#if>
</#list>
]
}
Loading…
Cancel
Save