@@ -246,10 +246,6 @@ | |||||
<systemPath>${basedir}/src/lib/zwdd-sdk-java-1.2.0.jar</systemPath> | <systemPath>${basedir}/src/lib/zwdd-sdk-java-1.2.0.jar</systemPath> | ||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>com.ningdatech</groupId> | |||||
<artifactId>nd-rabbitmq-starter</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.httpcomponents</groupId> | <groupId>org.apache.httpcomponents</groupId> | ||||
<artifactId>httpclient</artifactId> | <artifactId>httpclient</artifactId> | ||||
</dependency> | </dependency> | ||||
@@ -49,7 +49,6 @@ public class PrequalificationDeclaredController { | |||||
@ApiOperation(value = "申报预审", notes = "申报预审") | @ApiOperation(value = "申报预审", notes = "申报预审") | ||||
@PostMapping("/start") | @PostMapping("/start") | ||||
public String startTheProcess(@Validated @RequestBody DefaultDeclaredDTO dto) { | 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()) || | VUtils.isTrue(!ProjectStatusEnum.PLAN_TO_BE_DECLARED.getCode().equals(projectInfo.getStatus()) || | ||||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage())) | !ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage())) | ||||
.throwMessage("提交失败 该项目不是 方案待申报状态或者未立项阶段"); | .throwMessage("提交失败 该项目不是 方案待申报状态或者未立项阶段"); | ||||
// TODO 再判断 该项目是否 真实走完 预审审批 | |||||
ProcessStartParamsVo params = new ProcessStartParamsVo(); | ProcessStartParamsVo params = new ProcessStartParamsVo(); | ||||
params.setUser(dto.getUser()); | params.setUser(dto.getUser()); | ||||
@@ -114,6 +114,14 @@ public class DeclaredProjectManage { | |||||
@Transactional(rollbackFor = Exception.class) | @Transactional(rollbackFor = Exception.class) | ||||
public String startTheProcess(DefaultDeclaredDTO dto) { | public String startTheProcess(DefaultDeclaredDTO dto) { | ||||
ProjectDTO projectInfo = dto.getProjectInfo(); | 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(); | String regionCode = projectInfo.getAreaCode(); | ||||
WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class) | WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class) | ||||
@@ -144,8 +152,8 @@ public class DeclaredProjectManage { | |||||
String instanceId = processService.startProcess(model.getProcessDefId(), params); | String instanceId = processService.startProcess(model.getProcessDefId(), params); | ||||
log.info("申报项目成功 【{}】", instanceId); | log.info("申报项目成功 【{}】", instanceId); | ||||
//保存项目 | |||||
saveProject(dto.getProjectInfo(), instanceId, regionCode); | |||||
//如果是重新提交的话 判断下 项目是否存在 | |||||
saveOrUpdateProject(dto.getProjectInfo(), instanceId, regionCode); | |||||
return instanceId; | return instanceId; | ||||
} | } | ||||
@@ -174,6 +182,11 @@ public class DeclaredProjectManage { | |||||
throw new BusinessException(String.format("此 【%s】区域找不到单位流程配置", regionCode)); | 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(); | ProcessStartParamsVo params = new ProcessStartParamsVo(); | ||||
params.setUser(dto.getUser()); | params.setUser(dto.getUser()); | ||||
params.setProcessUsers(Collections.emptyMap()); | params.setProcessUsers(Collections.emptyMap()); | ||||
@@ -221,7 +234,7 @@ public class DeclaredProjectManage { | |||||
* @param projectDto | * @param projectDto | ||||
* @param instanceId | * @param instanceId | ||||
*/ | */ | ||||
private void saveProject(ProjectDTO projectDto, String instanceId, String regionCode) { | |||||
private void saveOrUpdateProject(ProjectDTO projectDto, String instanceId, String regionCode) { | |||||
//流程启动之后 入库项目 重要业务信息 用于列表查询 展示 | //流程启动之后 入库项目 重要业务信息 用于列表查询 展示 | ||||
try { | try { | ||||
//保存项目表信息 | //保存项目表信息 | ||||
@@ -233,7 +246,7 @@ public class DeclaredProjectManage { | |||||
project.setStage(ProjectStatusEnum.NOT_APPROVED.getCode()); | project.setStage(ProjectStatusEnum.NOT_APPROVED.getCode()); | ||||
project.setStatus(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode()); | project.setStatus(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode()); | ||||
project.setInstCode(instanceId); | project.setInstCode(instanceId); | ||||
projectService.save(project); | |||||
projectService.saveOrUpdate(project); | |||||
//保存项目应用 | //保存项目应用 | ||||
if (CollUtil.isNotEmpty(projectDto.getApplicationList())) { | if (CollUtil.isNotEmpty(projectDto.getApplicationList())) { | ||||
List<ProjectApplication> applications = projectDto.getApplicationList().stream().map(application -> { | List<ProjectApplication> applications = projectDto.getApplicationList().stream().map(application -> { | ||||
@@ -250,6 +263,7 @@ public class DeclaredProjectManage { | |||||
projectInst.setInstCode(instanceId); | projectInst.setInstCode(instanceId); | ||||
projectInst.setCreatOn(LocalDateTime.now()); | projectInst.setCreatOn(LocalDateTime.now()); | ||||
projectInst.setUpdateOn(LocalDateTime.now()); | projectInst.setUpdateOn(LocalDateTime.now()); | ||||
projectInst.setInstType(ProjectProcessStageEnum.ORG_INTERNAL_APPROVAL_PROCESS.getCode()); | |||||
projectInstService.save(projectInst); | projectInstService.save(projectInst); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
log.error("项目信息入库错误 ", 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.model.entity.ProjectInst; | ||||
import com.ningdatech.pmapi.projectlib.service.IProjectInstService; | import com.ningdatech.pmapi.projectlib.service.IProjectInstService; | ||||
import com.ningdatech.pmapi.projectlib.service.IProjectService; | import com.ningdatech.pmapi.projectlib.service.IProjectService; | ||||
import com.ningdatech.pmapi.staging.serivice.IProjectStagingService; | |||||
import com.wflow.bean.entity.WflowModels; | import com.wflow.bean.entity.WflowModels; | ||||
import com.wflow.exception.BusinessException; | import com.wflow.exception.BusinessException; | ||||
import com.wflow.workflow.bean.vo.ProcessStartParamsVo; | import com.wflow.workflow.bean.vo.ProcessStartParamsVo; | ||||
@@ -52,6 +53,8 @@ public class PrequalificationDeclaredProjectManage { | |||||
private final IProjectInstService projectInstService; | private final IProjectInstService projectInstService; | ||||
private final IProjectStagingService projectStagingService; | |||||
/** | /** | ||||
* 提交预审 | * 提交预审 | ||||
* | * | ||||
@@ -95,8 +98,13 @@ public class PrequalificationDeclaredProjectManage { | |||||
//如果是省级部门 需要联审的(申报金额大于1000万 并且是市级项目) | //如果是省级部门 需要联审的(申报金额大于1000万 并且是市级项目) | ||||
if(ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS | if(ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS | ||||
.getCode().equals(projectInfo.getStatus())){ | .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 | }else if(ProjectStatusEnum.PRE_APPLYING | ||||
.getCode().equals(projectInfo.getStatus())){ | .getCode().equals(projectInfo.getStatus())){ | ||||
//如果是非省级联审的项目 直接提交 预审 | //如果是非省级联审的项目 直接提交 预审 | ||||
@@ -115,14 +123,13 @@ public class PrequalificationDeclaredProjectManage { | |||||
log.info("提交预审项目成功 【{}】", instanceId); | log.info("提交预审项目成功 【{}】", instanceId); | ||||
//保存预审项目 | //保存预审项目 | ||||
if(Objects.nonNull(instanceId)){ | |||||
modifyProject(projectInfo, instanceId); | |||||
} | |||||
modifyProject(projectInfo, instanceId); | |||||
}else{ | }else{ | ||||
throw new BusinessException("项目状态 错误 project :" + JSON.toJSONString(projectInfo)); | throw new BusinessException("项目状态 错误 project :" + JSON.toJSONString(projectInfo)); | ||||
} | } | ||||
return instanceId; | |||||
return "提交预审成功【" + instanceId + "】"; | |||||
} | } | ||||
/** | /** | ||||
@@ -146,6 +153,7 @@ public class PrequalificationDeclaredProjectManage { | |||||
projectInst.setInstCode(instanceId); | projectInst.setInstCode(instanceId); | ||||
projectInst.setCreatOn(LocalDateTime.now()); | projectInst.setCreatOn(LocalDateTime.now()); | ||||
projectInst.setUpdateOn(LocalDateTime.now()); | projectInst.setUpdateOn(LocalDateTime.now()); | ||||
projectInst.setInstType(ProjectProcessStageEnum.PROJECT_PREQUALIFICATION_APPROVAL_PROCESS.getCode()); | |||||
projectInstService.save(projectInst); | projectInstService.save(projectInst); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
log.error("提交预审 项目信息修改 错误 ", 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") | @ApiModelProperty("实例ID") | ||||
private String instCode; | private String instCode; | ||||
@ApiModelProperty("实例类型 1单位内部审批流程 2项目预审审批流程 3部门联合审批流程 4建设方案审批流程 5验收申报审批流程") | |||||
private Integer instType; | |||||
@ApiModelProperty("创建时间") | @ApiModelProperty("创建时间") | ||||
private LocalDateTime creatOn; | 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,69 @@ | |||||
package com.ningdatech.pmapi.staging.utils; | |||||
import com.google.common.collect.Maps; | |||||
import com.ningdatech.pmapi.projectdeclared.manage.ConstructionPlanManage; | |||||
import com.ningdatech.pmapi.projectdeclared.manage.DeclaredProjectManage; | |||||
import com.ningdatech.pmapi.projectdeclared.manage.PrequalificationDeclaredProjectManage; | |||||
import com.ningdatech.pmapi.projectdeclared.manage.ReviewByProvincialDeptManage; | |||||
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 ReviewByProvincialDeptManage provincialDeptManage; | |||||
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->provincialDeptManage.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); | |||||
} | |||||
} |
@@ -87,17 +87,6 @@ spring: | |||||
wall: | wall: | ||||
config: | config: | ||||
multi-statement-allow: true | 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: | mybatis-plus: | ||||
configuration: | configuration: | ||||
@@ -150,11 +150,6 @@ | |||||
<version>1.0.0</version> | <version>1.0.0</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>com.ningdatech</groupId> | |||||
<artifactId>nd-rabbitmq-starter</artifactId> | |||||
<version>1.0.0</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>joda-time</groupId> | <groupId>joda-time</groupId> | ||||
<artifactId>joda-time</artifactId> | <artifactId>joda-time</artifactId> | ||||
<version>2.10.6</version> | <version>2.10.6</version> | ||||