CompletableFuture多线程查询统一结果返回
收到一个新的需求,设计的页面是这样的。
- 页面表格31个,统计展示,加上表格中风险等级字段需要运算得出,如果靠单线程去执行,耗时一定很长,综合考虑,采用多线程的方式将结果查询出来,执行完成后统一结果返回给前端。
- 思路:
-
-
实现细节
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));
}
}
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();
rs.put("selAjList",selajFuture.get());
rs.put("selRyList",selRyFuture.get());
}catch (Exception e){
e.printStackTrace();
}
return rs;
}
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;
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;
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多线程查询统一结果返回的案例使用,解决对应的问题,希望能帮到大家。