因项目需要,需要将项目中的接口生成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可视化的版本。