CompletableFuture多线程查询统一结果返回

CompletableFuture多线程查询统一结果返回

收到一个新的需求,设计的页面是这样的。

功能设计

  • 页面表格31个,统计展示,加上表格中风险等级字段需要运算得出,如果靠单线程去执行,耗时一定很长,综合考虑,采用多线程的方式将结果查询出来,执行完成后统一结果返回给前端。
  • 思路:
    • 每个表格启动一个子线程执行查询、计算。
    • 所有子线程执行完成后,统一结果返回个前端。
实现细节
  • Controller层
package com.gosuncn.fxfk.api.controller;

import com.alibaba.fastjson.JSONObject;
import com.gosuncn.fxfk.common.model.Response;
import com.gosuncn.fxfk.db.service.FxFkNxbgService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;


@RestController
@RequestMapping("/nxbg")
public class FxFkNxbgController {

    @Autowired
    private FxFkNxbgService fxFkNxbgService;

    @PostMapping("/getZffxqkList")
    public Response getZffxqkList(@RequestBody JSONObject params){
        if(params.isEmpty()) return Response.fail("请求参数不能为空!");
        return Response.success(fxFkNxbgService.getZffxqkList(params));
    }
}

  • Service接口
package com.gosuncn.fxfk.db.service;

import com.alibaba.fastjson.JSONObject;
import com.gosuncn.fxfk.entity.vo.common.RegionOrgVo;
import com.gosuncn.fxfk.entity.vo.nxbg.zffxylb.SwfxyYlb;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

public interface FxFkNxbgService {

    Map<String,Object> getZffxqkList(JSONObject params);
}
  • Service接口实现,这里只展示前两个表格的处理逻辑
package com.gosuncn.fxfk.db.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bsp.security.model.SessionUser;
import com.bsp.security.util.SessionUserUtil;
import com.gosuncn.fxfk.bsp.util.UserAuthorityUtil;
import com.gosuncn.fxfk.common.enums.EnumRoleLevel;
import com.gosuncn.fxfk.common.util.PoiUtil;
import com.gosuncn.fxfk.db.config.AsyncTaskConfig;
import com.gosuncn.fxfk.db.mapper.FkSwJalDwZdMapper;
import com.gosuncn.fxfk.db.service.*;
import com.gosuncn.fxfk.entity.vo.common.PmVo;
import com.gosuncn.fxfk.entity.vo.common.RegionOrgVo;
import com.gosuncn.fxfk.entity.vo.fx.CjlAreaCountVO;
import com.gosuncn.fxfk.entity.vo.nxbg.*;
import com.gosuncn.fxfk.entity.vo.nxbg.zffxylb.SwfxyYlb;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class FxFkNxbgServiceImpl implements FxFkNxbgService {

    @Value("${system-mark}")
    private String systemMark;

    @Autowired
    private AsyncTaskConfig asyncTaskConfig;

    @Autowired
    private FkSwSelajService fkSwSelajService;

    @Autowired
    private FkSwSelryService fkSwSelryService;


	
    @Async
    public List<SelAjZffxqk> getSelAjBgInfo(JSONObject params,SessionUser user) {
        List<SelAjZffxqk> selAjList = new ArrayList<>();
        if (params.isEmpty()) return selAjList;
        EnumRoleLevel roleLevel  = UserAuthorityUtil.getMaxRoleLevel(systemMark,user);
        List<CjlAreaCountVO> listAll = fkSwSelajService.queryAreaCountToXfjAll(JSON.parseObject(params.toJSONString(),Map.class));
        List<CjlAreaCountVO> listSj = new ArrayList<>();
        if(params.containsKey("orgCode") && StringUtils.isNotEmpty(params.getString("orgCode"))){ // 市级权限
            listSj.addAll(fkSwSelajService.queryAreaCountToXfj(JSON.parseObject(params.toJSONString(),Map.class),user));
        }
        for(int i = 0;i < listAll.size();i++){
            CjlAreaCountVO cjlAreaCountVO = listAll.get(i);
            SelAjZffxqk selAjZffxqk = new SelAjZffxqk();
            selAjZffxqk.setDwdm(cjlAreaCountVO.getRegionCode());
            selAjZffxqk.setDwmc(cjlAreaCountVO.getRegionName());
            selAjZffxqk.setAjzs(cjlAreaCountVO.getCaseTotal());
            selAjZffxqk.setAjwjs(cjlAreaCountVO.getWjazsTotal());
            selAjZffxqk.setAjwjl(cjlAreaCountVO.getJalTotal());
            if(i < 10){
                selAjZffxqk.setLevel("高");
            }else if(i >= 10 && i < 20) {
                selAjZffxqk.setLevel("中");
            }else {
                selAjZffxqk.setLevel("低");
            }
            selAjList.add(selAjZffxqk);
        }
        //市级权限
        if(params.containsKey("orgCode") && StringUtils.isNotEmpty(params.getString("orgCode"))){
            // 求两个集合的交集
            List<SelAjZffxqk> selAjListList = selAjList.stream()
                    .filter(entityA -> listSj.stream().map(CjlAreaCountVO::getRegionCode)
                            .anyMatch(code -> Objects.equals(entityA.getDwdm(),code)
                            )).collect(Collectors.toList());

            return selAjListList;
        }
        return selAjList;
    }


    @Async
    public List<SelRyXzXsAjWjl> getSelRyXzXsAjWjlBgInfo(JSONObject params,SessionUser user){
        List<SelRyXzXsAjWjl> selRyXzXsAjWjls = new ArrayList<>();
        if (params.isEmpty()) return selRyXzXsAjWjls;
        EnumRoleLevel roleLevel  = UserAuthorityUtil.getMaxRoleLevel(systemMark,user);
        List<CjlAreaCountVO> listAll = fkSwSelryService.queryAreaCountToXfjAll(JSON.parseObject(params.toJSONString(),Map.class));
        List<CjlAreaCountVO> listSj = new ArrayList<>();
        if(params.containsKey("orgCode") && StringUtils.isNotEmpty(params.getString("orgCode"))){ // 市级权限
            listSj.addAll(fkSwSelryService.queryAreaCountToXfj(JSON.parseObject(params.toJSONString(),Map.class),user));
        }
        for(int i = 0;i < listAll.size();i++){
            CjlAreaCountVO cjlAreaCountVO = listAll.get(i);
            SelRyXzXsAjWjl selRyZffxqk = new SelRyXzXsAjWjl();
            selRyZffxqk.setDwdm(cjlAreaCountVO.getRegionCode());
            selRyZffxqk.setDwmc(cjlAreaCountVO.getRegionName());
            selRyZffxqk.setAjzs(cjlAreaCountVO.getCaseTotal());
            selRyZffxqk.setAjwjs(cjlAreaCountVO.getWjazsTotal());
            selRyZffxqk.setAjwjl(cjlAreaCountVO.getJalTotal());
            if(i < 10){
                selRyZffxqk.setLevel("高");
            }else if(i >= 10 && i < 20) {
                selRyZffxqk.setLevel("中");
            }else {
                selRyZffxqk.setLevel("低");
            }
            selRyXzXsAjWjls.add(selRyZffxqk);
        }
        //市级权限
        if(params.containsKey("orgCode") && StringUtils.isNotEmpty(params.getString("orgCode"))){
            // 求两个集合的交集
            List<SelRyXzXsAjWjl> selRyXzXsAjWjlsList = selRyXzXsAjWjls.stream()
                    .filter(entityA -> listSj.stream().map(CjlAreaCountVO::getRegionCode)
                            .anyMatch(code -> Objects.equals(entityA.getDwdm(),code)
                            )).collect(Collectors.toList());

            return selRyXzXsAjWjlsList;
        }
        return selRyXzXsAjWjls;
    }


    @Override
    public Map<String, Object> getZffxqkList(JSONObject params) {
        Map<String,Object> rs = Collections.synchronizedMap(new LinkedHashMap<>(32));
        if (params.isEmpty()) return rs;
        SessionUser user = SessionUserUtil.getSessionUser();
        if(!params.containsKey("orgCode") || StringUtils.isEmpty(params.getString("orgCode"))){
            params.put("orgCode",UserAuthorityUtil.getCurrentUserLevelOrgId(systemMark,user));
        }
        // 使用多线程执行查询
        CompletableFuture<List<SelAjZffxqk>> selajFuture = CompletableFuture.supplyAsync(() -> getSelAjBgInfo(JSONObjectDeepCopy(params),user),asyncTaskConfig.asyncTaskExecutor());
        CompletableFuture<List<SelRyXzXsAjWjl>> selRyFuture = CompletableFuture.supplyAsync(() -> getSelRyXzXsAjWjlBgInfo(JSONObjectDeepCopy(params),user),asyncTaskConfig.asyncTaskExecutor());
        

        CompletableFuture<Void> allOf = CompletableFuture.allOf(selajFuture, selRyFuture);
        try{
            allOf.join(); // join阻塞主线程,等子线程执行完成后才会继续玩下执行。join会抛出未经检查的异常
            rs.put("selAjList",selajFuture.get());
            rs.put("selRyList",selRyFuture.get());
        }catch (Exception e){
            e.printStackTrace();
        }
        return rs;
    }


    /**
     * 需要进行深度拷贝的参数
     * @param params
     * @return
     */
    private JSONObject JSONObjectDeepCopy(JSONObject params){
        JSONObject rs = new JSONObject();
        rs.putAll(params);
        return rs;
    }
}

  • 线程池定义
package com.gosuncn.fxfk.db.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 多线程定义线程池
 */
@EnableAsync
@Configuration
public class AsyncTaskConfig {

    @Bean(name = "asyncTaskExecutor")
    public ThreadPoolTaskExecutor asyncTaskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20); //核心线程数
        executor.setMaxPoolSize(200); //最大线程数
        executor.setQueueCapacity(1000); //队列大小
        executor.setThreadNamePrefix("LocustTask-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setKeepAliveSeconds(1000);
        executor.setAllowCoreThreadTimeOut(false);
        executor.initialize();

        return executor;
    }
}

  • 对应的实体类
package com.gosuncn.fxfk.entity.vo.nxbg;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;

import java.io.Serializable;

/**
 * 十二类案件执法风险情况
 */
//@ExcelTarget(value = "selAjZffxqk")
public class SelAjZffxqk implements Serializable {

    @Excel(name = "单位")
    private String dwmc;

    @ExcelIgnore
    private String dwdm;

    @Excel(name = "案件总数")
    private Integer ajzs = 0; //案件总数

    @Excel(name = "案件未结数")
    private Integer ajwjs = 0; //案件未结数

    @Excel(name = "案件未结率")
    private String ajwjl; //案件未结率

    @Excel(name = "风险等级")
    private String level; //风险等级

    public String getDwmc() {
        return dwmc;
    }

    public void setDwmc(String dwmc) {
        this.dwmc = dwmc;
    }

    public String getDwdm() {
        return dwdm;
    }

    public void setDwdm(String dwdm) {
        this.dwdm = dwdm;
    }

    public Integer getAjzs() {
        return ajzs;
    }

    public void setAjzs(Integer ajzs) {
        this.ajzs = ajzs;
    }

    public Integer getAjwjs() {
        return ajwjs;
    }

    public void setAjwjs(Integer ajwjs) {
        this.ajwjs = ajwjs;
    }

    public String getAjwjl() {
        return ajwjl;
    }

    public void setAjwjl(String ajwjl) {
        this.ajwjl = ajwjl;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }
}
package com.gosuncn.fxfk.entity.vo.nxbg;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;

import java.io.Serializable;

/**
 * 十二类人员行政、刑事案件未结率
 */
//@ExcelTarget(value = "selRyXzXsAjWjl")
public class SelRyXzXsAjWjl implements Serializable {
    @Excel(name = "单位")
    private String dwmc;

    @ExcelIgnore
    private String dwdm;

    @Excel(name = "案件总数")
    private Integer ajzs = 0; //案件总数

    @Excel(name = "案件未结数")
    private Integer ajwjs = 0; //案件未结数

    @Excel(name = "案件未结率")
    private String ajwjl; //案件未结率

    @Excel(name = "风险等级")
    private String level; //风险等级

    public String getDwmc() {
        return dwmc;
    }

    public void setDwmc(String dwmc) {
        this.dwmc = dwmc;
    }

    public String getDwdm() {
        return dwdm;
    }

    public void setDwdm(String dwdm) {
        this.dwdm = dwdm;
    }

    public Integer getAjzs() {
        return ajzs;
    }

    public void setAjzs(Integer ajzs) {
        this.ajzs = ajzs;
    }

    public Integer getAjwjs() {
        return ajwjs;
    }

    public void setAjwjs(Integer ajwjs) {
        this.ajwjs = ajwjs;
    }

    public String getAjwjl() {
        return ajwjl;
    }

    public void setAjwjl(String ajwjl) {
        this.ajwjl = ajwjl;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }
}

结语

使用CompletableFuture多线程查询统一结果返回的案例使用,解决对应的问题,希望能帮到大家。
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值