SpringBoot通过注解获取接口信息

TOC

SpringBoot通过注解获取接口信息

获取Spring框架的ApplicationContext

需要修改Application主类

@ComponentScan(basePackages = "com.example.demo.**.**")
@SpringBootApplication
public class DemoApplication implements CommandLineRunner, ApplicationContextAware {//实现接口 CommandLineRunner, ApplicationContextAware

    /**
     * 获取Spring框架的上下文
     */
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext arg0) {
        this.applicationContext = arg0;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);

    }

    /**
     * 调用 applicationContext(不能在main中使用,main是static的,不能调用)
     * @param args
     */
    @Override
    public void run(String... args) {
        //在这里可以调用applicationContext了
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(RequestMapping.class);
    }
}

相关的方法

  • getBeansWithAnnotation(注解的class) 获取spring中拥有这个注解的所有类

    定义:Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;

比如,通过上面的applicationContext,获取项目中所有的RestController

//获取使用RestController注解的所有类
Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(RestController.class);
  • 根据对象获取class:AopUtils.getTargetClass(Object对象)

上面获取的是Map 的对象,获取每一个map对应的class;

获取了class,就可以使用反射的方法了,比如

getDeclaredMethods:获取当前类的所有方法(包括public、private、protected、默认)

getMethods:获取当前类和父类的所有的public方法

for (Map.Entry<String, Object> entry : controllers.entrySet()) {//遍历每个controller层
     //   entry.getValue() 获取的是 Object对象
    AopUtils.getTargetClass(entry.getValue())
}  
  • 判断一个class/方法中有没有这个注解isAnnotationPresent

    定义:public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

判断的是class的注解,所以需要使用上面的AopUtils.getTargetClass(Object对象)获取到class

AopUtils.getTargetClass(entry.getValue()).isAnnotationPresent(RequestMapping.class) //判断这个class中有没有RequestMapping这个注解
  • 获取一个class/方法的某个注解的对象信息getAnnotationgetDeclaredAnnotation

    getAnnotation返回的是"直接修饰"注解和继承的注解的合集,不包括容器注解里包含的注解;

    getDeclaredAnnotation仅仅返回"直接修饰"注解。

RequestMapping annotation = AopUtils.getTargetClass(entry.getValue()).getAnnotation(RequestMapping.class);
或
RequestMapping methodAnno = method.getDeclaredAnnotation(RequestMapping.class);

案例

案例1 :项目启动,获取controller层的接口

  • controller
@RestController
@RequestMapping(name = "demo1con",value = {"/demo/demo1","/url111"})
public class Demo1Controller {

    @RequestMapping(name = "方法1",value = "/m1")
    public String testDemo1(){
        return "";
    }
}
  • 主类设置
@ComponentScan(basePackages = "com.example.demo.**.**")
@SpringBootApplication
public class DemoApplication implements CommandLineRunner, ApplicationContextAware {//实现接口 CommandLineRunner, ApplicationContextAware

    /**
     * 获取Spring框架的上下文
     */
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext arg0) {
        this.applicationContext = arg0;
    }

    public static void main(String[] args) {
//        SpringApplication app = new SpringApplication(DemoApplication.class);
//        //程序部署在linux环境,若需要配置成系统服务,使用systemctl(CentOS7系统服务命令)进行程序的启动、停止、重启等操作,则需要在程序启动后,生成一个pid文件,其内容则是该进程的pid。
//        //SpringBoot已经提供了pid文件的生成方式,只需要做简单的配置即可。
//        //配置文件application.properties文件内容如下,该配置指定了pid文件的位置: 比如 spring.pid.file=/xxx/syb.pid
//        app.addListeners(new ApplicationPidFileWriter());
//        app.run(args);

        SpringApplication.run(DemoApplication.class, args);

    }

    /**
     * 调用 applicationContext(不能在main中使用,main是static的,不能调用)
     * @param args
     */
    @Override
    public void run(String... args) {
        //获取使用RestController注解的所有controller层类
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(RestController.class);//获取到 demo1Controller -> {Demo1Controller@5595}
        for (Map.Entry<String, Object> entry : controllers.entrySet()) {//遍历每个controller层
            System.out.println(entry.getKey());//demo1Controller
            Object value = entry.getValue();
            Class<?> aClass = AopUtils.getTargetClass(value);//获取class
            System.out.println(aClass.isAnnotationPresent(RequestMapping.class));//true
            RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);//获取注解详情
            RequestMapping declaredAnnotation = aClass.getDeclaredAnnotation(RequestMapping.class);
            //注解的详情可以直接调用了
            System.out.println(JSON.toJSONString(annotation));//{"path":[],"headers":[],"method":[],"name":"demo1con","produces":[],"params":[],"value":["/demo/demo1","/url111"],"consumes":[]}
            List<Method> methods = Arrays.asList(aClass.getMethods());//获取方法
            List<Method> declaredMethods = Arrays.asList(aClass.getDeclaredMethods());//获取方法
            System.out.println(declaredMethods.get(0).isAnnotationPresent(RequestMapping.class));//判断这个方法有没有这个注解
            RequestMapping annotation1 = declaredMethods.get(0).getAnnotation(RequestMapping.class);//获取方法的注解
            RequestMapping annotation2 = declaredMethods.get(0).getDeclaredAnnotation(RequestMapping.class);
            System.out.println(JSON.toJSONString(annotation1));//{"path":[],"headers":[],"method":[],"name":"方法1","produces":[],"params":[],"value":["/m1"],"consumes":[]}
        }
    }
}

案例2:项目启动,接口写入数据库

项目启动的时候,检测所有的controller层,将接口信息写入数据库

接口

public class DemoApplication implements CommandLineRunner, ApplicationContextAware {//1.实现了接口CommandLineRunner, ApplicationContextAware

    /**
     * 2.获取Spring框架的上下文
     */
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext arg0) {
        this.applicationContext = arg0;
    }

    /**
    后台接口自动导入
    */
    @Autowired
    private BackApiAutoImportInter backApiAutoImportInter;

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(DemoApplication.class);
        app.addListeners(new ApplicationPidFileWriter());
        app.run(args);
    }

    @Override
    public void run(String... args) {
        try {
            if (backApiAutoImportInter != null) {
                backApiAutoImportInter.setApplicationContext(applicationContext);
                backApiAutoImportInter.setIsLocal(false);
                backApiAutoImportInter.setIsOpen(false);

                backApiAutoImportInter.run(BackApiDataSource.UCENTER);
            } else {
                log.error("backApiAutoImportInter is empty", "backApiAutoImportInter inject failed");
            }
        } catch (Exception ex) {
            log.error("error:", ex);
        }
    }

}

监听后台接口

项目启动的时候,自动识别项目的所有接口

  • 接口层
/**
* 后台接口自动导入
*
* @author huangyutao
* @date 2019-08-16 10:13:54
*/
public interface BackApiAutoImportInter {

    /**
     * 上下文赋值
        *
     * @param applicationContext 参数
     * @return
     * @author huangyutao
     * @date 2019-08-16 10:34:35
        */
      void setApplicationContext(ApplicationContext applicationContext);

    /**
     * 本地录入标识
        *
     * @param isLocal 参数
     * @return
     * @author huangyutao
     * @date 2019-09-05 18:01:24
        */
      void setIsLocal(boolean isLocal);

    /**
     * 开放标识
        *
     * @param isOpen 参数
     * @return
     * @author huangyutao
     * @date 2019-09-18 11:09:36
        */
      void setIsOpen(boolean isOpen);

    /**
     * 执行导入(用户中心中url以"/back/"开头的接口不录入数据库)
        *
     * @param dataSource 数据来源
     * @return
     * @author huangyutao
     * @date 2019-08-20 10:13:28
        */
      void run(String dataSource);

}
  • 实现层
package net.cc.ucenter.modules.backapi.service;

import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.cc.commons.IdGen;
import net.cc.commons.annotation.User;
import net.cc.commons.web.base.BaseHttpResult;
import net.cc.ucenter.modules.backapi.dto.BackApiAnnoDTO;
import net.cc.ucenter.modules.backapi.entity.BackApiInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
* 后台接口自动导入--将项目中的controller接口写入数据库
*/
@Slf4j
@Service
public class BackApiAutoImportImpl implements BackApiAutoImportInter {

    @Autowired
    private BackApiInfoService backApiInfoService;

    /**Spring框架的上下文*/
    private ApplicationContext applicationContext;
    /**本地录入标识*/
    private boolean isLocal;
    /**开放标识*/
    private boolean isOpen;

    /**
     * 上下文赋值
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /**
     * 本地录入标识
     */
    @Override
    public void setIsLocal(boolean isLocal) {
        this.isLocal = isLocal;
    }

    /**
     * 开放标识
     */
    @Override
    public void setIsOpen(boolean isOpen) {
        this.isOpen = isOpen;
    }

    /**
     * 执行导入(用户中心中url以"/back/"开头的接口不录入数据库)
     */
    @Override
    public void run(String dataSource) {
        List<String> invalidControllers = new ArrayList<>();//没有注解RequestMapping或RequestMapping注解没有设置name的所有的类的集合
        List<String> invalidMethods = new ArrayList<>();
        List<String> invalidMethodAnnos = new ArrayList<>();
        List<BackApiInfo> insertParams = new ArrayList<>();
        List<BackApiInfo> updateParams = new ArrayList<>();
        // 获取数据库中的接口
        BackApiInfo backApiInfoParam = new BackApiInfo();
        backApiInfoParam.setDataSource(dataSource);
        List<BackApiInfo> backApiInfos = backApiInfoService.findList(backApiInfoParam);//查询当前数据库汇总记录的所有的接口
        // 获取代码中所有的controller
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(RestController.class);//获取使用RestController注解的所有controller层类
        // 加工数据
        List<String> apiUrls = backApiInfos.stream().map(p -> p.getApiUrl()).collect(Collectors.toList());//获取数据库中所有的接口的路由url
        for (Map.Entry<String, Object> entry : controllers.entrySet()) {//遍历每个controller层
            //AopUtils.getTargetClass(entry.getValue())  获取controller的真实的class 比如  com.demo1.controller.Demo1Controller
            //isAnnotationPresent 判断class的类注解中有没有这个注解
            //此处为判断这个controller类有没有RequestMapping注解(否则是普通的方法)
            if (!AopUtils.getTargetClass(entry.getValue()).isAnnotationPresent(RequestMapping.class)
                    //getAnnotation 返回这个class的这个注解的所有信息
                    //此处判断的是,给这个controller类设置了name
                    || StringUtils.isBlank(AopUtils.getTargetClass(entry.getValue()).getAnnotation(RequestMapping.class).name())) {
                invalidControllers.add(entry.getKey());
            } else {
                RequestMapping controllerAnno = AopUtils.getTargetClass(entry.getValue()).getAnnotation(RequestMapping.class);//获取这个controller的RequestMapping注解的信息
                for (String controllerUrl : controllerAnno.value()) {//遍历controller的接口(value是数组,一个RequestMapping可以设置多个url)
                    // 过滤/back/开头的接口
                    if (StringUtils.isNotBlank(controllerUrl) && !procPath(controllerUrl).toLowerCase().startsWith("/back/")) {
                        List<String> methodUrls = new ArrayList<>();//这个类的所有的url接口
                        List<Method> methods = Arrays.stream(AopUtils.getTargetClass(entry.getValue()).getDeclaredMethods())//获取本类的所有的方法(包括public、private、protected、默认)
                                .filter(p -> Modifier.isPublic(p.getModifiers()))//过滤掉public的
                                .collect(Collectors.toList());
                        for (Method method : methods) {
                            //若是这个方法没有RequestMapping及相关注解,或者注解没有设置name值
                            if ((!method.isAnnotationPresent(RequestMapping.class) || StringUtils.isBlank(method.getDeclaredAnnotation(RequestMapping.class).name()))
                                    && (!method.isAnnotationPresent(GetMapping.class) || StringUtils.isBlank(method.getDeclaredAnnotation(GetMapping.class).name()))
                                    && (!method.isAnnotationPresent(PostMapping.class) || StringUtils.isBlank(method.getDeclaredAnnotation(PostMapping.class).name()))
                                    && (!method.isAnnotationPresent(PutMapping.class) || StringUtils.isBlank(method.getDeclaredAnnotation(PutMapping.class).name()))
                                    && (!method.isAnnotationPresent(DeleteMapping.class) || StringUtils.isBlank(method.getDeclaredAnnotation(DeleteMapping.class).name()))
                                    && (!method.isAnnotationPresent(PatchMapping.class) || StringUtils.isBlank(method.getDeclaredAnnotation(PatchMapping.class).name()))
                            ) {
                                invalidMethods.add(method.getDeclaringClass().getName() + "." + method.getName());//不需要解析的方法
                            } else {
                                List<BackApiAnnoDTO> backApiAnnoDTOS = getAnnos(method);
                                if (CollectionUtils.isNotEmpty(backApiAnnoDTOS)) {
                                    methodUrls.addAll(backApiAnnoDTOS.stream()
                                            .map(p -> p.getValue())
                                            .collect(Collectors.toList()));
                                }
                            }
                        }
                        List<String> dupliUrls = getDuplicateElements(methodUrls);//获取url重复的元素列表
                        if (CollectionUtils.isNotEmpty(dupliUrls)) {
                            invalidMethodAnnos.addAll(dupliUrls.stream()
                                    .map(p -> "url:"" + p + ""[" + AopUtils.getTargetClass(entry.getValue()).getName() + "]")
                                    .collect(Collectors.toList()));//记录重复的url
                        }
                        for (Method method : methods) {
                            if (method.isAnnotationPresent(RequestMapping.class)
                                    || method.isAnnotationPresent(GetMapping.class)
                                    || method.isAnnotationPresent(PostMapping.class)
                                    || method.isAnnotationPresent(PutMapping.class)
                                    || method.isAnnotationPresent(DeleteMapping.class)
                                    || method.isAnnotationPresent(PatchMapping.class)
                            ) {//若是这个方法有接口的注解
                                List<BackApiAnnoDTO> backApiAnnoDTOS = getAnnos(method);//获取所有的接口信息
                                if (CollectionUtils.isNotEmpty(backApiAnnoDTOS)) {
                                    backApiAnnoDTOS.forEach(backApiAnnoDTO -> {
                                        if (!dupliUrls.contains(backApiAnnoDTO.getValue())) {//不是重复的url(spring不允许重复的url,有重复的就该报异常了)
                                            String apiUrl = new StringBuilder() //拼接controller和方法的url
                                                    .append(procPath(controllerUrl))
                                                    .append(procPath(backApiAnnoDTO.getValue()))
                                                    .toString();
                                            if (StringUtils.isNotBlank(apiUrl)) {
                                                if (!apiUrls.contains(apiUrl)) {//数据库在中不存在这个url
                                                    BackApiInfo backApiInfo = new BackApiInfo();
                                                    backApiInfo.setApiId(IdGen.snowflakeId());
                                                    try {
                                                        Thread.sleep(5);
                                                    } catch (Exception ex) {
                                                        throw new RuntimeException(ex);
                                                    }
                                                    backApiInfo.setApiName(backApiAnnoDTO.getName());
                                                    backApiInfo.setApiUrl(apiUrl);
                                                    backApiInfo.setModuleName(controllerAnno.name());
                                                    backApiInfo.setDataSource(dataSource);
                                                    backApiInfo.setIsOpen(isOpen ? "1" : "0");
                                                    backApiInfo.setIsCheckToken(method.isAnnotationPresent(User.class) ?
                                                            "1" : "0");//是否需要登录
                                                    backApiInfo.setIsUse("1");
                                                    backApiInfo.setIsSync("1");
                                                    backApiInfo.setCreateBy(-1L);
                                                    backApiInfo.setRemarks("system");
                                                    insertParams.add(backApiInfo); //记录为插入的url
                                                } else {
                                                    // delete from apiUrls
                                                    apiUrls.remove(apiUrl);
                                                    // update 数据库中已经存在这个url了,那就更新这个接口的信息
                                                    BackApiInfo backApiInfo = backApiInfos.stream() //获取数据库中的信息
                                                            .filter(p -> p.getApiUrl().equals(apiUrl))
                                                            .findFirst().orElse(null);
                                                    if (backApiInfo.getIsSync().equals("1")) {
                                                        if (!backApiInfo.getApiName().equals(backApiAnnoDTO.getName())
                                                                || !backApiInfo.getModuleName().equals(controllerAnno.name())
                                                                || !backApiInfo.getIsCheckToken().equals(
                                                                method.isAnnotationPresent(User.class) ? "1" : "0")) {
                                                            backApiInfo.setApiName(backApiAnnoDTO.getName());
                                                            backApiInfo.setModuleName(controllerAnno.name());
                                                            backApiInfo.setIsCheckToken(method.isAnnotationPresent(User.class) ?
                                                                    "1" : "0");
                                                            updateParams.add(backApiInfo);//记录为更新的url
                                                        } else {
                                                            // nothing to update
                                                        }
                                                    } else {
                                                        // no sync
                                                    }
                                                }
                                            }
                                        }
                                    });
                                }
                            }
                        }
                    } else {
                        // controller value is empty
                    }
                }
            }
        }
        Map<String, List<Object>> data = new HashMap<>(8);
        data.put("invalidControllers", invalidControllers.stream().map(p -> (Object) p).collect(Collectors.toList()));
        data.put("invalidMethods", invalidMethods.stream().map(p -> (Object) p).collect(Collectors.toList()));
        data.put("invalidMethodAnnos", invalidMethodAnnos.stream().map(p -> (Object) p).collect(Collectors.toList()));
        data.put("insertParams", insertParams.stream().map(p -> (Object) p).collect(Collectors.toList()));
        data.put("updateParams", updateParams.stream().map(p -> (Object) p).collect(Collectors.toList()));
        data.put("deleteParams", apiUrls.stream().map(p -> (Object) p).collect(Collectors.toList()));
        BaseHttpResult<Map<String, List<String>>> result = backApiInfoService.proceedData(data
                , applicationContext.getEnvironment().getActiveProfiles()[0], isLocal);//applicationContext.getEnvironment().getActiveProfiles()[0] 是启动环境,是application的-之后的环境.
        if (!result.isSuccess()) {
            Map<String, List<String>> resultData = result.getData();
            resultData.forEach((key, value) -> log.error(key + "{}", JSON.toJSONString(value)));
            SpringApplication.exit(applicationContext);
        }
    }

    /**
     * 获取注解信息列表
     *
     * @param method 方法
     * @return
     * @author huangyutao
     * @date 2019-08-15 17:26:35
     */
    private List<BackApiAnnoDTO> getAnnos(Method method) {
        List<BackApiAnnoDTO> backApiAnnoDTOs = new ArrayList<>();
        String name = "";
        List<String> values = new ArrayList<>();
        if (method.isAnnotationPresent(RequestMapping.class)) {//判断方法有没有这个注解
            RequestMapping methodAnno = method.getDeclaredAnnotation(RequestMapping.class);
            name = methodAnno.name();//获取方法名
            values = Arrays.asList(methodAnno.value());//获取这个方法的所有的路由url
        } else if (method.isAnnotationPresent(GetMapping.class)) {
            GetMapping methodAnno = method.getDeclaredAnnotation(GetMapping.class);
            name = methodAnno.name();
            values = Arrays.asList(methodAnno.value());
        } else if (method.isAnnotationPresent(PostMapping.class)) {
            PostMapping methodAnno = method.getDeclaredAnnotation(PostMapping.class);
            name = methodAnno.name();
            values = Arrays.asList(methodAnno.value());
        } else if (method.isAnnotationPresent(PutMapping.class)) {
            PutMapping methodAnno = method.getDeclaredAnnotation(PutMapping.class);
            name = methodAnno.name();
            values = Arrays.asList(methodAnno.value());
        } else if (method.isAnnotationPresent(DeleteMapping.class)) {
            DeleteMapping methodAnno = method.getDeclaredAnnotation(DeleteMapping.class);
            name = methodAnno.name();
            values = Arrays.asList(methodAnno.value());
        } else if (method.isAnnotationPresent(PatchMapping.class)) {
            PatchMapping methodAnno = method.getDeclaredAnnotation(PatchMapping.class);
            name = methodAnno.name();
            values = Arrays.asList(methodAnno.value());
        }
        for (String value : values) {//遍历每一个路由,创建详情
            BackApiAnnoDTO backApiAnnoDTO = new BackApiAnnoDTO();
            backApiAnnoDTO.setName(name);
            backApiAnnoDTO.setValue(value);
            backApiAnnoDTOs.add(backApiAnnoDTO);
        }
        return backApiAnnoDTOs;
    }

    /**
     * 处理path
     *
     * @param path path
     * @return path
     * @author huangyutao
     * @date 2019-08-12 11:22:59
     */
    private String procPath(String path) {
        path = path.trim();
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        while (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        return path;
    }

    /**
     * 获取重复的元素列表
     *
     * @param list 数据源
     * @return
     * @author huangyutao
     * @date 2019-08-19 10:59:29
     */
    private <T> List<T> getDuplicateElements(List<T> list) {
        return list.stream()
                // 获得元素出现频率的 Map,键为元素,值为元素出现的次数
                .collect(Collectors.toMap(e -> e, e -> 1, Integer::sum))
                // 所有 entry 对应的 Stream
                .entrySet().stream()
                // 过滤出元素出现次数大于 1 的 entry
                .filter(entry -> entry.getValue() > 1)
                // 获得 entry 的键(重复元素)对应的 Stream
                .map(entry -> entry.getKey())
                .collect(Collectors.toList());
    }

}

backApiInfoService

    /**
     * 处理数据
     *
     * @param data    参数
     * @param profile 启动配置文件
     * @param isLocal profile=local时是否同步数据
     * @return
     * @author huangyutao
     * @date 2019-09-05 10:14:03
     */
    @Transactional(rollbackFor = Exception.class, readOnly = false)
    public BaseHttpResult<Map<String, List<String>>> proceedData(Map<String, List<Object>> data
            , String profile, Boolean isLocal) {
        // 从参数中抽离数据
        List<String> invalidControllers = data.get("invalidControllers").stream()
                .map(p -> objectMapper.convertValue(p, String.class)).collect(Collectors.toList());
        List<String> invalidMethods = data.get("invalidMethods").stream()
                .map(p -> objectMapper.convertValue(p, String.class)).collect(Collectors.toList());
        List<String> invalidMethodAnnos = data.get("invalidMethodAnnos").stream()
                .map(p -> objectMapper.convertValue(p, String.class)).collect(Collectors.toList());
        List<BackApiInfo> insertParams = data.get("insertParams").stream()
                .map(p -> objectMapper.convertValue(p, BackApiInfo.class)).collect(Collectors.toList());
        List<BackApiInfo> updateParams = data.get("updateParams").stream()
                .map(p -> objectMapper.convertValue(p, BackApiInfo.class)).collect(Collectors.toList());
        List<String> deleteParams = data.get("deleteParams").stream()
                .map(p -> objectMapper.convertValue(p, String.class)).collect(Collectors.toList());

        Map<String, List<String>> resultData = new HashMap<>(3);
        if (CollectionUtils.isNotEmpty(invalidControllers)) {
            resultData.put("controllers missing anno: ", invalidControllers);
        }
        if (CollectionUtils.isNotEmpty(invalidMethods)) {
            resultData.put("methods missing anno: ", invalidMethods);
        }
        if (CollectionUtils.isNotEmpty(invalidMethodAnnos)) {
            resultData.put("methods duplicate anno: ", invalidMethodAnnos);
        }
        if (MapUtils.isEmpty(resultData)) {
            // 数据操作
            List<SysParameterInfo> sysParameterInfos = SysParamUtils.getSysParamList("BackApiIgnoreUrl");
            if (CollectionUtils.isNotEmpty(sysParameterInfos) && CollectionUtils.isNotEmpty(insertParams)) {
                List<String> ignoreUrls = sysParameterInfos.stream()
                        .map(p -> p.getParameterKey())
                        .collect(Collectors.toList());
                // 去掉忽略的
                insertParams = insertParams.stream()
                        .filter(p -> !ignoreUrls.contains(p.getApiUrl()))
                        .collect(Collectors.toList());
            }
            switch (profile) {
                case ProfileType.LOCAL:
                    if (isLocal) {
                        if (CollectionUtils.isNotEmpty(insertParams)) {
                            dao.insertBatch(insertParams);
                        }
                        if (CollectionUtils.isNotEmpty(updateParams)) {
                            dao.updateBatch(updateParams);
                        }
                        if (CollectionUtils.isNotEmpty(deleteParams)) {
                            List<BackApiInfo> backApiInfos = dao.selectBatch(deleteParams);
                            // 删除后台接口信息
                            dao.deleteBatch(deleteParams);
                            // 删除关联关系
                            backApiInFuncDao.deleteBatch(backApiInfos.stream().map(p -> p.getApiId())
                                    .collect(Collectors.toList()));
                        }
                    }
                    break;
                case ProfileType.TEST:
                case ProfileType.TEST_STABLE:
                    if (CollectionUtils.isNotEmpty(insertParams)) {
                        dao.insertBatch(insertParams);
                    }
                    if (CollectionUtils.isNotEmpty(updateParams)) {
                        dao.updateBatch(updateParams);
                    }
                    if (CollectionUtils.isNotEmpty(deleteParams)) {
                        List<BackApiInfo> backApiInfos = dao.selectBatch(deleteParams);
                        // 删除后台接口信息
                        dao.deleteBatch(deleteParams);
                        // 删除关联关系
                        backApiInFuncDao.deleteBatch(backApiInfos.stream().map(p -> p.getApiId())
                                .collect(Collectors.toList()));
                    }
                    break;
                case ProfileType.PROD:
                    if (CollectionUtils.isNotEmpty(insertParams)) {
                        dao.insertBatch(insertParams);
                    }
                    break;
                default:
                    break;
            }

            // 清除缓存
            List<String> keys = new ArrayList<>();
            keys.addAll(new ArrayList<>(redisTemplate.keys(CfgProperties.BASEINFO + "*")));
            keys.addAll(new ArrayList<>(redisTemplate.keys(CfgProperties.ACCOUNTURL + "*")));
            keys.add(CfgProperties.NOEXISTURL);
            redisTemplate.delete(keys);

            return success(resultData);
        } else {
            return error(resultData);
        }
    }




原文地址:https://www.cnblogs.com/ziyue7575/p/fda93464ccee630b63d91035bef74396.html