@@ -246,10 +246,6 @@ | |||
<systemPath>${basedir}/src/lib/zwdd-sdk-java-1.2.0.jar</systemPath> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.ningdatech</groupId> | |||
<artifactId>nd-rabbitmq-starter</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.apache.httpcomponents</groupId> | |||
<artifactId>httpclient</artifactId> | |||
</dependency> | |||
@@ -49,7 +49,6 @@ public class PrequalificationDeclaredController { | |||
@ApiOperation(value = "申报预审", notes = "申报预审") | |||
@PostMapping("/start") | |||
public String startTheProcess(@Validated @RequestBody DefaultDeclaredDTO dto) { | |||
String instanceId = prequalificationDeclaredProjectManage.startTheProcess(dto); | |||
return "提交预审 【" + instanceId + "】 成功"; | |||
return prequalificationDeclaredProjectManage.startTheProcess(dto); | |||
} | |||
} |
@@ -82,7 +82,6 @@ public class ConstructionPlanManage { | |||
VUtils.isTrue(!ProjectStatusEnum.PLAN_TO_BE_DECLARED.getCode().equals(projectInfo.getStatus()) || | |||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage())) | |||
.throwMessage("提交失败 该项目不是 方案待申报状态或者未立项阶段"); | |||
// TODO 再判断 该项目是否 真实走完 预审审批 | |||
ProcessStartParamsVo params = new ProcessStartParamsVo(); | |||
params.setUser(dto.getUser()); | |||
@@ -114,6 +114,14 @@ public class DeclaredProjectManage { | |||
@Transactional(rollbackFor = Exception.class) | |||
public String startTheProcess(DefaultDeclaredDTO dto) { | |||
ProjectDTO projectInfo = dto.getProjectInfo(); | |||
//如果是重新提交的话 判断下 项目是否存在 | |||
if(Objects.nonNull(projectInfo.getId())){ | |||
Project oldProject = projectService.getById(projectInfo.getId()); | |||
VUtils.isTrue(Objects.isNull(oldProject)) | |||
.throwMessage(String.format("重新提交失败 该项目【%s】不存在",projectInfo.getId())); | |||
} | |||
String regionCode = projectInfo.getAreaCode(); | |||
WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class) | |||
@@ -144,8 +152,8 @@ public class DeclaredProjectManage { | |||
String instanceId = processService.startProcess(model.getProcessDefId(), params); | |||
log.info("申报项目成功 【{}】", instanceId); | |||
//保存项目 | |||
saveProject(dto.getProjectInfo(), instanceId, regionCode); | |||
//如果是重新提交的话 判断下 项目是否存在 | |||
saveOrUpdateProject(dto.getProjectInfo(), instanceId, regionCode); | |||
return instanceId; | |||
} | |||
@@ -174,6 +182,11 @@ public class DeclaredProjectManage { | |||
throw new BusinessException(String.format("此 【%s】区域找不到单位流程配置", regionCode)); | |||
} | |||
//首先要判断 项目当前状态 是不是 单位内部拒绝 | |||
VUtils.isTrue(!ProjectStatusEnum.UNDER_INTERNAL_AUDIT_NOT_PASS.getCode().equals(projectInfo.getStatus()) || | |||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage())) | |||
.throwMessage("提交失败 该项目不是 单位内部拒绝审核状态或者未立项阶段"); | |||
ProcessStartParamsVo params = new ProcessStartParamsVo(); | |||
params.setUser(dto.getUser()); | |||
params.setProcessUsers(Collections.emptyMap()); | |||
@@ -221,7 +234,7 @@ public class DeclaredProjectManage { | |||
* @param projectDto | |||
* @param instanceId | |||
*/ | |||
private void saveProject(ProjectDTO projectDto, String instanceId, String regionCode) { | |||
private void saveOrUpdateProject(ProjectDTO projectDto, String instanceId, String regionCode) { | |||
//流程启动之后 入库项目 重要业务信息 用于列表查询 展示 | |||
try { | |||
//保存项目表信息 | |||
@@ -233,7 +246,7 @@ public class DeclaredProjectManage { | |||
project.setStage(ProjectStatusEnum.NOT_APPROVED.getCode()); | |||
project.setStatus(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode()); | |||
project.setInstCode(instanceId); | |||
projectService.save(project); | |||
projectService.saveOrUpdate(project); | |||
//保存项目应用 | |||
if (CollUtil.isNotEmpty(projectDto.getApplicationList())) { | |||
List<ProjectApplication> applications = projectDto.getApplicationList().stream().map(application -> { | |||
@@ -250,6 +263,7 @@ public class DeclaredProjectManage { | |||
projectInst.setInstCode(instanceId); | |||
projectInst.setCreatOn(LocalDateTime.now()); | |||
projectInst.setUpdateOn(LocalDateTime.now()); | |||
projectInst.setInstType(ProjectProcessStageEnum.ORG_INTERNAL_APPROVAL_PROCESS.getCode()); | |||
projectInstService.save(projectInst); | |||
} catch (Exception e) { | |||
log.error("项目信息入库错误 ", e); | |||
@@ -15,6 +15,7 @@ import com.ningdatech.pmapi.projectlib.model.entity.Project; | |||
import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst; | |||
import com.ningdatech.pmapi.projectlib.service.IProjectInstService; | |||
import com.ningdatech.pmapi.projectlib.service.IProjectService; | |||
import com.ningdatech.pmapi.staging.serivice.IProjectStagingService; | |||
import com.wflow.bean.entity.WflowModels; | |||
import com.wflow.exception.BusinessException; | |||
import com.wflow.workflow.bean.vo.ProcessStartParamsVo; | |||
@@ -52,6 +53,8 @@ public class PrequalificationDeclaredProjectManage { | |||
private final IProjectInstService projectInstService; | |||
private final IProjectStagingService projectStagingService; | |||
/** | |||
* 提交预审 | |||
* | |||
@@ -95,8 +98,13 @@ public class PrequalificationDeclaredProjectManage { | |||
//如果是省级部门 需要联审的(申报金额大于1000万 并且是市级项目) | |||
if(ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS | |||
.getCode().equals(projectInfo.getStatus())){ | |||
//TODO 对接外部 省级 | |||
instanceId = DeclaredProjectContant.Instance.PROVINCE_INSTANCE_ID; | |||
//入库暂存表 后续处理 对接外部接口 | |||
projectInfo.setUpdateOn(LocalDateTime.now()); | |||
if(projectStagingService.addByProject(projectInfo,"省级部门联审") | |||
&& projectService.updateById(projectInfo)){ | |||
return "提交省级部门联审成功"; | |||
} | |||
return "提交省级部门联审失败"; | |||
}else if(ProjectStatusEnum.PRE_APPLYING | |||
.getCode().equals(projectInfo.getStatus())){ | |||
//如果是非省级联审的项目 直接提交 预审 | |||
@@ -115,14 +123,13 @@ public class PrequalificationDeclaredProjectManage { | |||
log.info("提交预审项目成功 【{}】", instanceId); | |||
//保存预审项目 | |||
if(Objects.nonNull(instanceId)){ | |||
modifyProject(projectInfo, instanceId); | |||
} | |||
modifyProject(projectInfo, instanceId); | |||
}else{ | |||
throw new BusinessException("项目状态 错误 project :" + JSON.toJSONString(projectInfo)); | |||
} | |||
return instanceId; | |||
return "提交预审成功【" + instanceId + "】"; | |||
} | |||
/** | |||
@@ -146,6 +153,7 @@ public class PrequalificationDeclaredProjectManage { | |||
projectInst.setInstCode(instanceId); | |||
projectInst.setCreatOn(LocalDateTime.now()); | |||
projectInst.setUpdateOn(LocalDateTime.now()); | |||
projectInst.setInstType(ProjectProcessStageEnum.PROJECT_PREQUALIFICATION_APPROVAL_PROCESS.getCode()); | |||
projectInstService.save(projectInst); | |||
} catch (Exception e) { | |||
log.error("提交预审 项目信息修改 错误 ", e); | |||
@@ -0,0 +1,87 @@ | |||
package com.ningdatech.pmapi.projectdeclared.manage; | |||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
import com.ningdatech.basic.function.VUtils; | |||
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum; | |||
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum; | |||
import com.ningdatech.pmapi.projectlib.model.entity.Project; | |||
import com.ningdatech.pmapi.projectlib.service.IProjectInstService; | |||
import com.ningdatech.pmapi.projectlib.service.IProjectService; | |||
import com.wflow.bean.entity.WflowModels; | |||
import com.wflow.exception.BusinessException; | |||
import com.wflow.workflow.service.ProcessInstanceService; | |||
import com.wflow.workflow.service.ProcessModelService; | |||
import lombok.RequiredArgsConstructor; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.stereotype.Component; | |||
import org.springframework.transaction.annotation.Transactional; | |||
import java.util.Objects; | |||
/** | |||
* @Classname ReviewByDeptJointManage | |||
* @Description 部门联审 | |||
* @Date 2023/2/17 14:48 | |||
* @Author PoffyZhang | |||
*/ | |||
@Component | |||
@Slf4j | |||
@RequiredArgsConstructor | |||
public class ReviewByDeptJointManage { | |||
private final IProjectService projectService; | |||
private final ProcessModelService processModelService; | |||
private final ProcessInstanceService processService; | |||
private final IProjectInstService projectInstService; | |||
/** | |||
* 省级部门联审 | |||
* @param project | |||
* @return | |||
*/ | |||
@Transactional(rollbackFor = Exception.class) | |||
public Boolean startTheProcess(Project project) { | |||
VUtils.isTrue(Objects.isNull(project.getId())).throwMessage("提交失败 缺少项目ID!"); | |||
Project projectInfo = projectService.getById(project.getId()); | |||
VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!"); | |||
String regionCode = projectInfo.getAreaCode(); | |||
WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class) | |||
.eq(WflowModels::getRegionCode, regionCode) | |||
.eq(WflowModels::getProcessType, ProjectProcessStageEnum.DEPARTMENT_JOINT_APPROVAL_PROCESS.getCode()) | |||
.last("limit 1")); | |||
if (Objects.isNull(model)) { | |||
log.error("此 【{}】区域找不到 部门联审申报流程配置", regionCode); | |||
throw new BusinessException(String.format("此 【%s】区域找不到 部门联审申报流程配置", regionCode)); | |||
} | |||
//要判断 项目当前状态 是不是 部门联审 | |||
VUtils.isTrue(!ProjectStatusEnum.DEPARTMENT_JOINT_REVIEW.getCode().equals(projectInfo.getStatus()) || | |||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage())) | |||
.throwMessage("提交失败 该项目不是 省级部门联审状态状态或者未立项阶段"); | |||
// 再判断 该项目是否 真实走完 预审审批 并且提取出 提交人 | |||
// projectInstService. | |||
// | |||
// ProcessStartParamsVo params = new ProcessStartParamsVo(); | |||
// params.setUser(dto.getUser()); | |||
// params.setProcessUsers(Collections.emptyMap()); | |||
// //放入条件判断的项目字段 | |||
// ProjectConditionDTO conditionDto = new ProjectConditionDTO(); | |||
// BeanUtils.copyProperties(projectInfo, conditionDto); | |||
// dto.getFormData().putAll( | |||
// JSON.parseObject(JSON.toJSONString(conditionDto), new TypeReference<Map<String, Object>>() { | |||
// }) | |||
// ); | |||
// params.setFormData(dto.getFormData()); | |||
// String instanceId = processService.startProcess(model.getProcessDefId(), params); | |||
// log.info("建设方案项目申报成功 【{}】", instanceId); | |||
// | |||
// //保存建设项目 | |||
// modifyProject(projectInfo, instanceId, projectInfo.getConstructionPlanFile()); | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
package com.ningdatech.pmapi.projectdeclared.manage; | |||
import com.ningdatech.basic.function.VUtils; | |||
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum; | |||
import com.ningdatech.pmapi.projectlib.model.entity.Project; | |||
import com.ningdatech.pmapi.projectlib.service.IProjectService; | |||
import lombok.RequiredArgsConstructor; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.stereotype.Component; | |||
import org.springframework.transaction.annotation.Transactional; | |||
import java.util.Objects; | |||
/** | |||
* @Classname ReviewByProvincialDeptManage | |||
* @Description 省级部门联审 | |||
* @Date 2023/2/17 14:48 | |||
* @Author PoffyZhang | |||
*/ | |||
@Component | |||
@Slf4j | |||
@RequiredArgsConstructor | |||
public class ReviewByProvincialDeptManage { | |||
private final IProjectService projectService; | |||
/** | |||
* 省级部门联审 | |||
* @param project | |||
* @return | |||
*/ | |||
@Transactional(rollbackFor = Exception.class) | |||
public Boolean startTheProcess(Project project) { | |||
VUtils.isTrue(Objects.isNull(project.getId())).throwMessage("提交失败 缺少项目ID!"); | |||
Project projectInfo = projectService.getById(project.getId()); | |||
VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!"); | |||
String regionCode = projectInfo.getAreaCode(); | |||
//首先要判断 项目当前状态 是不是 省级部门联审 | |||
VUtils.isTrue(!ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS.getCode().equals(projectInfo.getStatus()) || | |||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage())) | |||
.throwMessage("提交失败 该项目不是 省级部门联审状态状态或者未立项阶段"); | |||
// TODO 对接省级联审的接口 | |||
Boolean sucessProvince = Boolean.FALSE; | |||
if(sucessProvince){ | |||
//成功了后 | |||
} | |||
return Boolean.FALSE; | |||
} | |||
} |
@@ -34,6 +34,9 @@ public class ProjectInst implements Serializable { | |||
@ApiModelProperty("实例ID") | |||
private String instCode; | |||
@ApiModelProperty("实例类型 1单位内部审批流程 2项目预审审批流程 3部门联合审批流程 4建设方案审批流程 5验收申报审批流程") | |||
private Integer instType; | |||
@ApiModelProperty("创建时间") | |||
private LocalDateTime creatOn; | |||
@@ -1,64 +0,0 @@ | |||
package com.ningdatech.pmapi.rabbitmq.config; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.amqp.core.Binding; | |||
import org.springframework.amqp.core.BindingBuilder; | |||
import org.springframework.amqp.core.DirectExchange; | |||
import org.springframework.amqp.core.Queue; | |||
import org.springframework.context.annotation.Bean; | |||
import org.springframework.context.annotation.Configuration; | |||
/** | |||
* @author zpf | |||
* @version 1.0.0 | |||
* @Description 创建direct类型的交换机 | |||
* @createTime 2023年02月17日 | |||
*/ | |||
@Slf4j | |||
@Configuration | |||
public class DirectRabbitConfig { | |||
private static final String QUEUE = "TestDirectQueue"; | |||
private static final String EXCHANGE = "TestDirectExchange"; | |||
private static final String ROUTING_KEY = "TestDirectRouting"; | |||
/** | |||
* 创建一个名为TestDirectQueue的队列 | |||
* | |||
* @return | |||
*/ | |||
@Bean | |||
public Queue testDirectQueue() { | |||
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效 | |||
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable | |||
// autoDelete:是否自动删除,有消息者订阅本队列,然后所有消费者都解除订阅此队列,会自动删除。 | |||
// arguments:队列携带的参数,比如设置队列的死信队列,消息的过期时间等等。 | |||
return new Queue(QUEUE, true); | |||
} | |||
/** | |||
* 创建一个名为TestDirectExchange的Direct类型的交换机 | |||
* | |||
* @return | |||
*/ | |||
@Bean | |||
public DirectExchange testDirectExchange() { | |||
// durable:是否持久化,默认是false,持久化交换机。 | |||
// autoDelete:是否自动删除,交换机先有队列或者其他交换机绑定的时候,然后当该交换机没有队列或其他交换机绑定的时候,会自动删除。 | |||
// arguments:交换机设置的参数,比如设置交换机的备用交换机(Alternate Exchange),当消息不能被路由到该交换机绑定的队列上时,会自动路由到备用交换机 | |||
return new DirectExchange(EXCHANGE, true, false); | |||
} | |||
/** | |||
* 绑定交换机和队列 | |||
* | |||
* @return | |||
*/ | |||
@Bean | |||
public Binding bindingDirect() { | |||
//bind队列to交换机中with路由key(routing key) | |||
return BindingBuilder.bind(testDirectQueue()).to(testDirectExchange()).with(ROUTING_KEY); | |||
} | |||
} | |||
@@ -1,47 +0,0 @@ | |||
package com.ningdatech.pmapi.rabbitmq.config; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.amqp.core.ReturnedMessage; | |||
import org.springframework.amqp.rabbit.connection.ConnectionFactory; | |||
import org.springframework.amqp.rabbit.connection.CorrelationData; | |||
import org.springframework.amqp.rabbit.core.RabbitTemplate; | |||
import org.springframework.context.annotation.Bean; | |||
import org.springframework.context.annotation.Configuration; | |||
@Slf4j | |||
@Configuration | |||
public class RabbitConfig { | |||
@Bean | |||
public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory) { | |||
RabbitTemplate rabbitTemplate = new RabbitTemplate(); | |||
rabbitTemplate.setConnectionFactory(connectionFactory); | |||
//设置消息投递失败的策略,有两种策略:自动删除或返回到客户端。 | |||
//我们既然要做可靠性,当然是设置为返回到客户端(true是返回客户端,false是自动删除) | |||
rabbitTemplate.setMandatory(true); | |||
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() { | |||
@Override | |||
public void confirm(CorrelationData correlationData, boolean ack, String cause) { | |||
if (ack) { | |||
log.info("ConfirmCallback 关联数据:{},投递成功,确认情况:{}", correlationData, ack); | |||
} else { | |||
log.info("ConfirmCallback 关联数据:{},投递失败,确认情况:{},原因:{}", correlationData, ack, cause); | |||
} | |||
} | |||
}); | |||
rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() { | |||
@Override | |||
public void returnedMessage(ReturnedMessage returnedMessage) { | |||
log.info("ReturnsCallback 消息:{},回应码:{},回应信息:{},交换机:{},路由键:{}" | |||
, returnedMessage.getMessage(), returnedMessage.getReplyCode() | |||
, returnedMessage.getReplyText(), returnedMessage.getExchange() | |||
, returnedMessage.getRoutingKey()); | |||
} | |||
}); | |||
return rabbitTemplate; | |||
} | |||
} |
@@ -1,59 +0,0 @@ | |||
package com.ningdatech.pmapi.rabbitmq.controller; | |||
import com.alibaba.fastjson.JSON; | |||
import com.ningdatech.pmapi.user.entity.UserInfo; | |||
import org.springframework.amqp.rabbit.connection.CorrelationData; | |||
import org.springframework.amqp.rabbit.core.RabbitTemplate; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.web.bind.annotation.GetMapping; | |||
import org.springframework.web.bind.annotation.RestController; | |||
import java.util.UUID; | |||
/** | |||
* @author zpf | |||
* @version 1.0.0 | |||
* @Description | |||
* @createTime 2023年02月17日 | |||
*/ | |||
@RestController | |||
public class TestController { | |||
@Autowired | |||
RabbitTemplate rabbitTemplate; | |||
@GetMapping("/test") | |||
public String test() { | |||
return "producer ok"; | |||
} | |||
@GetMapping("/push") | |||
public String push() { | |||
for (int i = 1; i <= 5; i++) { | |||
//这个参数是用来做消息的唯一标识 | |||
//发布消息时使用,存储在消息的headers中 | |||
UserInfo user = new UserInfo(); | |||
user.setId(1L); | |||
user.setRealName("汪涵"); | |||
// 关联的数据,可以用在消息投递失败的时候,作为一个线索,比如我把当前用户的id放进去,如果user消息投递失败 | |||
// 我后面可以根据id再找到user,再次投递数据 | |||
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString().concat("-") + i); | |||
if (i == 2) { | |||
//故意把交换机写错,演示 confirmCallback | |||
rabbitTemplate.convertAndSend("TestDirectExchange_111", "TestDirectRouting", | |||
JSON.toJSONString(user), correlationData); | |||
} else if (i == 3) { | |||
//故意把路由键写错,演示 returnCallback | |||
rabbitTemplate.convertAndSend("TestDirectExchange", "TestDirectRouting_111", | |||
JSON.toJSONString(user), correlationData); | |||
} else { | |||
//正常发送 | |||
rabbitTemplate.convertAndSend("TestDirectExchange", "TestDirectRouting", | |||
JSON.toJSONString(user), correlationData); | |||
} | |||
} | |||
return "producer push ok"; | |||
} | |||
} | |||
@@ -0,0 +1,93 @@ | |||
package com.ningdatech.pmapi.scheduler.task; | |||
import cn.hutool.core.collection.CollUtil; | |||
import com.alibaba.fastjson.JSON; | |||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
import com.ningdatech.pmapi.projectlib.model.entity.Project; | |||
import com.ningdatech.pmapi.projectlib.service.IProjectService; | |||
import com.ningdatech.pmapi.scheduler.contants.TaskContant; | |||
import com.ningdatech.pmapi.staging.contants.StagingContant; | |||
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging; | |||
import com.ningdatech.pmapi.staging.serivice.IProjectStagingService; | |||
import com.ningdatech.pmapi.staging.utils.ProjectStatusFlowMapUtil; | |||
import lombok.RequiredArgsConstructor; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.scheduling.annotation.Scheduled; | |||
import org.springframework.stereotype.Component; | |||
import java.net.InetAddress; | |||
import java.net.UnknownHostException; | |||
import java.time.LocalDateTime; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.function.Function; | |||
/** | |||
* @Classname ProjectStatusFlowTask | |||
* @Description | |||
* @Date 2023/2/20 10:12 | |||
* @Author PoffyZhang | |||
*/ | |||
@Slf4j | |||
@Component | |||
@RequiredArgsConstructor | |||
public class ProjectStatusFlowTask { | |||
private final IProjectStagingService projectStagingService; | |||
private final IProjectService projectService; | |||
private final ProjectStatusFlowMapUtil projectStatusFlowMapUtil; | |||
@Scheduled(cron = "0 */1 * * * ?") | |||
public void statusFlow() throws UnknownHostException { | |||
//测试暂时用自己电脑HOST | |||
if (TaskContant.Host.HOST_ZPF.equals(InetAddress.getLocalHost().getHostName())) { | |||
//1. 定时取 项目暂存表的数据 去进行状态继续流转 | |||
List<ProjectStaging> stagingList = projectStagingService.list(Wrappers.lambdaQuery(ProjectStaging.class) | |||
.eq(ProjectStaging::getDead,Boolean.FALSE) | |||
.ge(ProjectStaging::getNextTime, LocalDateTime.now()) | |||
.le(ProjectStaging::getRetryTimes, StagingContant.Retry.MAX_RETRY_TIMES) | |||
.orderByAsc(ProjectStaging::getProjectId)); | |||
log.info("需要状态流转的项目 size:{} :{}",stagingList.size(), JSON.toJSONString(stagingList)); | |||
if(CollUtil.isEmpty(stagingList)){ | |||
log.info("没有需要状态流转的项目!"); | |||
return; | |||
} | |||
//遍历 | |||
for(ProjectStaging projectStaging : stagingList){ | |||
try{ | |||
Project project = projectService.getById(projectStaging.getProjectId()); | |||
if(Objects.isNull(project)){ | |||
log.info("此项目 【{}】 不存在",projectStaging.getProjectId()); | |||
continue; | |||
} | |||
//2. 用函数map 定位到 状态流转的函数 | |||
Map<Integer, Function<Project, Boolean>> reStartProcessMap = | |||
projectStatusFlowMapUtil.statusFlowFunctionMap; | |||
if(!reStartProcessMap.containsKey(project.getStatus())){ | |||
log.info("此项目 【{}】 当前状态 【{}】,没有对应流转函数",projectStaging.getProjectId(),project.getStatus()); | |||
continue; | |||
} | |||
Function<Project, Boolean> functionMap = reStartProcessMap.get(project.getStatus()); | |||
//执行对应的函数 | |||
if(functionMap.apply(project)){ | |||
//执行成功了 删除暂存的数据 | |||
projectStagingService.removeById(projectStaging); | |||
} | |||
}catch (Exception e){ | |||
log.error("项目流转 异常 projectId:【" + projectStaging.getProjectId() + "】 异常内容:" + e); | |||
}finally { | |||
//增加重试的次数 和下次扫描时间 | |||
projectStagingService.addRetryTimes(projectStaging); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
package com.ningdatech.pmapi.staging.contants; | |||
/** | |||
* 项目暂存 静态配置 | |||
*/ | |||
public interface StagingContant { | |||
class Retry { | |||
public static final Integer MAX_RETRY_TIMES = 10; | |||
} | |||
} |
@@ -0,0 +1,13 @@ | |||
package com.ningdatech.pmapi.staging.mapper; | |||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging; | |||
import org.apache.ibatis.annotations.Param; | |||
import java.time.LocalDateTime; | |||
public interface ProjectStagingMapper extends BaseMapper<ProjectStaging> { | |||
Boolean addRetryTimes(@Param("id") Long id, @Param("retryTimes") Integer retryTimes, | |||
@Param("nextRetryTime") LocalDateTime nextRetryTime,@Param("dead") Boolean dead); | |||
} |
@@ -0,0 +1,12 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||
<mapper namespace="com.ningdatech.pmapi.staging.mapper.ProjectStagingMapper"> | |||
<update id="addRetryTimes" > | |||
update nd_project_staging | |||
set retry_times = #{retryTimes}, | |||
next_time = #{nextRetryTime}, | |||
dead = #{dead} | |||
where id = #{id} and retry_times = #{retryTimes - 1} | |||
</update> | |||
</mapper> |
@@ -0,0 +1,69 @@ | |||
package com.ningdatech.pmapi.staging.model.entity; | |||
import com.baomidou.mybatisplus.annotation.IdType; | |||
import com.baomidou.mybatisplus.annotation.TableId; | |||
import com.baomidou.mybatisplus.annotation.TableName; | |||
import io.swagger.annotations.ApiModel; | |||
import io.swagger.annotations.ApiModelProperty; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Builder; | |||
import lombok.Data; | |||
import lombok.NoArgsConstructor; | |||
import java.io.Serializable; | |||
import java.time.LocalDateTime; | |||
/** | |||
* @Classname ProjectStaging | |||
* @Description | |||
* @Date 2023/2/20 9:40 | |||
* @Author PoffyZhang | |||
*/ | |||
@Data | |||
@Builder | |||
@AllArgsConstructor | |||
@NoArgsConstructor | |||
@TableName("nd_project_staging") | |||
@ApiModel(value = "ProjectStaging", description = "项目暂存表 扫描进行 状态继续流转 做解耦用") | |||
public class ProjectStaging implements Serializable { | |||
@ApiModelProperty("主键") | |||
@TableId(type = IdType.AUTO) | |||
private Long id; | |||
@ApiModelProperty("项目ID") | |||
private Long projectId; | |||
@ApiModelProperty("项目名称") | |||
private String projectName; | |||
@ApiModelProperty("实例code") | |||
private String instCode; | |||
@ApiModelProperty("流程状态") | |||
private Integer processStatus; | |||
@ApiModelProperty("项目阶段") | |||
private Integer stage; | |||
@ApiModelProperty("项目状态") | |||
private Integer status; | |||
@ApiModelProperty("备注") | |||
private String remark; | |||
@ApiModelProperty("重试次数") | |||
private Integer retryTimes; | |||
@ApiModelProperty("是否死信") | |||
private Boolean dead; | |||
@ApiModelProperty("下次扫描时间") | |||
private LocalDateTime nextTime; | |||
@ApiModelProperty("创建时间") | |||
private LocalDateTime createOn; | |||
@ApiModelProperty("修改时间") | |||
private LocalDateTime updateOn; | |||
} |
@@ -0,0 +1,18 @@ | |||
package com.ningdatech.pmapi.staging.serivice; | |||
import com.baomidou.mybatisplus.extension.service.IService; | |||
import com.ningdatech.pmapi.projectlib.model.entity.Project; | |||
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging; | |||
/** | |||
* @Classname IProjectStagingService | |||
* @Description | |||
* @Date 2023/2/20 10:08 | |||
* @Author PoffyZhang | |||
*/ | |||
public interface IProjectStagingService extends IService<ProjectStaging> { | |||
Boolean addRetryTimes(ProjectStaging projectStaging); | |||
public Boolean addByProject(Project project,String remark) ; | |||
} |
@@ -0,0 +1,77 @@ | |||
package com.ningdatech.pmapi.staging.serivice.impl; | |||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||
import com.ningdatech.pmapi.projectlib.model.entity.Project; | |||
import com.ningdatech.pmapi.staging.contants.StagingContant; | |||
import com.ningdatech.pmapi.staging.mapper.ProjectStagingMapper; | |||
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging; | |||
import com.ningdatech.pmapi.staging.serivice.IProjectStagingService; | |||
import com.ningdatech.pmapi.staging.utils.ProjectStatusFlowMapUtil; | |||
import lombok.RequiredArgsConstructor; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.stereotype.Service; | |||
import java.time.LocalDateTime; | |||
/** | |||
* <p> | |||
* 服务实现类 | |||
* </p> | |||
* | |||
* @author zpf | |||
* @since 2023-02-18 | |||
*/ | |||
@Service | |||
@Slf4j | |||
@RequiredArgsConstructor | |||
public class ProjectStagingServiceImpl extends ServiceImpl<ProjectStagingMapper, ProjectStaging> implements IProjectStagingService { | |||
private final ProjectStagingMapper mapper; | |||
private final ProjectStatusFlowMapUtil projectStatusFlowMapUtil; | |||
/** | |||
* 在某些状态节点 增加一个项目到状态暂存库 | |||
* @param project | |||
* @return | |||
*/ | |||
@Override | |||
public Boolean addByProject(Project project,String remark) { | |||
ProjectStaging projectStaging = ProjectStaging.builder() | |||
.projectId(project.getId()) | |||
.projectName(project.getProjectName()) | |||
.stage(project.getStage()) | |||
.status(project.getStatus()) | |||
.createOn(LocalDateTime.now()) | |||
.updateOn(LocalDateTime.now()) | |||
.instCode(project.getInstCode()) | |||
.processStatus(project.getProcessStatus()) | |||
.nextTime(LocalDateTime.now()) | |||
.retryTimes(0) | |||
.remark(remark) | |||
.build(); | |||
return this.save(projectStaging); | |||
} | |||
/** | |||
* 增加 重试次数 和下次扫描时间 | |||
* @param projectStaging | |||
* @return | |||
*/ | |||
@Override | |||
public Boolean addRetryTimes(ProjectStaging projectStaging) { | |||
Integer retryTimes = projectStaging.getRetryTimes() + 1; | |||
if(!projectStatusFlowMapUtil.intervalTimeMap.containsKey(retryTimes)){ | |||
log.info("没有对应重试间隔时间 添加重试信息失败"); | |||
return Boolean.FALSE; | |||
} | |||
Integer addSeconds = projectStatusFlowMapUtil.intervalTimeMap.get(retryTimes); | |||
Boolean dead = Boolean.FALSE; | |||
//超过重试最大次数 dead置为 true | |||
if(retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0){ | |||
dead = Boolean.TRUE; | |||
} | |||
LocalDateTime nextRetryTime = LocalDateTime.now().plusSeconds(addSeconds); | |||
return mapper.addRetryTimes(projectStaging.getId(),retryTimes,nextRetryTime,dead); | |||
} | |||
} |
@@ -0,0 +1,66 @@ | |||
package com.ningdatech.pmapi.staging.utils; | |||
import com.google.common.collect.Maps; | |||
import com.ningdatech.pmapi.projectdeclared.manage.*; | |||
import com.ningdatech.pmapi.projectdeclared.model.dto.DefaultDeclaredDTO; | |||
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum; | |||
import com.ningdatech.pmapi.projectlib.model.entity.Project; | |||
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.stereotype.Component; | |||
import javax.annotation.PostConstruct; | |||
import java.util.Map; | |||
import java.util.function.Function; | |||
/** | |||
* @Classname ProjectStatusFlowMapUtil | |||
* @Description 状态流转 事件函数MAP | |||
* @Date 2023/2/15 11:19 | |||
* @Author PoffyZhang | |||
*/ | |||
@Component | |||
@RequiredArgsConstructor | |||
public class ProjectStatusFlowMapUtil { | |||
private final ReviewByProvincialDeptManage provincialDeptManage; | |||
private final ReviewByDeptJointManage reviewByDeptJointManage; | |||
public Map<Integer, Function<Project,Boolean>> statusFlowFunctionMap = Maps.newHashMap(); | |||
/** | |||
* key 重试的次数 , value 是增加是描述 | |||
*/ | |||
public Map<Integer, Integer> intervalTimeMap = Maps.newHashMap(); | |||
/** | |||
* 初始化业务分派逻辑,代替了if-else部分 | |||
* key: 枚举 状态值 | |||
* value: lambda表达式,最终会获取发起实例的函数 | |||
*/ | |||
@PostConstruct | |||
public void statusFlowFunctionInit(){ | |||
//省级部门联审 | |||
statusFlowFunctionMap.put(ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS.getCode(), | |||
project->provincialDeptManage.startTheProcess(project)); | |||
//部门联审 | |||
statusFlowFunctionMap.put(ProjectStatusEnum.DEPARTMENT_JOINT_REVIEW.getCode(), | |||
project->reviewByDeptJointManage.startTheProcess(project)); | |||
} | |||
/** | |||
* 扫描的间隔越来越长 秒数 | |||
*/ | |||
@PostConstruct | |||
public void intervalTimeMapInit(){ | |||
intervalTimeMap.put(1,60 * 2); | |||
intervalTimeMap.put(2,60 * 6); | |||
intervalTimeMap.put(3,60 * 15); | |||
intervalTimeMap.put(4,60 * 30); | |||
intervalTimeMap.put(5,60 * 60); | |||
intervalTimeMap.put(6,60 * 60 * 2); | |||
intervalTimeMap.put(7,60 * 60 * 5); | |||
intervalTimeMap.put(8,60 * 60 * 12); | |||
intervalTimeMap.put(9,60 * 60 * 24); | |||
intervalTimeMap.put(10,60 * 60 * 72); | |||
} | |||
} |
@@ -2,6 +2,7 @@ package com.ningdatech.pmapi.user.manage; | |||
import cn.hutool.core.collection.CollUtil; | |||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||
import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||
import com.ningdatech.basic.exception.BizException; | |||
@@ -46,7 +47,8 @@ public class UserInfoManage { | |||
public PageVo<ResUserInfoListVO> list(ReqUserInfoListPO reqUserInfoListPO) { | |||
LambdaQueryWrapper<DingEmployeeInfo> wrapper = Wrappers.lambdaQuery(DingEmployeeInfo.class) | |||
.eq(DingEmployeeInfo::getMainJob, "true"); | |||
.eq(DingEmployeeInfo::getMainJob, "true") | |||
.eq(StringUtils.isNotBlank(reqUserInfoListPO.getOrgCode()), DingEmployeeInfo::getOrganizationCode, reqUserInfoListPO.getOrgCode()); | |||
Page<DingEmployeeInfo> page = iDingEmployeeInfoService.page(new Page<>(reqUserInfoListPO.getPageNumber(), reqUserInfoListPO.getPageSize()), wrapper); | |||
List<DingEmployeeInfo> records = page.getRecords(); | |||
@@ -25,6 +25,9 @@ public class ReqUserInfoListPO extends PagePo { | |||
@ApiModelProperty("所在单位(主职)") | |||
private String orgName; | |||
@ApiModelProperty("所在单位Code(主职)") | |||
private String orgCode; | |||
@ApiModelProperty("所属区域") | |||
private Long regionId; | |||
@@ -87,17 +87,6 @@ spring: | |||
wall: | |||
config: | |||
multi-statement-allow: true | |||
# rabbitmq 配置信息 | |||
rabbitmq: | |||
host: 110.40.194.60 | |||
port: 5672 | |||
username: admin | |||
password: admin | |||
#1、确保消息从发送端到服务端投递可靠(分为以下两个步骤) | |||
#1.1、确认消息已发送到交换机(Exchange) 可以把publisher-confirms: true 替换为 publisher-confirm-type: correlate | |||
publisher-confirm-type: correlated | |||
#1.2、确认消息从交换机中到队列中 | |||
publisher-returns: true | |||
mybatis-plus: | |||
configuration: | |||
@@ -150,11 +150,6 @@ | |||
<version>1.0.0</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.ningdatech</groupId> | |||
<artifactId>nd-rabbitmq-starter</artifactId> | |||
<version>1.0.0</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>joda-time</groupId> | |||
<artifactId>joda-time</artifactId> | |||
<version>2.10.6</version> | |||