Merge pull request 'AD用户状态同步ehr员工状态' (#4) from nflg-bom-transition-lhj0801 into feature/DM/nflg-bom-transition
Reviewed-on: http://192.168.0.40:3000/root/nflg_project/pulls/4
This commit is contained in:
commit
0ff9cfe794
|
|
@ -17,6 +17,7 @@ import com.nflg.product.material.pojo.vo.AuthorityMenuVO;
|
||||||
import com.nflg.product.material.pojo.vo.AuthorityUserVO;
|
import com.nflg.product.material.pojo.vo.AuthorityUserVO;
|
||||||
import com.nflg.product.material.service.AuthorityPowerService;
|
import com.nflg.product.material.service.AuthorityPowerService;
|
||||||
import com.nflg.product.material.service.AuthorityUserService;
|
import com.nflg.product.material.service.AuthorityUserService;
|
||||||
|
import com.nflg.product.material.service.EhrService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import nflg.product.common.constant.STATE;
|
import nflg.product.common.constant.STATE;
|
||||||
|
|
@ -174,6 +175,10 @@ public class AuthorityUserApi extends BaseApi {
|
||||||
return ResultVO.success(authorityUserService.updateById(user));
|
return ResultVO.success(authorityUserService.updateById(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("syncEhrEmployee")
|
||||||
|
@ApiOperation("同步ehr员工的状态")
|
||||||
|
public ResultVO<String> syncEhrEmployee(){
|
||||||
|
return ResultVO.success(authorityUserService.syncEhrEmployee());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,9 @@ public class SaticScheduleTask {
|
||||||
@Resource
|
@Resource
|
||||||
private MaterialUpdateBillService materialUpdateBillService;
|
private MaterialUpdateBillService materialUpdateBillService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AuthorityUserService authorityUserService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新AD(每天6点)
|
* 更新AD(每天6点)
|
||||||
*/
|
*/
|
||||||
|
|
@ -149,4 +152,12 @@ public class SaticScheduleTask {
|
||||||
public void doQueryCurrentTwoYearsUsage() throws Exception {
|
public void doQueryCurrentTwoYearsUsage() throws Exception {
|
||||||
materialMainService.doQueryCurrentTwoYearsUsage();
|
materialMainService.doQueryCurrentTwoYearsUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每周六 同步ehr用户人员状态,离职的更新为未启用
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "${ehr.sync.employee.state.time:0 0 9 ? * SAT}")
|
||||||
|
public void syncEhrEmployee() {
|
||||||
|
authorityUserService.syncEhrEmployee();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
package com.nflg.product.material.pojo.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* packageName com.nflg.product.material.pojo.dto
|
||||||
|
*
|
||||||
|
* @author luohj
|
||||||
|
* @className EhrEmployeeDTO
|
||||||
|
* @date 2024/8/1 0001
|
||||||
|
* @description ehr 员工信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class EhrEmployeeDTO implements Serializable {
|
||||||
|
|
||||||
|
@ApiModelProperty("员工ID")
|
||||||
|
private String EmpID;
|
||||||
|
|
||||||
|
@ApiModelProperty("员工编号")
|
||||||
|
private String EmpNo;
|
||||||
|
|
||||||
|
@ApiModelProperty("员工姓名")
|
||||||
|
private String EmpName;
|
||||||
|
|
||||||
|
@ApiModelProperty("所属部门ID")
|
||||||
|
private String DeptId;
|
||||||
|
|
||||||
|
@ApiModelProperty("所属部门编号")
|
||||||
|
private String DEPTCODE;
|
||||||
|
|
||||||
|
@ApiModelProperty("员工状态 0启用1停用")
|
||||||
|
private String DISABLE;
|
||||||
|
|
||||||
|
@ApiModelProperty("人员类别 1在职5离职")
|
||||||
|
private String A0191;
|
||||||
|
|
||||||
|
@ApiModelProperty("手机号码")
|
||||||
|
private String CELLPHONE;
|
||||||
|
|
||||||
|
@ApiModelProperty("岗位ID")
|
||||||
|
private String POSITIONID;
|
||||||
|
|
||||||
|
@ApiModelProperty("身份证号")
|
||||||
|
private String IDCARDNO;
|
||||||
|
|
||||||
|
@ApiModelProperty("性别")
|
||||||
|
private String SEX;
|
||||||
|
|
||||||
|
@ApiModelProperty("最后修改日期")
|
||||||
|
private Date LASTMODIFYTIME;
|
||||||
|
|
||||||
|
@ApiModelProperty("开户银行")
|
||||||
|
private String A0136;
|
||||||
|
|
||||||
|
@ApiModelProperty("银行代码")
|
||||||
|
private String YHDM;
|
||||||
|
|
||||||
|
@ApiModelProperty("银行账号")
|
||||||
|
private String A0137;
|
||||||
|
|
||||||
|
@ApiModelProperty("银行国家代码")
|
||||||
|
private String YHGJDM;
|
||||||
|
|
||||||
|
@ApiModelProperty("职级")
|
||||||
|
private String GWZJ;
|
||||||
|
|
||||||
|
@ApiModelProperty("序列")
|
||||||
|
private String RYXL;
|
||||||
|
|
||||||
|
@ApiModelProperty("是否结算加班费")
|
||||||
|
private String A01190;
|
||||||
|
|
||||||
|
@ApiModelProperty("入职日期")
|
||||||
|
private String A0141;
|
||||||
|
|
||||||
|
@ApiModelProperty("成本中心编码")
|
||||||
|
private String COSTNO;
|
||||||
|
|
||||||
|
@ApiModelProperty("成本中心")
|
||||||
|
private String COSTNAME;
|
||||||
|
|
||||||
|
@ApiModelProperty("第一次合同签订时间")
|
||||||
|
private Date HT_BEGIN_DATE;
|
||||||
|
}
|
||||||
|
|
@ -3,10 +3,13 @@ package com.nflg.product.material.service;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.lang.TypeReference;
|
import cn.hutool.core.lang.TypeReference;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.core.util.XmlUtil;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.nflg.product.base.core.conmon.util.DESUtil;
|
import com.nflg.product.base.core.conmon.util.DESUtil;
|
||||||
import com.nflg.product.base.core.vo.PageVO;
|
import com.nflg.product.base.core.vo.PageVO;
|
||||||
import com.nflg.product.material.mapper.master.AuthorityPowerMapper;
|
import com.nflg.product.material.mapper.master.AuthorityPowerMapper;
|
||||||
|
|
@ -14,23 +17,30 @@ import com.nflg.product.material.mapper.master.AuthorityPowerPermissionMapper;
|
||||||
import com.nflg.product.material.mapper.master.AuthorityRoleMapper;
|
import com.nflg.product.material.mapper.master.AuthorityRoleMapper;
|
||||||
import com.nflg.product.material.mapper.master.AuthorityUserMapper;
|
import com.nflg.product.material.mapper.master.AuthorityUserMapper;
|
||||||
import com.nflg.product.material.pojo.dto.AuthorityUserDTO;
|
import com.nflg.product.material.pojo.dto.AuthorityUserDTO;
|
||||||
|
import com.nflg.product.material.pojo.dto.EhrEmployeeDTO;
|
||||||
import com.nflg.product.material.pojo.dto.SaveUserMemuPermissionDTO;
|
import com.nflg.product.material.pojo.dto.SaveUserMemuPermissionDTO;
|
||||||
import com.nflg.product.material.pojo.dto.UserRoleDTO;
|
import com.nflg.product.material.pojo.dto.UserRoleDTO;
|
||||||
import com.nflg.product.material.pojo.entity.AuthorityPowerPermissionEntity;
|
import com.nflg.product.material.pojo.entity.AuthorityPowerPermissionEntity;
|
||||||
import com.nflg.product.material.pojo.entity.AuthorityUserEntity;
|
import com.nflg.product.material.pojo.entity.AuthorityUserEntity;
|
||||||
import com.nflg.product.material.pojo.query.AuthorityUserQuery;
|
import com.nflg.product.material.pojo.query.AuthorityUserQuery;
|
||||||
import com.nflg.product.material.pojo.vo.AuthorityUserVO;
|
import com.nflg.product.material.pojo.vo.AuthorityUserVO;
|
||||||
|
import com.nflg.product.material.util.HttpUtils;
|
||||||
import com.nflg.product.material.util.ListCommonUtil;
|
import com.nflg.product.material.util.ListCommonUtil;
|
||||||
|
import org.dom4j.Document;
|
||||||
|
import org.dom4j.DocumentException;
|
||||||
|
import org.dom4j.DocumentHelper;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -58,6 +68,8 @@ public class AuthorityUserService extends ServiceImpl<AuthorityUserMapper, Autho
|
||||||
@Resource
|
@Resource
|
||||||
AuthorityRoleMapper authorityRoleMapper;
|
AuthorityRoleMapper authorityRoleMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EhrService ehrService;
|
||||||
/**
|
/**
|
||||||
* 分页查询所有数据
|
* 分页查询所有数据
|
||||||
*
|
*
|
||||||
|
|
@ -199,5 +211,37 @@ public class AuthorityUserService extends ServiceImpl<AuthorityUserMapper, Autho
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步ehr用户人员状态,离职的更新为未启用
|
||||||
|
* 将来源为AD域同步的用户,与ehr数据更新状态
|
||||||
|
*/
|
||||||
|
public String syncEhrEmployee(){
|
||||||
|
String res = "";
|
||||||
|
//获取AD域同步的用户,状态是启用中的集合,判断在ehr中是否已经离职了
|
||||||
|
List<AuthorityUserEntity> userList = this.list(Wrappers.<AuthorityUserEntity>lambdaQuery()
|
||||||
|
.eq(AuthorityUserEntity::getUserSource,1)
|
||||||
|
.eq(AuthorityUserEntity::getEnableState,1));
|
||||||
|
if(userList.isEmpty()){
|
||||||
|
return "正常AD用户数量为0";
|
||||||
|
}
|
||||||
|
String sessionId = ehrService.getSessionId();
|
||||||
|
List<EhrEmployeeDTO> empList = ehrService.empList(sessionId);
|
||||||
|
if(empList.isEmpty()){
|
||||||
|
return "员工数量为0";
|
||||||
|
}
|
||||||
|
//离职员工编号集合
|
||||||
|
List<String> empNoList = empList.stream().filter(emp -> Objects.equals("1",emp.getDISABLE()) || Objects.equals("5",emp.getA0191()))
|
||||||
|
.map(emp -> emp.getEmpNo().toUpperCase()).collect(Collectors.toList());
|
||||||
|
List<AuthorityUserEntity> disableList = userList.stream()
|
||||||
|
.filter(user -> empNoList.contains(user.getUserCode().toUpperCase()))
|
||||||
|
.map(user -> {
|
||||||
|
user.setEnableState(0);
|
||||||
|
return user;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
if(!disableList.isEmpty()){
|
||||||
|
this.updateBatchById(disableList);
|
||||||
|
}
|
||||||
|
return String.format("正常AD用户数:%d,员工数:%d,离职数:%d,更新记录:%d",userList.size(),empList.size(),empNoList.size(),disableList.size());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
package com.nflg.product.material.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.util.XmlUtil;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.nflg.product.material.pojo.dto.EhrEmployeeDTO;
|
||||||
|
import com.nflg.product.material.util.CompletableFutureUtil;
|
||||||
|
import com.nflg.product.material.util.HttpUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dom4j.Document;
|
||||||
|
import org.dom4j.DocumentHelper;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* packageName com.nflg.product.material.service
|
||||||
|
*
|
||||||
|
* @author luohj
|
||||||
|
* @className EhrService
|
||||||
|
* @date 2024/8/1 0001
|
||||||
|
* @description ehr 相关接口
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
@RefreshScope
|
||||||
|
public class EhrService {
|
||||||
|
|
||||||
|
private static HttpUtils httpUtils = new HttpUtils();
|
||||||
|
|
||||||
|
@Value("${ehr.url:http://192.168.163.30:8088/hr/DataInterface/WebService.asmx}")
|
||||||
|
private String ehrUrl;
|
||||||
|
@Value("${ehr.user:nflj}")
|
||||||
|
private String ehrUser;
|
||||||
|
@Value("${ehr.pwd:nfljadmin}")
|
||||||
|
private String ehrPwd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ehr sessionId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getSessionId(){
|
||||||
|
String sessionId = "";
|
||||||
|
Map<String,String> mp = Maps.newHashMap();
|
||||||
|
mp.put("S1",ehrUser);
|
||||||
|
mp.put("S2",ehrPwd);
|
||||||
|
try {
|
||||||
|
String re = httpUtils.doformPost(ehrUrl + "/Login",mp);
|
||||||
|
Document d = DocumentHelper.parseText(re);
|
||||||
|
sessionId = d.getRootElement().getStringValue();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("ehr 登录异常: {}",e.getMessage());
|
||||||
|
}
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ehr 员工总数
|
||||||
|
* @param sessionId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Integer empTotal(String sessionId){
|
||||||
|
int total = -1;
|
||||||
|
Map<String,String> mp2 = Maps.newHashMap();
|
||||||
|
mp2.put("SessionID",sessionId);
|
||||||
|
mp2.put("NewOnly","0");
|
||||||
|
mp2.put("Time","");
|
||||||
|
String re2 = null;
|
||||||
|
try {
|
||||||
|
re2 = httpUtils.doPost(ehrUrl + "/EmpBeginGetEmployee",mp2);
|
||||||
|
Document d2 = DocumentHelper.parseText(re2);
|
||||||
|
total =Integer.valueOf(d2.getRootElement().getStringValue());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ehr 员工列表
|
||||||
|
* @param sessionId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<EhrEmployeeDTO> empList(String sessionId){
|
||||||
|
int total = empTotal(sessionId);
|
||||||
|
List<EhrEmployeeDTO> ehrEmployeeList =Lists.newArrayList();
|
||||||
|
//每批次数量 1222 6 22 7
|
||||||
|
int batch = 200;
|
||||||
|
if(total <= 0){
|
||||||
|
return ehrEmployeeList;
|
||||||
|
}
|
||||||
|
int mul = total / batch;
|
||||||
|
int rem = total % batch;
|
||||||
|
int cnt = mul + (rem > 0 ? 1: 0);
|
||||||
|
List<CompletableFuture<List<EhrEmployeeDTO>>> taskList = Lists.newArrayList();
|
||||||
|
for (int i = 1; i <= cnt; i++) {
|
||||||
|
int finalI = i;
|
||||||
|
CompletableFuture<List<EhrEmployeeDTO>> future = CompletableFuture.supplyAsync(() -> {
|
||||||
|
Map<String,String> mp3 = Maps.newHashMap();
|
||||||
|
mp3.put("SessionID",sessionId);
|
||||||
|
mp3.put("from",String.valueOf( (finalI -1)*batch + 1 ));
|
||||||
|
mp3.put("to",String.valueOf( (finalI * batch) > total ? total: (finalI * batch) ));
|
||||||
|
try {
|
||||||
|
String re3 = httpUtils.doPost(ehrUrl + "/GetSegment",mp3);
|
||||||
|
Document d3 = DocumentHelper.parseText(re3);
|
||||||
|
String r3 = d3.getRootElement().getStringValue();
|
||||||
|
Map<String, Object> m3 = XmlUtil.xmlToMap(r3);
|
||||||
|
return Convert.toList(EhrEmployeeDTO.class,m3.get("Table"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("eHr获取人员信息异常:{},{}",sessionId,e.getMessage());
|
||||||
|
}
|
||||||
|
return Lists.newArrayList();
|
||||||
|
});
|
||||||
|
taskList.add(future);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
|
||||||
|
CompletableFuture<Void> allTask = CompletableFuture.allOf(taskList.stream().map(CompletableFutureUtil::executeActionAsync).toArray(CompletableFuture[]::new));
|
||||||
|
allTask.get();
|
||||||
|
taskList.forEach(t -> ehrEmployeeList.addAll(t.join()));
|
||||||
|
|
||||||
|
//清除缓存
|
||||||
|
Map<String,String> mp4 = Maps.newHashMap();
|
||||||
|
mp4.put("SessionID",sessionId);
|
||||||
|
httpUtils.doPost(ehrUrl + "/ClearCache",mp4);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("eHr获取人员信息异常:{}",e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ehrEmployeeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.nflg.product.material.util;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* packageName com.nflg.product.material.util
|
||||||
|
*
|
||||||
|
* @author luohj
|
||||||
|
* @className CompletableFutureUtil
|
||||||
|
* @date 2024/8/1 0001
|
||||||
|
* @description TODO
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class CompletableFutureUtil {
|
||||||
|
private static final int MAX_RETRIES = 3;
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> List<T> getAllCompleted(List<CompletableFuture<T>> futuresList) throws Exception {
|
||||||
|
CompletableFuture<Void> allFuturesResult = CompletableFuture
|
||||||
|
.allOf(futuresList.stream().map(CompletableFutureUtil::executeActionAsync).toArray(CompletableFuture[]::new));
|
||||||
|
allFuturesResult.get();
|
||||||
|
return futuresList
|
||||||
|
.stream()
|
||||||
|
.map(CompletableFuture::join)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CompletableFuture<T> executeActionAsync(CompletableFuture<T> action) {
|
||||||
|
return action
|
||||||
|
.thenApply(CompletableFuture::completedFuture)
|
||||||
|
.exceptionally(t -> retry(t, action, 0))
|
||||||
|
.thenCompose(Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> CompletableFuture<T> retry(Throwable first, CompletableFuture<T> action, int retry) {
|
||||||
|
if (retry >= MAX_RETRIES) {
|
||||||
|
return CompletableFutureUtil.failedFuture(first);
|
||||||
|
}
|
||||||
|
return action
|
||||||
|
.thenApply(CompletableFuture::completedFuture)
|
||||||
|
.exceptionally(t -> {
|
||||||
|
// first.addSuppressed(t);
|
||||||
|
log.info("任务:{} , 重试:{}", action, retry);
|
||||||
|
return retry(first, action, retry + 1); })
|
||||||
|
.thenCompose(Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CompletableFuture<T> failedFuture(Throwable t) {
|
||||||
|
final CompletableFuture<T> cf = new CompletableFuture<>();
|
||||||
|
cf.completeExceptionally(t);
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue