Procházet zdrojové kódy

react 接口动态生成

tanzhongran před 3 roky
rodič
revize
cd4fe1140a

+ 36 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/controller/special/ReactAutoApiController.java

@@ -0,0 +1,36 @@
+package com.abi.qms.platform.controller.special;
+
+import com.abi.qms.platform.annotation.PassToken;
+import com.abi.qms.platform.infrastructure.frontend.AutoApiUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+
+import javax.websocket.server.PathParam;
+
+/**
+ * @author AndyTan
+ * @date 2021-06-11
+ */
+@Slf4j
+@RestController
+@RequestMapping("/frontend/react")
+@Api(tags = "前端自动接口生成")
+public class ReactAutoApiController {
+
+    @Autowired
+    private AutoApiUtil autoApiUtil;
+
+    @PassToken
+    @ApiOperation("自动生成前端api")
+    @GetMapping(value = "/{controllerDesc}",produces = "text/html;charset=utf-8")
+    public String autoApi(@PathVariable(value = "controllerDesc") String controllerDesc) throws Exception {
+        String s = autoApiUtil.generateOneController(controllerDesc);
+        System.out.println(s);
+        return s;
+    }
+
+}

+ 325 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/infrastructure/frontend/AutoApiUtil.java

@@ -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()+"&lt;IBaseResponse&lt;"+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;
+
+    }
+
+
+}

+ 37 - 28
abi-cloud-qr-platform-server/src/test/java/com/abi/qms/platform/ReactBeanTest.java

@@ -5,10 +5,13 @@ import com.abi.qms.platform.dto.req.QueryOrderFormLimitReq;
 import com.abi.qms.platform.dto.res.QueryOrderFormDetailRes;
 import com.abi.qms.platform.dto.res.QueryOrderFormLimitRes;
 import com.abi.qms.platform.dto.res.ReservationOrderQueryRes;
+import com.abi.qms.platform.infrastructure.frontend.AutoApiUtil;
 import io.swagger.annotations.ApiModelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
 import java.lang.reflect.Field;
@@ -20,35 +23,41 @@ import java.util.Map;
 @Slf4j
 public class ReactBeanTest {
 
-    public static void main(String[] args) {
-        Class clz = ReservationOrderQueryRes.ReservationOrderQueryBean.class;
-
-        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");
-
-        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();
-            }
-
-//            System.out.println(field.getName());
-//            System.out.println(classMap.get(field.getType()));
-//            System.out.println(desc);
-
-            sb.append(String.format("// %s\n",desc));
-            sb.append(String.format("%s: %s;\n",field.getName(),classMap.get(field.getType())));
-        }
-        System.out.println(sb.toString());
+    @Autowired
+    private AutoApiUtil autoApiUtil;
+
+    @Test
+    public void testAutoApi() throws Exception {
+        String apiString = autoApiUtil.generateOneController("码活动管理");
+        System.out.println(apiString);
     }
 
 
+//    public static void main(String[] args) {
+//        Class clz = ReservationOrderQueryRes.ReservationOrderQueryBean.class;
+//
+//        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");
+//
+//        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\n",desc));
+//            sb.append(String.format("%s: %s;\n",field.getName(),classMap.get(field.getType())));
+//        }
+//        System.out.println(sb.toString());
+//    }
+
+
 }