zoukankan      html  css  js  c++  java
  • SpringBoot异步处理请求

       在实际项目中需要开发一个处理资源编译请求的接口:接受前台页面上传的ymal文件,后台根据模板生成scala文件,然后打包、构建docker镜像。

    文件上传和后台处理过程的实现都不难,只是整个过程是比较耗时的,这里如果使用同步方式,那么上传-->模板解析-->打包-->构建镜像-->返回结果;这个过程,前台的页面都是等待状态的,用户会以为页面卡死了。所以,这里需要做异步处理:

    1.上传-->返回正在编译的标志;

    2.模板解析-->打包-->构建镜像-->存储编译结果;

    此时,当用户上传完文件后,页面立马跳转,模板解析和镜像构建等工作,继续在后台进行,而用户可以不用等待。

    由于整个接口服务采用springboot实现,这里简单记录一种springBoot的异步使用方式,

      这种方式,是springBoot自身的一种异步方式,使用注解实现,非常方便,我们在想要异步执行的方法上加上@Async注解,在controller上加上@EnableAsync即可。注意这里的异步方法,只能在自身之外调用,在本类调用是无效的。

    controller

    @RequestMapping(value = "/XXX/xxx")
    @RestController
    @EnableAsync
    public class CompileController {
        private static final Logger log = LoggerFactory.getLogger(CompileController.class);
    
        private final static int MZX_SIZE = 51200000;
    
        @Autowired
        private CompileRecordRepository recordRepository;
    
        @Autowired
        private BackendService backend;
    
    
        @Value("${build.resource-dir}")
        private String resourceDir;
    
        /**
         * 编译服务
         *
         * @param name
         * @param version
         * @param namespace
         * @param file
         * @return
         */
        @RequestMapping(value = "/compile", method = RequestMethod.POST)
        public String compile(String name, String version, String namespace, @RequestParam("yaml") MultipartFile file) {
            if (file.isEmpty()) {
                return Response.error("编译失败,因为文件是空的.");
            }
            if (file.getSize() > MZX_SIZE) {
                return Response.error("编译失败,文件大小超過限制");
            }
    
            String fileName = file.getOriginalFilename().toLowerCase();
            log.info("fileName:" + fileName);
    
            if (!fileName.endsWith(".yml")) {
                return Response.error("must upload yml format file");
            }
    
            String token = TokenUtil.generateToken();
            CompileLog compileLog = new CompileLog();
            compileLog.setId(token);
            compileLog.setName(name);
            compileLog.setNamespace(namespace);
            compileLog.setToken(token);
            compileLog.setVersion(version);
            compileLog.setCreateTime(System.currentTimeMillis());
            compileLog.setUpdateTime(System.currentTimeMillis());
            compileLog.setStatus(0);
            recordRepository.save(compileLog);
    
            //读取文件内容并写到本地
            String ymlStr = readAndWrite2Local(file);
            //后台异步执行
            backend.execute(compileLog, ymlStr);
    
            return Response.Builder
                    .success()
                    .setMsg("正在编译,可根据token查询编译结果")
                    .appendData("token", token)
                    .build();
        }
    }

    serviceImpl

    @Component
    public class BackendService {
        private static final Logger log = LoggerFactory.getLogger(BackendService.class);
    
        @Autowired
        CompileRecordRepository recordRepository;
    
        @Value("${build.resource-dir}")
        String resourceDir;
    
        private final static String SCALA_FILE = "";
    
        @Async
        public String execute(CompileLog compileLog, String ymlStr) {
    
            //模板代码目录
            String capTemplateDir = resourceDir + "/cap";
            String capInstanceDir = resourceDir + "/capInstance/" + compileLog.getToken();
            FileUtil.mkdir(capInstanceDir);
            capInstanceDir += "/cap";
            //创建实例代码目录
            FileUtil.copyDir(capTemplateDir, capInstanceDir);
    
            log.info(Thread.currentThread().getName() + " start rendering...");
            TemplateService.templateRender(ymlStr, capInstanceDir + SCALA_FILE);
    
            this.pack(capInstanceDir, compileLog);
            this.image(capInstanceDir, compileLog);
          
            log.info(Thread.currentThread().getName() + " update record...");
            compileLog.setStatus(CompileStatus.SUCCESS);
            compileLog.setUpdateTime(System.currentTimeMillis());
            recordRepository.save(compileLog);
    
            log.info(Thread.currentThread().getName() + " execute finished.");
            return "执行异步任务完毕";
        }
    
    
        /**
         * 打成jar包
         */
        private void pack(String capDir, CompileLog record) {
            log.info("start package jar...");
        
        }
    
        /**
         * 生成镜像
         */
        private void image(String capDir, CompileLog record) {
            log.info("start build docker image...");
    
        }
    }

    执行结果,略。。。。。。

    很多情况下,异步处理是一种很常见而且高效的方式,springBoot自带的注解方式只用两个注解即可实现,简单易用。当然除此之外还有其他的实现方式,例如可以通过创建线程池来实现。

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 一元三次方程
    Java实现 蓝桥杯VIP 算法训练 乘法表
    Java实现 蓝桥杯VIP 算法训练 矩阵加法
    Java实现 蓝桥杯VIP 算法训练 一元三次方程
    Java实现 蓝桥杯VIP 算法训练 平方计算
    Java实现 蓝桥杯VIP 算法训练 平方计算
    Java实现 蓝桥杯VIP 算法训练 平方计算
    Java实现 蓝桥杯VIP 算法训练 乘法表
    Java实现 蓝桥杯VIP 算法训练 乘法表
    监管只是压倒网盘业务的一根稻草,但不是主要原因(答案只有一个:成本!)
  • 原文地址:https://www.cnblogs.com/taich-flute/p/9565423.html
Copyright © 2011-2022 走看看