|
@@ -0,0 +1,325 @@
|
|
|
+package com.abi.qms.platform.infrastructure.frontend;
|
|
|
+
|
|
|
+import io.swagger.annotations.Api;
|
|
|
+import io.swagger.annotations.ApiModelProperty;
|
|
|
+import io.swagger.annotations.ApiOperation;
|
|
|
+import io.swagger.v3.oas.annotations.media.Schema;
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import lombok.Data;
|
|
|
+import lombok.NoArgsConstructor;
|
|
|
+import lombok.ToString;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.aop.support.AopUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.context.ApplicationContext;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.stereotype.Controller;
|
|
|
+import org.springframework.web.bind.annotation.GetMapping;
|
|
|
+import org.springframework.web.bind.annotation.PostMapping;
|
|
|
+import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
+import org.springframework.web.bind.annotation.RestController;
|
|
|
+
|
|
|
+import java.io.Serializable;
|
|
|
+import java.lang.reflect.Field;
|
|
|
+import java.lang.reflect.Method;
|
|
|
+import java.lang.reflect.Parameter;
|
|
|
+import java.lang.reflect.Type;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+@Component
|
|
|
+public class AutoApiUtil {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ApplicationContext applicationContext;
|
|
|
+
|
|
|
+ private static final String CONTROLLER_PACKAGE = "com.abi.qms.platform.controller";
|
|
|
+
|
|
|
+ private Map<String,ControllerBean> controllerBeanMap = null;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构造一个controller的api
|
|
|
+ * @param controllerDesc
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public String generateOneController(String controllerDesc) throws Exception {
|
|
|
+ if(controllerBeanMap==null){
|
|
|
+ init();
|
|
|
+ }
|
|
|
+ ControllerBean controllerBean = controllerBeanMap.get(controllerDesc);
|
|
|
+ if(controllerBean==null){
|
|
|
+ return "结构不存在";
|
|
|
+ }
|
|
|
+ //方法列表
|
|
|
+ List<MethodBean> methodBeanList = controllerBean.getMethodBeanList();
|
|
|
+
|
|
|
+ //开始生成
|
|
|
+ StringBuffer contentSb = new StringBuffer();
|
|
|
+ //先接口文件
|
|
|
+ contentSb.append("interface begin============================================================================></br></br>");
|
|
|
+ contentSb.append(generateInterface(methodBeanList));
|
|
|
+ contentSb.append("</br></br>interface end============================================================================></br></br>");
|
|
|
+ //然后文件
|
|
|
+ contentSb.append("index begin============================================================================></br></br>");
|
|
|
+ contentSb.append(generateApiIndex(methodBeanList));
|
|
|
+ contentSb.append("</br></br>index end============================================================================></br></br>");
|
|
|
+
|
|
|
+ return contentSb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private String generateApiIndex(List<MethodBean> methodBeanList)throws Exception {
|
|
|
+ StringBuffer apiSb = new StringBuffer();
|
|
|
+ for(MethodBean methodBean:methodBeanList){
|
|
|
+ String param = "I"+xxxToXxx(methodBean.getMethodName())+"Params";
|
|
|
+ String resp = methodBean.getReturnClass()!=null?("I"+xxxToXxx(methodBean.getMethodName())+"Resp"):"void";
|
|
|
+ apiSb.append("/**</br>");
|
|
|
+ apiSb.append(" * "+methodBean.getMethodSwaggerValue()+"</br>");
|
|
|
+ apiSb.append(" * @param params</br>");
|
|
|
+ apiSb.append(" * @returns</br>");
|
|
|
+ apiSb.append(" */</br>");
|
|
|
+ apiSb.append("export function "+methodBean.getMethodName()+"(params: "+param+") {</br>");
|
|
|
+ apiSb.append(" return "+methodBean.getHttpMethodType()+"<IBaseResponse<"+resp+">>('"+methodBean.getFinalMappingUrl()+"', params);</br>");
|
|
|
+ apiSb.append("}</br>");
|
|
|
+ }
|
|
|
+ return apiSb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String generateInterface(List<MethodBean> methodBeanList)throws Exception {
|
|
|
+ StringBuffer interfaceSb = new StringBuffer();
|
|
|
+ for(MethodBean methodBean:methodBeanList){
|
|
|
+ //param
|
|
|
+ if(methodBean.getParamClass()!=null){
|
|
|
+ String methodBeanName = "I"+xxxToXxx(methodBean.getMethodName())+"Params";
|
|
|
+ interfaceSb.append("//"+methodBean.getMethodSwaggerValue()+"入参</br>");
|
|
|
+ interfaceSb.append("export interface "+methodBeanName+" {</br>");
|
|
|
+ interfaceSb.append(createParamResultBean(methodBean.getParamClass(),methodBeanName,0));
|
|
|
+ interfaceSb.append("}</br>");
|
|
|
+ }
|
|
|
+ //result
|
|
|
+ if(methodBean.getReturnClass()!=null){
|
|
|
+ //内部类列表
|
|
|
+ Class[] declaredClasses = methodBean.getReturnClass().getDeclaredClasses();
|
|
|
+
|
|
|
+ String methodBeanName = "I"+xxxToXxx(methodBean.getMethodName())+"Resp";
|
|
|
+ interfaceSb.append("//"+methodBean.getMethodSwaggerValue()+"出参</br>");
|
|
|
+ interfaceSb.append("export interface "+methodBeanName+" {</br>");
|
|
|
+ interfaceSb.append(createParamResultBean(methodBean.getReturnClass(),methodBeanName,declaredClasses.length));
|
|
|
+ interfaceSb.append("}</br>");
|
|
|
+
|
|
|
+ //result inner class
|
|
|
+ for (Class innerClz:declaredClasses){
|
|
|
+ String simpleName = declaredClasses.length>1?innerClz.getSimpleName():"";
|
|
|
+ methodBeanName = "I"+xxxToXxx(methodBean.getMethodName())+"Resp"+simpleName+"Item";
|
|
|
+ interfaceSb.append("//"+methodBean.getMethodSwaggerValue()+"出参明细</br>");
|
|
|
+ interfaceSb.append("export interface "+methodBeanName+" {</br>");
|
|
|
+ interfaceSb.append(createParamResultBean(innerClz,methodBeanName,declaredClasses.length));
|
|
|
+ interfaceSb.append("}</br>");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return interfaceSb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化map
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private synchronized void init() throws Exception {
|
|
|
+ if(controllerBeanMap!=null){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取使用RestController注解标注的的所有controller类
|
|
|
+ Map<String, Object> restControllers = applicationContext.getBeansWithAnnotation(RestController.class);
|
|
|
+ Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(Controller.class);
|
|
|
+ controllers.putAll(restControllers);
|
|
|
+
|
|
|
+ List<ControllerBean> controllerBeanList = new ArrayList<>();
|
|
|
+
|
|
|
+ //遍历每个controller层
|
|
|
+ for (Map.Entry<String, Object> entry : controllers.entrySet()) {
|
|
|
+ Object value = entry.getValue();
|
|
|
+ Class<?> controllerClass = AopUtils.getTargetClass(value);
|
|
|
+
|
|
|
+ //类url 地址
|
|
|
+ RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);
|
|
|
+ if(requestMapping==null){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String classMappingUrl = requestMapping.value()[0].replace("/","");
|
|
|
+ //接口swagger描述
|
|
|
+ Api api = controllerClass.getAnnotation(Api.class);
|
|
|
+ if(api==null){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String controllerSwaggerDesc = api.tags()[0];
|
|
|
+ //构造内部对象
|
|
|
+ ControllerBean controllerBean = new ControllerBean();
|
|
|
+ controllerBean.setControllerSwaggerDesc(controllerSwaggerDesc);
|
|
|
+ controllerBean.setControllerName(controllerClass.getName());
|
|
|
+
|
|
|
+ //如果不是指定包路径下的controller则过掉
|
|
|
+ if(controllerClass.getPackage().getName()==null || !controllerClass.getPackage().getName().startsWith(CONTROLLER_PACKAGE)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<MethodBean> methodBeanList = new ArrayList<>();
|
|
|
+ //拿到申明的方法
|
|
|
+ Method[] declaredMethods = controllerClass.getDeclaredMethods();
|
|
|
+ for(Method method:declaredMethods){
|
|
|
+ //没有swagger注解的方法不要
|
|
|
+ ApiOperation methodSwaggerAnnotation = method.getAnnotation(ApiOperation.class);
|
|
|
+ if(methodSwaggerAnnotation==null){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取http方法与方法的路径
|
|
|
+ String httpMethod = null;
|
|
|
+ String methodMappingUrl = null;
|
|
|
+ PostMapping postMapping = method.getAnnotation(PostMapping.class);
|
|
|
+ if(postMapping!=null){
|
|
|
+ httpMethod = "post";
|
|
|
+ methodMappingUrl = postMapping.value()[0].replace("/","");
|
|
|
+ }
|
|
|
+ GetMapping getMapping = method.getAnnotation(GetMapping.class);
|
|
|
+ if(getMapping!=null){
|
|
|
+ httpMethod = "get";
|
|
|
+ methodMappingUrl = getMapping.value()[0].replace("/","");
|
|
|
+ }
|
|
|
+ if(httpMethod==null){
|
|
|
+ throw new Exception("");
|
|
|
+ }
|
|
|
+ String finalMappingUrl = "/"+classMappingUrl+"/"+methodMappingUrl;
|
|
|
+
|
|
|
+ //入参
|
|
|
+ Type[] parameters = method.getGenericParameterTypes();
|
|
|
+ String paramTypeTypeName = parameters.length>0?parameters[0].getTypeName():null;
|
|
|
+ Class paramClass = null;
|
|
|
+ if(StringUtils.isNotBlank(paramTypeTypeName)){
|
|
|
+ paramClass = this.getClass().getClassLoader().loadClass(paramTypeTypeName);
|
|
|
+ }
|
|
|
+
|
|
|
+ //出参
|
|
|
+ Type genericReturnType = method.getGenericReturnType();
|
|
|
+ String returnTypeTypeName = genericReturnType.getTypeName();
|
|
|
+ Class returnClass = null;
|
|
|
+ if(returnTypeTypeName!=null && returnTypeTypeName.contains("<")&&returnTypeTypeName.contains(">")){
|
|
|
+ String returnClassName = returnTypeTypeName.substring(returnTypeTypeName.indexOf("<")+1, returnTypeTypeName.indexOf(">"));
|
|
|
+ returnClass = this.getClass().getClassLoader().loadClass(returnClassName);
|
|
|
+ }
|
|
|
+
|
|
|
+ MethodBean methodBean = new MethodBean();
|
|
|
+ methodBean.setMethodSwaggerValue(methodSwaggerAnnotation.value());
|
|
|
+ methodBean.setFinalMappingUrl(finalMappingUrl);
|
|
|
+ methodBean.setHttpMethodType(httpMethod);
|
|
|
+ methodBean.setMethodName(method.getName());
|
|
|
+ methodBean.setParamClass(paramClass);
|
|
|
+ methodBean.setReturnClass(returnClass);
|
|
|
+ methodBeanList.add(methodBean);
|
|
|
+
|
|
|
+ }
|
|
|
+ controllerBean.setMethodBeanList(methodBeanList);
|
|
|
+ controllerBeanList.add(controllerBean);
|
|
|
+ }
|
|
|
+
|
|
|
+ //构造controllerMap
|
|
|
+ controllerBeanMap = new HashMap<>();
|
|
|
+ for(ControllerBean controllerBean:controllerBeanList){
|
|
|
+ controllerBeanMap.put(controllerBean.getControllerSwaggerDesc(),controllerBean);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String createParamResultBean(Class clz,String methodBeanName,int innerClassCount) throws ClassNotFoundException {
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
+
|
|
|
+ Field[] declaredFields = clz.getDeclaredFields();
|
|
|
+ for(Field field:declaredFields){
|
|
|
+ ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
|
|
|
+ String desc = apiModelProperty==null?"":apiModelProperty.value();
|
|
|
+ if(StringUtils.isBlank(desc)){
|
|
|
+ Schema schema = field.getAnnotation(Schema.class);
|
|
|
+ desc = schema==null?"":schema.name();
|
|
|
+ }
|
|
|
+
|
|
|
+ sb.append(String.format("// %s</br>",desc));
|
|
|
+ System.out.println();
|
|
|
+ sb.append(String.format("%s: %s;</br>",field.getName(),optParamTypes(field.getType(),field.getGenericType().getTypeName(),methodBeanName,innerClassCount)));
|
|
|
+ }
|
|
|
+
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String optParamTypes(Class clz,String typeName,String methodBeanName,int innerClassCount) throws ClassNotFoundException {
|
|
|
+ Map<Class,String> classMap = new HashMap<>();
|
|
|
+ classMap.put(String.class,"string");
|
|
|
+ classMap.put(LocalDateTime.class,"string");
|
|
|
+ classMap.put(Long.class,"string");
|
|
|
+ classMap.put(Integer.class,"number");
|
|
|
+
|
|
|
+ String result = null;
|
|
|
+
|
|
|
+ //普通类型直接返回
|
|
|
+ if(classMap.containsKey(clz)){
|
|
|
+ result = classMap.get(clz);
|
|
|
+ }else if(clz == List.class){
|
|
|
+ String realTypeName = typeName.substring(typeName.indexOf("<") + 1, typeName.indexOf(">"));
|
|
|
+ Class<?> realClss = this.getClass().getClassLoader().loadClass(realTypeName);
|
|
|
+ String realTsxType = classMap.get(realClss);
|
|
|
+ if(realTsxType!=null){
|
|
|
+ result = realTsxType+"[]";
|
|
|
+ }else{
|
|
|
+ String simpleName = innerClassCount>1?realClss.getSimpleName():"";
|
|
|
+ result = methodBeanName+simpleName+"Item[]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String xxxToXxx(String xxx){
|
|
|
+ return xxx.substring(0,1).toUpperCase()+xxx.substring(1);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Data
|
|
|
+ @NoArgsConstructor
|
|
|
+ @AllArgsConstructor
|
|
|
+ @ToString
|
|
|
+ public static class MethodBean{
|
|
|
+
|
|
|
+ private String methodName;
|
|
|
+
|
|
|
+ private String httpMethodType;
|
|
|
+
|
|
|
+ private String finalMappingUrl;
|
|
|
+
|
|
|
+ private String methodSwaggerValue;
|
|
|
+
|
|
|
+ private Class paramClass;
|
|
|
+
|
|
|
+ private Class returnClass;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Data
|
|
|
+ @NoArgsConstructor
|
|
|
+ @AllArgsConstructor
|
|
|
+ @ToString
|
|
|
+ public static class ControllerBean{
|
|
|
+
|
|
|
+ private String controllerName;
|
|
|
+
|
|
|
+ private String controllerSwaggerDesc;
|
|
|
+
|
|
|
+ private List<MethodBean> methodBeanList;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|