Aspect生成服务端API接口

news/2024/5/19 4:00:59 标签: java, spring, 反射, poi

背景

随着分布式系统逐渐成熟及普遍应用,应用与应用直接通过微服务调用,需要对外部提供相应API接口,为次提供一套切面生成API接口的工具

技术实现

  1. aspectj 切面获取注解信息
  2. Java 反射获取属性信息
  3. SpringContext 获取spring 容器beans
  4. poi工具生成docx文档

核心代码

切面基础信息

GenerateApi 定义接口切面信息

package fills.tools.generate.aspectj;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface GenerateApi {

/*

 * API-接口名称

 */

String name() default "";

/*

 * API-接口唯一标识

 */

String key() default "";

/*

 * API-接口描述信息

 */

String description() default "";

}

GenerateMethod 定义方法切面信息

package fills.tools.generate.aspectj;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface GenerateMethod {

/*

 * Method-方法名称

 */

String name() default "";

/*

 * Method-方法唯一标识

 */

String key() default "";

/*

 * Method-方法描述信息

 */

String description() default "";

}

GenerateMethodParams 定义方法参数数组切面信息

package fills.tools.generate.aspectj;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface GenerateMethodParams {

GenerateMethodParam[] params();

}

GenerateMethodParam 定义方法参数切面信息

package fills.tools.generate.aspectj;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface GenerateMethodParam {

/*

 * Param-参数名称

 */

String name() default "";

/*

 * Param-参数唯一标识

 */

String key() default "";

/*

 * Param-参数描述信息

 */

String description() default "";

/*

 * Param-参数是否必填

 */

boolean isMust() default false;

/*

 * Param-参数是否有子参数

 */

boolean isChildren() default false;

/*

 * Param-参数是否隐藏

 */

boolean isHidden() default false;

}

GenerateEntity 定义实体对象切面信息

package fills.tools.generate.aspectj;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface GenerateEntity {

/*

 * Param-参数名称

 */

String name() default "";

/*

 * Param-参数唯一标识

 */

String key() default "";

/*

 * Param-参数描述信息

 */

String description() default "";

}

GenerateFiled 定义实体对象属性切面信息

package fills.tools.generate.aspectj;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target({ElementType.FIELD,ElementType.PARAMETER})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface GenerateFiled {

/*

 * Param-参数名称

 */

String name() default "";

/*

 * Param-参数唯一标识

 */

String key() default "";

/*

 * Param-参数是否必填

 */

boolean isMust() default false;

/*

 * Param-参数是否有子参数

 */

boolean isChildren() default false;

/*

 * Param-参数是否隐藏

 */

boolean isHidden() default false;

}

切面封装接口数据

package fills.tools.generate.impl;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.lang.reflect.Parameter;

import java.lang.reflect.ParameterizedType;

import java.lang.reflect.Type;

import java.util.Collection;

import java.util.HashMap;

import java.util.LinkedHashMap;

import java.util.Map;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.ApplicationContext;

import fills.tools.generate.aspectj.GenerateApi;

import fills.tools.generate.aspectj.GenerateEntity;

import fills.tools.generate.aspectj.GenerateFiled;

import fills.tools.generate.aspectj.GenerateMethod;

import fills.tools.generate.aspectj.GenerateMethodParam;

import fills.tools.generate.aspectj.GenerateMethodParams;

import fills.tools.generate.util.JsonTools;

@SuppressWarnings({"rawtypes","unchecked"})

public class GenerateApiCache {

private static Logger log = LoggerFactory.getLogger(GenerateApiCache.class);

//                 API类名              方法名              参数名      参数描述对象

public static Map<String, Map<String,Map<String, Map>>> methodReqApiCache = new LinkedHashMap<>();

//                 方法名      参数信息

public static Map<String, Map> methodRequestCache = new LinkedHashMap<>();

//                 方法名               参数名     参数描述对象

public static Map<String,Map<String, Map>> methodResApiCache = new LinkedHashMap<>();

//                 方法名      响应信息

public static Map<String, Map> methodResponseCache = new LinkedHashMap<>();

//         实体对象类型名称        实体对象参数信息

public static Map<String, Map> entityCache = new LinkedHashMap<>();

    /**

     * @description: 获取spring容器Api注解,封装api接口

     * @param:  context

     * @return:

     * @author ysf

     * @date: 2021/8/12 19:12

    */

    public static void apiMethodCache(ApplicationContext context){

        Map<String, Object> map = context.getBeansWithAnnotation(GenerateApi.class);

        for(Map.Entry<String, Object> entry : map.entrySet()) {

            Object obj = entry.getValue();

            GenerateApi api = obj.getClass().getAnnotation(GenerateApi.class);

            String classKey = api.key()+"_"+api.name();

            log.debug("接口唯一标识:"+classKey);

            Map<String,Map<String, Map>> methodMap = methodReqApiCache.get(classKey);

            if (methodMap == null) {

                methodMap = new LinkedHashMap<>();

                methodReqApiCache.put(classKey,methodMap);

            }

            Method[] bs = null;

            String classPath = obj.getClass().getName().split("[$$]")[0];

            try {

                bs = Class.forName(classPath).getMethods();

            } catch (Exception e) {

                log.debug("反射获取类异常",e);

                continue;

            }

            for (Method m : bs) {

                Map<String,Map> method = null;

                if (m.isAnnotationPresent(GenerateMethod.class)) {

                 GenerateMethod ao = m.getDeclaredAnnotation(GenerateMethod.class);

                    String methodKey = ao.key()+"_"+ao.name();

                    log.debug("方法唯一标识:"+methodKey);

                    method = methodMap.get(methodKey);

                    if(method==null){

                        method = new LinkedHashMap<>();

                        methodMap.put(methodKey,method);

                    }

                    GenerateMethodParam[] params ={};

                    Map<String,GenerateMethodParam> mapParams = new LinkedHashMap<>();

                    if (m.isAnnotationPresent(GenerateMethodParams.class)) {

                     GenerateMethodParams aip = m.getDeclaredAnnotation(GenerateMethodParams.class);

                     params = aip.params();

                        if(params.length>0) {

                            for (GenerateMethodParam param : params) {

                                mapParams.put(param.key(), param);

                            }

                        }

                    }

                    Parameter[] parameters =  m.getParameters();

                    if(parameters!=null&¶meters.length>0){

                        for(int i=0;i<parameters.length;i++){

                         Parameter p = parameters[i];

                         GenerateMethodParam gp = mapParams.get(p.getName());

                         boolean flag = true;

                         if(gp==null){

                         if(i<params.length){

                         gp = params[i];

                         }

                         }else{

                         flag = false;

                         }

                            setParam(p,gp,method,flag);

                        }

                        setRequestParams(methodKey,parameters);

                    }

                    Class rt = m.getReturnType();

                    if(rt!=null){

                        setResponseParams(methodKey,m);

                    }

                }

            }

        }

    }

    /**

     * @description: 封装响应参数

     * @param:  methodKey

     * @param:  c

     * @return:

     * @author ysf

     * @date: 2021/8/13 11:24

    */

    private static  void setResponseParams(String methodKey,Method m){

        Class c = m.getReturnType();

        Map param = new LinkedHashMap();

        param.put("key", c.getName());

        param.put("isMust", false);

        param.put("type", m.getGenericReturnType().getTypeName());

        if(c.isAnnotationPresent(GenerateEntity.class)) {

            GenerateEntity GenerateEntity = (GenerateEntity) c.getAnnotation(GenerateEntity.class);

            param.put("name", GenerateEntity.key());

        }else{

            param.put("name", c.getTypeName());

        }

        Class c2 =null;

        String res = "";

        int dataType = checkDataType(c);

        String r = "";

        if(dataType<0){

            c2 = c;

            r = getJsonStr(c,1);

            res = "".equals(r) ? c.getName() : r;

        }else if(dataType==0){

            Type tp = m.getGenericReturnType();

            if(tp instanceof ParameterizedType){

                c2 = (Class<?>) ((ParameterizedType)tp).getActualTypeArguments()[0];

                r = getJsonStr(c2,1);

                res ="["+("".equals(r) ? c2.getName() : r)+"]";

            }

        }else if(dataType>0){

            Type tp = m.getGenericReturnType();

            if(tp instanceof ParameterizedType){

                c2 = (Class<?>) ((ParameterizedType)tp).getActualTypeArguments()[1];

                r = getJsonStr(c2,1);

                res ="{"+("".equals(r) ? c2.getName() : r)+"}";

            }

        }

        if(c2!=null&&!c2.isPrimitive()){

            setMoreParam(c2, param,1);

        }else {

            param.put("isMore", "false");

        }

        methodResApiCache.put(methodKey , param);

        Map map = new HashMap();

        map.put("dataType",m.getGenericReturnType().getTypeName());

        if(!"".equals(res)) {

            map.put("dataValue",res);

        }else{

            map.put("dataValue",c.getName());

        }

        methodResponseCache.put(methodKey,map);

    }

    /**

     * @description: 封装请求参数

     * @param:  methodKey

     * @param:  parameters

     * @return:

     * @author ysf

     * @date: 2021/8/13 11:06

    */

    private static void setRequestParams(String methodKey,Parameter[] parameters){

        StringBuffer sb = new StringBuffer();

        StringBuffer sb1 = new StringBuffer();

        String name ="";

        for (Parameter p : parameters) {

            if (!p.getType().isPrimitive()) {

                int dataType = checkDataType(p.getType());

                if(dataType<0) {

                    name = getJsonStr(p.getType(),1);

                    sb.append("".equals(name) ? p.getName() : name).append(",");

                    sb1.append(p.getType().getTypeName()).append(" ,");

                }else if(dataType==0){

                    name = getJsonStr(getDataType(p),1);

                    sb.append("[").append("".equals(name) ? p.getName() : name).append("],");

                    sb1.append(p.getParameterizedType().getTypeName()).append(" ,");

                }else if(dataType>0){

                    name = getJsonStr(getDataType(p),1);

                    sb.append("{").append("".equals(name) ? p.getName() : name).append("},");

                    sb1.append(p.getParameterizedType().getTypeName()).append(" ,");

                }

            }

        }

        if(sb.length()>0) {

            Map map = new HashMap();

            map.put("dataType",sb1.toString().substring(0, sb1.toString().length() - 1));

            map.put("dataValue",sb.toString().substring(0, sb.toString().length() - 1));

            methodRequestCache.put(methodKey, map);

        }

    }

    /**

     * @description: 封装请求参数 count 用于解决相互依赖死循环

     * @param:  c

     * @param:  count

     * @return:  String

     * @author ysf

     * @date: 2021/8/13 15:40

    */

    private static String getJsonStr(Class c,int count){

        String req = null;

        try {

            if(c!=null&&c.isAnnotationPresent(GenerateEntity.class)&&count<5){

                Field[] fields = c.getDeclaredFields();

                Map<String, String> fieldMap = new LinkedHashMap();

                for (Field field : fields) {

                    if (field.isAnnotationPresent(GenerateFiled.class)) {

                        GenerateFiled amp = field.getAnnotation(GenerateFiled.class);

                        if (amp.isHidden()) {

                            continue;

                        }

                        int dataType = checkDataType(field.getType());

                        if(dataType<0) {

                            fieldMap.put(field.getName(), getJsonStr(field.getType(),count+1));

                        }else if(dataType==0){

                            fieldMap.put(field.getName(), "["+getJsonStr(getDataType(field),count+1)+"]");

                        }else if(dataType>0){

                            fieldMap.put(field.getName(), "{"+getJsonStr(getDataType(field),count+1)+"}");

                        }

                    }

                }

                if(!fieldMap.isEmpty()){

                 req = JsonTools.writeValueAsString(fieldMap, false);

                }

            }

        } catch (Exception e) {

        }

        if (req ==null) {

            return "";

        }else{

            return req;

        }

    }

    /**

     * @description: 封装方法参数

     * @param:  p

     * @param:  aip

     * @param:  method

     * @return:

     * @author ysf

     * @date: 2021/8/12 19:13

    */

private static void setParam(Parameter p,GenerateMethodParam aip,Map<String,Map> method,boolean flag){

        Map param = new LinkedHashMap();

        param.put("key",flag ? p.getName() : aip!=null ? aip.key() : "");

        param.put("name", aip !=null ? aip.name() : p.getName());

        param.put("isMust", aip !=null ? aip.isMust() +"": ""+false);

        param.put("type", p.getParameterizedType().getTypeName());

        if(!p.getType().isPrimitive()) {

            Class dataType = getDataType(p);

            if(dataType ==null){

                setMoreParam(p.getType(), param,1);

            }else{

                setMoreParam(dataType, param,1);

            }

        }else{

            param.put("isMore", "false");

        }

        method.put(aip !=null ? aip.key() : p.getName() , param);

    }

    /**

     * @description: 获取数据类型

     * @param:  p

     * @return: Class

     * @author ysf

    */

    private static Class getDataType(Parameter p){

        Class c3 = p.getType();

        try {

            if (Collection.class.isAssignableFrom(c3)) {

                ParameterizedType pt = (ParameterizedType) p.getParameterizedType();

                return (Class<?>) pt.getActualTypeArguments()[0];

            } else if (Map.class.isAssignableFrom(c3)) {

                ParameterizedType pt = (ParameterizedType) p.getParameterizedType();

                return (Class<?>) pt.getActualTypeArguments()[1];

            } else if (c3.isArray()) {

                return p.getType().getComponentType();

            }

        }catch (Exception e){

            return null;

        }

        return null;

    }

    

    /**

     * @description: 获取数据类型

     * @param:  field

     * @return: Class

     * @author ysf

    */

    private static Class getDataType(Field field){

        Class<?> genericityType = null;

        try {

            field.setAccessible(true);

            Class c3 = field.getType();

            if (Collection.class.isAssignableFrom(c3) || Map.class.isAssignableFrom(c3)) {

                Type genericType = field.getGenericType();

                if (null == genericType) {

                    return genericityType;

                }

                if (genericType instanceof ParameterizedType) {

                    ParameterizedType pt = (ParameterizedType) genericType;

                    genericityType = (Class<?>) pt.getActualTypeArguments()[0];

                    if (Map.class.isAssignableFrom(c3)) {

                        genericityType = (Class<?>) pt.getActualTypeArguments()[1];

                    }

                }

            } else if (c3.isArray()) {

                genericityType = c3.getComponentType();

            }

        }catch (Exception e){

            return null;

        }

        return genericityType;

    }

    /**

     * @description: 校验数据类型

     * @param: c3

     * @return:  int

     * @author ysf

     * @date: 2021/8/13 15:40

    */

    private static int checkDataType(Class c3){

        if(Collection.class.isAssignableFrom(c3)){

            return 0;

        }else if( Map.class.isAssignableFrom(c3)) {

           return 1;

        }else if(c3.isArray()){

            return 1;

        }

        return -1;

    }

    /**

     * @description: 封装method 参数,count 避免相互依赖死循环,递归5次后结束

     * @param:  c2

     * @param:  param

     * @param:  count

     * @return:

     * @author ysf

     * @date: 2021/8/12 19:14

    */

    private static void setMoreParam(Class c2,Map param,int count){

       try {

           //Class c2 = Class.forName(c.getName());

           if (c2.isAnnotationPresent(GenerateEntity.class)&&count<5) {

               param.put("isMore", "true");

               Map<String, Map> fieldMap = entityCache.get(c2.getTypeName());

               if(fieldMap==null){

                fieldMap = new LinkedHashMap();

                Field[] fields = c2.getDeclaredFields();

               for (Field field : fields) {

                   if (field.isAnnotationPresent(GenerateFiled.class)) {

                       GenerateFiled amp = field.getAnnotation(GenerateFiled.class);

                       if(amp.isHidden()){

                           continue;

                       }

                       fieldMap.put(field.getName(), setMapData(field,field.getType(),count,amp.name()));

                   }else{

                       Class<?> genericityType =getDataType(field);

                       if(genericityType!=null) {

                           fieldMap.put(field.getName(), setMapData(field, genericityType, count, null));

                       }

                   }

               }

                entityCache.put(c2.getTypeName(), fieldMap);

               }

               param.put("more",fieldMap);

           } else{

               param.put("isMore", "false");

           }

       }catch (Exception e){

           log.error("反射获取对象异常",e);

       }

    }

    /**

     * @description: 封装参数类型

     * @param:  field

     * @param:  c

     * @param:  count

     * @param:  name

     * @return:  Map

     * @author ysf

     * @date: 2021/8/13 10:26

    */

    private static Map setMapData(Field field,Class c,int count,String name){

        Map map = new LinkedHashMap();

        map.put("key", field.getName());

        map.put("name",name!=null ? name: field.getName());

        map.put("isMust", "false");

        map.put("type", field.getType().getName());

        if(!field.getType().isPrimitive()) {

            setMoreParam(c, map,count+1);

        }

        return map;

    }

    

}

封装Service-Api 文档和Html页面

package fills.tools.generate.impl;

import java.awt.Desktop;

import java.io.File;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.LinkedHashMap;

import java.util.List;

import java.util.Map;

import org.apache.poi.xwpf.usermodel.XWPFDocument;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import fills.tools.generate.util.CreateDocxTableUtil;

import fills.tools.generate.util.DubboApiHtmlTemp;

import fills.tools.generate.util.FileUtil;

import fills.tools.generate.util.JsonTools;

@SuppressWarnings({ "rawtypes", "unchecked" })

public class CreateApiTools {

private static Logger log = LoggerFactory.getLogger(CreateApiTools.class);

public static Map<String,Map<String, List<Object[]>>> apiListReqArrayApi = new LinkedHashMap();

    public static Map<String,Map<String, List<Object[]>>> apiListResArrayApi = new LinkedHashMap();

    

    private static String DEFAULT_PATH = "./create/api/html/server-api.html";

    

    static XWPFDocument xdoc = null;

    

    /**

     * 生成API-HTML页面源码

     * @return String

     */

    public static String getApiHtml(){

     return DubboApiHtmlTemp.getApiHtml();

    }

    

    /**

     * 生成API-HTML byte[] 字节流源码,用户页面 response.getOutputStream().write(byte[]);

     * @return byte[]

     */

    public static byte[] getApiByte(){

     try {

return getApiHtml().getBytes("UTF-8");

} catch (UnsupportedEncodingException e) {

}

     return getApiHtml().getBytes();

    }

    

    /**

     * 生成本地接口并打开默认浏览器查看接口

     */

    public static void openHtml(){

     try {

     FileUtil.writeContent(getApiHtml(), DEFAULT_PATH);

Desktop.getDesktop().open(new File(DEFAULT_PATH));

} catch (IOException e) {

}

    }

    

    /**

     * 创建本地API-HTML页面

     * @param createLocalPath

     */

    public static void createLocalHtml(String createLocalPath){

     FileUtil.writeContent(getApiHtml(), createLocalPath);

    }

    

    /**

 * 创建本地docx接口文档

 * @param createLocalPath

 */

public static void createLocalDocx(String createLocalPath){

if(xdoc==null){

getApiDocx();

}

if(xdoc!=null){

try {

FileUtil.createFile(createLocalPath);

CreateDocxTableUtil.saveDocument(xdoc, createLocalPath);

} catch (Exception e) {

}

}

}

/**

 * 获取api接口文档docx

 * @return

 */

public static XWPFDocument getApiDocx(){

if(apiListReqArrayApi.isEmpty()){

getClassParams();

}

if(!apiListReqArrayApi.isEmpty()){

String[] fileds = new String[]{"参数名","二级参数名","三级参数名","参数说明","数据类型","是否必须","是否含子参数"};

int[] fileds_widths = new int[] {1504,1504,1504,1504,1504,300,300};

xdoc = new XWPFDocument();

for(Map.Entry<String,Map<String,List<Object[]>>> entry : apiListReqArrayApi.entrySet()){

String classKey = entry.getKey();

Map<String,List<Object[]>> reqMap = entry.getValue();

Map<String,List<Object[]>> resMap = apiListResArrayApi.get(classKey);

for(Map.Entry<String, List<Object[]>> obj : reqMap.entrySet()){

String methodKey = obj.getKey();

List<Object[]> reqList = obj.getValue();

List<Object[]> resList = resMap.get(methodKey);

Map<String,Map> reqParamMap = GenerateApiCache.methodRequestCache.get(methodKey);

Map<String,Map> resParamMap = GenerateApiCache.methodResponseCache.get(methodKey);

try {

CreateDocxTableUtil.createTitle(xdoc, classKey, "28");

CreateDocxTableUtil.createTitle(xdoc, methodKey, "24");

CreateDocxTableUtil.createTitle(xdoc, "请求类型", "22");

CreateDocxTableUtil.createContent(xdoc, reqParamMap.get("dataType")+"", "20");

CreateDocxTableUtil.createTitle(xdoc, "请求示例", "22");

CreateDocxTableUtil.createContent(xdoc, reqParamMap.get("dataValue")+"", "20");

CreateDocxTableUtil.createTitle(xdoc, "请求参数", "22");

CreateDocxTableUtil.createTable(xdoc, fileds_widths, fileds, reqList, "18");

CreateDocxTableUtil.createTitle(xdoc, "响应类型", "22");

CreateDocxTableUtil.createContent(xdoc, resParamMap.get("dataType")+"", "20");

CreateDocxTableUtil.createTitle(xdoc, "响应示例", "22");

CreateDocxTableUtil.createContent(xdoc, resParamMap.get("dataValue")+"", "20");

CreateDocxTableUtil.createTitle(xdoc, "响应参数", "22");

CreateDocxTableUtil.createTable(xdoc, fileds_widths, fileds, resList, "18");

} catch (Exception e) {

}

}

}

return xdoc;

}

return null;

}

/**

 * 获取封装参数

 */

private static void getClassParams(){

Map<String, Map<String,Map<String, Map>>> methodReqApiCache = GenerateApiCache.methodReqApiCache;

for(Map.Entry<String, Map<String,Map<String, Map>>> entry : methodReqApiCache.entrySet()){

String classKey = entry.getKey();

Map<String,Map<String, Map>> methodMap = entry.getValue();

Map<String, List<Object[]>> methodReqMap = new HashMap<String, List<Object[]>>();

apiListReqArrayApi.put(classKey, methodReqMap);

Map<String, List<Object[]>> methodResMap = new HashMap<String, List<Object[]>>();

apiListResArrayApi.put(classKey, methodResMap);

getMethodParams(methodMap, methodReqMap,methodResMap);

}

log.debug(JsonTools.writeValueAsString(apiListReqArrayApi));

log.debug(JsonTools.writeValueAsString(apiListResArrayApi));

}

/**

 * 封装请求,响应参数

 * @param methodMap

 * @param paramList

 * @param methodResMap

 */

private static void getMethodParams(Map<String,Map<String, Map>> methodMap, Map<String, List<Object[]>> paramList,Map<String, List<Object[]>> methodResMap){

for(Map.Entry<String, Map<String, Map>> e : methodMap.entrySet()){

String methodKey = e.getKey();

List<Object[]> paramReqArray = new ArrayList<Object[]>();

getParams(e.getValue(), paramReqArray, 0);

paramList.put(methodKey, paramReqArray);

List<Object[]> paramResArray = new ArrayList<Object[]>();

getParam(GenerateApiCache.methodResApiCache.get(methodKey),paramResArray,0);

methodResMap.put(methodKey, paramResArray);

}

}

/**

 * 封装对象参数

 * @param map

 * @param paramArray

 * @param paramSize

 */

private static void getParams(Map<String, Map> map,List<Object[]> paramArray,int paramSize){

for(Map.Entry<String, Map> field : map.entrySet()){

getParam(field.getValue(),paramArray, paramSize);

}

}

/**

 * 封装行参数

 * @param map

 * @param paramArray

 * @param paramSize

 */

private static void getParam(Map map,List<Object[]> paramArray,int paramSize){

if(paramSize>=3){

return;

}

//参数名称,二级参数名称 ,三级参数名称,参数说明 ,数据类型,是否必须,是否含有子参数

String isMore = map.get("isMore").toString();

paramArray.add(new Object[]{paramSize == 0 ? map.get("key") : "" , paramSize == 1 ? map.get("key") : "" , paramSize == 2 ? map.get("key") : "" , map.get("name") , map.get("type") , map.get("isMust") , isMore});

if("true".equals(isMore)){

getParams((Map<String, Map>)map.get("more"), paramArray, (paramSize+1));

}

}

/**

 * 获取docx文档 byte[]

 * @param document

 * @return byte[]

 */

public static byte[] getDocumentByte(XWPFDocument document){

 ByteArrayOutputStream out = new ByteArrayOutputStream();

 byte[] obj= null;

 try {

document.write(out);

obj = out.toByteArray();

out.close();

} catch (IOException e) {

}

 return obj;

}

}

监听Spring初始化容器封装接口数据

package fills.tools.generate.listener;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;

import fills.tools.generate.impl.GenerateApiCache;

/**

 * 监听spring初始完成获取beans,封装接口数据

 * @author ysf

 *

 */

@Component

public class CenerateApiListener implements InitializingBean ,ApplicationContextAware{

private static Logger log = LoggerFactory.getLogger(GenerateApiCache.class);

private static ApplicationContext applicationContext;

@SuppressWarnings("static-access")

@Override

public void setApplicationContext(ApplicationContext applicationContext)

throws BeansException {

this.applicationContext = applicationContext;

}

@Override

public void afterPropertiesSet() throws Exception {

while(applicationContext==null){

log.info("applicationContext is  null");

}

log.info("applicationContext is  not  null");

GenerateApiCache.apiMethodCache(applicationContext);

}

}

系统接入

Spring 接入一

<bean id="cenerateApiListener"

 class="fills.tools.generate.listener.CenerateApiListener" />

Spring 接入二

<context:component-scan base-package="com.xxxx,fills.tools"> 

  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>   

</context:component-scan>

SpringBoot 接入

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class, scanBasePackages = {"com.xxx", "fills.tools"})

输出接口文档

Html输出

@RequestMapping("sys/apihtml")

public void serviceApiHtml(HttpServletResponse response) throws IOException {

response.getOutputStream().write(CreateApiTools.getApiHtml().getBytes("UTF-8"));

    }

Docx输出

@RequestMapping("sys/apidocx")

public void serviceApiDocx(HttpServletResponse response) throws IOException {

     response.setHeader("Content-Disposition","attachment; filename=service-api.docx");

response.getOutputStream().write(CreateApiTools.getDocumentByte());

    }

展示效果

Service-Api html页面

 

Service-Api docx文档

系统JAR

切面生成service-api接口-jar

系统源码

aspectj切面生成service-api接口源码


http://www.niftyadmin.cn/n/1638935.html

相关文章

Mybatis教程-使用Hikari和QueryRunner简化JDBC链接操作

Mybatis教程-简化JDBC链接操作 当我们发现使用JDBC有着很多冗余的代码的时候&#xff0c;我们可以自己封装一些代码&#xff0c;完成这些重复的操作。当然市面上其实也有很多这样的封装&#xff0c;这也是Mybatis发展历史中的重要一个环节。所有的框架都是基于不断的封装&#…

Drools规则引擎介绍及实践

1.规则引擎 规则引擎是由推理引擎发展而来&#xff0c;是一种嵌入在应用程序中的组件&#xff0c;实现了将业务决策从应用程序代码中分离出来&#xff0c;并使用预定义的语义模块编写业务决策。接受数据输入&#xff0c;解释业务规则&#xff0c;并根据业务规则做出业务决策。…

BitMap数据结构梳理总结及代码实现

BitMap(位图) BitMap定义 位图&#xff08;BitMap&#xff09;&#xff0c;即位&#xff08;Bit&#xff09;的集合&#xff0c;是一个离散的数组结构&#xff0c;用一个bit位来标记某个元素对应的Value&#xff0c;而Key即是该元素;最基本的情况&#xff0c;使用一个bit表示…

架构技能教程-时序图(UML图)的制作

echo编辑整理&#xff0c;欢迎转载&#xff0c;转载请声明文章来源。欢迎添加echo微信(微信号&#xff1a;t2421499075)交流学习。 什么是时序图&#xff08;UML图&#xff09;&#xff1f; 时序图&#xff08;Sequence Diagram&#xff09;&#xff0c;又名序列图、循序图&am…

Maven Jar 加载原则及Jar冲突加载优先级梳理

Maven Jar 加载原则 依赖最短路径优先原则 如:a.jar 依赖 b.jar,b.jar 依赖 c.jar, c.jar依赖 d.0.jar; a.jar 依赖 e.jar,e.jar 依赖 d.1.jar 则&#xff1a;最终依赖d.1.jar 2.pom文件中申明顺序优先 如&#xff1a;a.jar 依赖 d.0.jar ; b.jar 依赖 d.1.jar且 a.jar 依…

架构技能教程-基础架构原则

echo编辑整理&#xff0c;欢迎转载&#xff0c;转载请声明文章来源。欢迎添加echo微信(微信号&#xff1a;t2421499075)交流学习。 基础架构需要遵循什么&#xff1f;设计产品架构应该需要考虑哪些因素&#xff1f;功能的完整性、效率、安全性、可扩展性&#xff1f;设计架构并…

Arthas在线诊断工具使用

Arthas 命令 下载地址 下载地址&#xff1a;Releases alibaba/arthas GitHub 参考官方文档:https://arthas.aliyun.com/doc/quick-start.html 使用版本arthas-all-3.6.0版本,windows环境下使用 解压到指定目录 /xx/xx/arthas/ 详情如下图 启动Arthas Windows 控制台 cmd…

如何优雅的关闭Java线程池

面试中经常会问到&#xff0c;创建一个线程池需要哪些参数啊&#xff0c;线程池的工作原理啊&#xff0c;却很少会问到线程池如何安全关闭的。 也正是因为大家不是很关注这块&#xff0c;即便是工作三四年的人&#xff0c;也会有因为线程池关闭不合理&#xff0c;导致应用无法…