因项目需要,需要将项目中的接口生成JSON格式的接口文档,试过swagger,改动太大,遂放弃,自己写了一个小工具,能用到的小伙伴可以参考下。好处是没有三方依赖,拿去就可以用
1. 定义方法的注解类
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Desc {
public String apiName() default "";
public String desc() default "";
public String[] para() default {};
}2.定义拦截器的注解类
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface InterceptorDesc {
public String name() default "";
public String desc() default "";
}3.DescAnnotationParse.java 根据类和方法名,查找注解,并返回Map类型的接口说明
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DescAnnotationParse {
public static Map<String, Object> parse(Class targetClass, String targetMethod) {
Method[] methods = targetClass.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (method.getName().equals(targetMethod) && method.isAnnotationPresent(Desc.class)) {//存在注解
Desc desc = method.getAnnotation(Desc.class);
String descStr = desc.desc();
String apiName = desc.apiName();
Map<String, Object> map = new HashMap<String, Object>();
map.put("apiName", apiName);
map.put("desc", descStr);
map.put("para", desc.para());
List paras = new ArrayList<>();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (Annotation[] annotationps : parameterAnnotations) {
for (Annotation annotation : annotationps) {
if (annotation instanceof Para) {
Map paramap = new HashMap();
if (!((Para) annotation).value().equals("-NULL VALUE-"))
paramap.put("paraName", ((Para) annotation).value());
if (!((Para) annotation).defaultValue().equals("-NULL VALUE-"))
paramap.put("defaultValue", ((Para) annotation).defaultValue());
//TODO :: 还缺少入参数据的类型
paras.add(paramap);
}
}
}
map.put("paras",paras);
map.put("class",targetClass.getName());
map.put("method",method.getName());
List beforeList = new ArrayList();
// 是否存在拦截器注解
if(targetClass.isAnnotationPresent(Before.class) && !method.isAnnotationPresent(Clear.class)){
Class[] interceptors = ((Before)targetClass.getAnnotation(Before.class)).value();
for(Class annoclass : interceptors){
if(annoclass.isAnnotationPresent(InterceptorDesc.class)) {
Map beforeMap = new HashMap();
InterceptorDesc interceptorDesc = (InterceptorDesc) annoclass.getAnnotation(InterceptorDesc.class);
beforeMap.put("type",annoclass.getName());
beforeMap.put("desc",interceptorDesc.desc());
beforeMap.put("name",interceptorDesc.name());
beforeList.add(beforeMap);
}
}
}
if(method.isAnnotationPresent(Before.class)){
Class[] interceptors = method.getAnnotation(Before.class).value();
for(Class annoclass : interceptors){
if(annoclass.isAnnotationPresent(InterceptorDesc.class)) {
Map beforeMap = new HashMap();
InterceptorDesc interceptorDesc = (InterceptorDesc) annoclass.getAnnotation(InterceptorDesc.class);
beforeMap.put("type",annoclass.getName());
beforeMap.put("desc",interceptorDesc.desc());
if (!beforeList.contains(beforeMap))
beforeList.add(beforeMap);
}
}
}
map.put("before",beforeList);
return map;
}
}
return null;
}
}4.ApiAnnotationUtils.java , 用于从路由表中查找带有@Desc注解的方法,并使用DescAnnotationParse工具遍历生成接口文档List
import com.jfinal.config.Routes;
import com.jfinal.core.Action;
import com.jfinal.core.JFinal;
import com.jfinal.json.JFinalJson;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ApiAnnotationUtils {
/**
* 路由表
*/
static Map<String, String> mapping = new HashMap<String, String>();
static Map<String, Map> descmapping = new HashMap<>();
public static void init() {
List<String> list = JFinal.me().getAllActionKeys();
list.stream().forEach(item -> {
Action action = JFinal.me().getAction(item, null);
String className = action.getControllerClass().getName();
String method = action.getMethodName();
mapping.put(item, className + "." + method);
try {
Class newClass = Class.forName(className);
Map map = DescAnnotationParse.parse(newClass, method);
if (map != null)
descmapping.put(item, map);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println("******************************************** Api Desc Start ********************************************\n");
list.forEach(item -> {
if (descmapping.containsKey(item)) {
System.out.println("url : " + item + " \t desc:" + JFinalJson.getJson().toJson(descmapping.get(item)));
}
});
System.out.println("\n********************************************* Api Desc End *********************************************\n");
}
public static void addRoute(Routes me,String path){
me.add(path,RoutesIndexController.class);
}
}5.RoutersIndexController.java 用于返回json文档,这个类暂时还没写完,后续增加html展示
import com.jfinal.core.Controller;
import com.jfinal.core.JFinal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RoutesIndexController extends Controller {
public void index(){
this.renderJson(ApiAnnotationUtils.descmapping.toString());
List list = JFinal.me().getAllActionKeys();
List all = new ArrayList();
list.stream().forEach(item -> {
if (ApiAnnotationUtils.descmapping.containsKey(item)) {
Map map = ApiAnnotationUtils.descmapping.get(item);
map.put("url",item);
all.add(map);
}
});
renderJson(all);
}
}6.使用时,在Config类下添加
public void configRoute(Routes me) {
...
ApiAnnotationUtils.addRoute(me,"/api/router");// /api/router 为访问路径
}public void onStart() {
ApiAnnotationUtils.init();
}7.启动项目,console打印

也可以访问步骤6中的路径,直接拿JSON
8.使用,方法上加注解,例:

后续有时间会完善带html可视化的版本。