欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

springboot利用aop实现接口异步(进度条)的全过程

程序员文章站 2022-03-04 13:41:57
目录一、前言二、时序图三、功能演示四、关键代码controllerasyncaopasyncservice五、源码地址总结一、前言在项目中发现有接口(excel导入数据)处理数据需要耗时比较长的时间,...

一、前言

在项目中发现有接口(excel导入数据)处理数据需要耗时比较长的时间,是因为数据量比较大,同时数据的校验需要耗费一定时间,决定使用一种通用的方法解决这个问题。

解决方案:通过aop使接口异步处理,前端轮询另外一个接口查询进度。

目标:

1接口上一个注解即可实现接口异步(优化:可以通过header参数动态控制是否异步)

2一个方法实现进度条的更新

二、时序图

springboot利用aop实现接口异步(进度条)的全过程

三、功能演示

springboot利用aop实现接口异步(进度条)的全过程

四、关键代码

controller

@enableasync是自已定义注解更新缓存进度asyncservice.updatepercent(per);

    @enableasync
    @requestmapping(value = "test", method = requestmethod.post)
    @apioperation(value = "接口测试")
    @apiimplicitparams({
            @apiimplicitparam(name = "num", value = "数字", required = true, datatype = "int", paramtype = "query", defaultvalue = "1")
    })
    public object demo(integer num) throws interruptedexception {
        for (int i = 0; i < 15; i++) {
            thread.sleep(1000);
            //计算百分比
            string per = bigdecimal.valueof(i).divide(bigdecimal.valueof(15), 2, roundingmode.half_down).tostring();
            //更新redis缓存进度
            asyncservice.updatepercent(per);
        }
        integer b = 100;
        return result.success(string.format("线程变量值:%s,100除以%s的结果是%s", requestholder.get(), num, b / num));
    }

asyncaop

 
import cn.hutool.core.util.idutil;
import com.asyf.demo.common.result;
import com.asyf.demo.common.pojo.requestholder;
import com.asyf.demo.service.asyncservice;
import lombok.extern.slf4j.slf4j;
import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.annotation.around;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.pointcut;
import org.aspectj.lang.reflect.methodsignature;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
import org.springframework.web.context.request.requestcontextholder;
import org.springframework.web.context.request.servletrequestattributes;
 
import javax.servlet.http.httpservletrequest;
 
@aspect
@component
@slf4j
public class asyncaop {
 
    @autowired
    private asyncservice asyncservice;
 
    @pointcut("@annotation(com.asyf.demo.common.aop.enableasync)")
    public void costtimepointcut() {
    }
 
    @around("costtimepointcut()")
    public object around(proceedingjoinpoint point) throws throwable {
        long begintime = system.currenttimemillis();
        //请求header
        servletrequestattributes servletrequestattributes = (servletrequestattributes) requestcontextholder.getrequestattributes();
        httpservletrequest request = servletrequestattributes.getrequest();
        requestholder.set(request.getheader("dateformat"));
        //异步消息
        string id = idutil.simpleuuid();
        asyncmsg asyncmsg = new asyncmsg();
        asyncmsg.setid(id);
        //异步返回值
        object result = result.success(asyncmsg);
        string requestholder = requestholder.get();
 
        //异步执行
        asyncservice.async(requestholder, asyncmsg, point);
 
        //执行时长(毫秒)
        long time = system.currenttimemillis() - begintime;
        logcosttime(point, time);
 
        return result;
    }
 
 
    private void logcosttime(proceedingjoinpoint point, long time) {
        methodsignature signature = (methodsignature) point.getsignature();
        string classname = point.gettarget().getclass().getname();
        string methodname = signature.getname();
        log.info("class:{} method:{} 耗时:{}ms", classname, methodname, time);
    }
}

asyncservice

实现异步消息的更新

异步消息的进度信息传递通过本地线程与redis实现

import cn.hutool.core.exceptions.exceptionutil;
import com.asyf.demo.common.aop.asyncmsg;
import com.asyf.demo.common.pojo.asyncholder;
import com.asyf.demo.common.pojo.requestholder;
import com.asyf.demo.service.asyncservice;
import lombok.extern.slf4j.slf4j;
import org.aspectj.lang.proceedingjoinpoint;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.data.redis.core.redistemplate;
import org.springframework.stereotype.service;
 
import java.util.concurrent.timeunit;
 
@service
@slf4j
public class asyncserviceimpl implements asyncservice {
 
    @autowired
    private redistemplate redistemplate;
 
    @override
    public void async(string requestholder, asyncmsg asyncmsg, proceedingjoinpoint point) {
        new thread(new runnable() {
            @override
            public void run() {
                string id = asyncmsg.getid();
                //请求线程变量-传递请求线程参数
                requestholder.set(requestholder);
                //异步消息线程变量-传送id到实际方法以便方法更新进度
                asyncholder.set(asyncmsg);
                //执行方法
                try {
                    redistemplate.opsforvalue().set(id, asyncmsg, 60, timeunit.minutes);
                    object result = point.proceed();
                    asyncmsg.setresult(result);
                    asyncmsg.setstatus("0");
                    redistemplate.opsforvalue().set(id, asyncmsg, 60, timeunit.minutes);
                } catch (throwable throwable) {
                    log.error(exceptionutil.stacktracetostring(throwable));
                    asyncmsg.setstatus("-1");
                    asyncmsg.setresult(throwable.getlocalizedmessage());
                    redistemplate.opsforvalue().set(id, asyncmsg, 60, timeunit.minutes);
                }
            }
        }).start();
    }
 
    @override
    public void updatepercent(string per) {
        asyncmsg asyncmsg = asyncholder.get();
        asyncmsg.setpercent(per);
        redistemplate.opsforvalue().set(asyncmsg.getid(), asyncmsg, 60, timeunit.minutes);
    }
 
}

五、源码地址

java-demo: 存储代码示例 - gitee.com

总结

到此这篇关于springboot利用aop实现接口异步(进度条)的文章就介绍到这了,更多相关springboot aop实现接口异步内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!