• 简介

在日常开发中,如果一个链接执行的时间过长,前端等不到后端返回数据会报错,或者用户一直等待任务执行,影响用户体验。
很多时候采用的方法是,前端将链接超时时间设长,但这有时并不优雅。
在这里采用redis+多线程,用户可以实时查看当前任务进度,还不必去过多等待任务执行。

  • 项目流程
    流程图
  • 技术概要
    此项目是在ruoyi架构上进行的(没有单独配置redis)
    为了与其他功能解耦,将此功能单独设置成一个模块,通过用户调用,实现流程。
    通过java代理对用户要执行的代码进行处理,使用户只需要处理业务代码,简化用户操作(核心)。
//给run方法添加代理
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //执行任务,报错
                Object invoke = null;
                try {
                    invoke = method.invoke(runnable, args);
                    updateTaskState(key,Entity.builder().state("200").msg(STATE_MSG_200).build());
                } catch (Exception e) {
                    updateTaskState(key,Entity.builder().state("400").msg(STATE_MSG_400).build());
                }
                return invoke;
            }
        };
  • 代码
    用户调用:
    通过简单的代码,就能完成对控制器的修改,并且不入侵原先的代码。如果觉得redisTaskServer.getTaskState(key)获取后判断,还是冗余,可以把这段代码放入到createTask方法中通过抛出异常实现
		String key = "user:12fla:001"; //key建议使用用户id加方法的标示
        Entity method = redisTaskServer.getTaskState(key); 
        if(method != null){
            return "上一个任务没有执行完:"+method.getMsg();
        }
        redisTaskServer.createTask(key, new Runnable() {
            @Override
            public void run() {
                //要执行的业务端代码
            }
        });
        return "已添加任务";

功能:

##########对外开放接口类
public interface RedisTaskServer {
    //查询任务结果
    public Entity getTaskState(String key);
    //删除任务结果
    public int deleteTaskKey(List<String> keys);
    //修改任务结果
    public Entity updateTaskState(String key,Entity entity);
    //简化一套 用户只要发送过来key与要执行人任务就可以。
    //自动生成任务信息共cglib动态生成结果
    public boolean createTask(String key,Runnable runnable);
    public String createKey(String arg);
}
#################对外开放实体类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Entity {
    private String state;
    private String msg;
}
################接口实现类
@Service
public class RedisTaskServerImpl implements RedisTaskServer {
    private final String KEY = "redisTask";
    private final String STATE_MSG_0 = "任务正在运行";
    private final String STATE_MSG_200 = "任务执行完毕";
    private final String STATE_MSG_400 = "任务执行失败";
    @Autowired
    private RedisCache redisCache;
    @Override
    public Entity getTaskState(String key) {
        String cacheMapValue = redisCache.getCacheMapValue(KEY, key);
        if(!cacheMapValue.isEmpty()){
            Entity entity = JSONUtil.toBean(cacheMapValue, Entity.class);
            return entity;
        }
        return null;
    }

    @Override
    public int deleteTaskKey(List<String> keys) {
        Map<String, Object> cacheMap = redisCache.getCacheMap(KEY);
        if(cacheMap == null){return 0;}
        int result = 0;
        for (String key : keys) {
            if(cacheMap.remove(key)!=null){
                result++;
            }
        }
        return result;
    }

    @Override
    public Entity updateTaskState(String key, Entity entity) {
        redisCache.setCacheMapValue(KEY,key,JSONUtil.parse(entity).toString());
        return entity;
    }

    @Override
    public boolean createTask(String key, Runnable runnable) {
        //不负责结果key冲突
        updateTaskState(key,Entity.builder().state("0").msg(STATE_MSG_0).build());

        //给run方法添加代理
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //执行任务,报错
                Object invoke = null;
                try {
                    invoke = method.invoke(runnable, args);
                    updateTaskState(key,Entity.builder().state("200").msg(STATE_MSG_200).build());
                } catch (Exception e) {
                    updateTaskState(key,Entity.builder().state("400").msg(STATE_MSG_400).build());
                }
                return invoke;
            }
        };
        Runnable o = (Runnable) Proxy.newProxyInstance(RedisTaskServerImpl.class.getClassLoader(),runnable.getClass().getInterfaces(),invocationHandler);

        new Thread(o).start();
        return true;
    }

    @Override
    public String createKey(String arg) {
        Long deptId = SecurityUtils.getLoginUser().getUser().getDeptId();
        String  key = "user:"+deptId+"fla:"+arg;
        return key;
    }
}复制

推荐内容

Logo

快速构建 Web 应用程序

更多推荐