业务场景:前段时间总结的有一个告警工单流程,我们都是直接自己建表,状态节点,操作节点,都是自定义设计的,而到后面会有很多的工单流程,比如创建一个遗留问题电子流,指定处理人进行分析闭环,等等多种电子流,后期重复的开发工作以及维护工作会越来越多。那么这里我们可以借助开源的工作流引擎 activiti
- Activiti是一个工作流引擎, activiti可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务流程由activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。
前置条件
- 本地安装jdk8以上
- 下载tomcat, 下载过程需要选择jre,所以要先安装好jdk
安装
Activiti6.0官方文档:https://www.activiti.org/userguide/
下载Activiti6.0,解压后有activiti-app.war、activiti-admin.war、activiti-rest.war三个war包。
- activiti-app:在线流程设计器、表单管理、应用管理、用户管理等;
- activiti-admin:查看流程定义、发起的流程实例、任务等;
- activiti-rest:提供Restful风格的服务;
将上面3个war放到tomcat的webapps目录下,运行bin目录下的startup.bat可以启动应用。
启动应用后,浏览器可以访问:
http://localhost:8080/activiti-app 默认账号密码:admin test
http://localhost:8080/activiti-admin 默认账号密码:admin admin
http://127.0.0.1:8080/activiti-rest/docs 默认账号密码:kermit kermit补充: 这里我们只需要运用这个app包,来进行在线流程设计,也就是用建模语言bpmn2.0定义流程图,结合实际业务场景的流程进行作图设计,然后再导出 xml文件,再放到我们的项目程序运行即可
访问登录后页面
这里我们是利用create process 创建流程,进行我们的业务流程图定义
总结特点:
1.流程图准备:
把对应的流程图画好导出bpmn2.0文件后,放入到项目中 resources -> process 目录下 ,文件以xml形式保存
2.引入依赖jar包
<dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter</artifactId> <version>7.1.0.M6</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator-autoconfigure</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>2.6.6</version> </dependency>
3.配置文件中 进行配置
activiti: database-schema-update:true #drop-create 该配置表示每次会删除activiti框架内置的表,然后再重新创建 true值则不会再重新建表 history-level:full deployment-name:deploy-test db-history-used:true #process-definition-location-prefix:classpath*:/processes/
4.接着运行程序项目后,框架会许多事情:
act_ge_bytearray 保存bpmn2.0xml文件记录
act_re_procdef 给bpmn2.0xml,创建对应的流程定义
5.也可以调用service接口 当前前端在创建一个问题电子流时,先生成一个 流程定义,对应的在act_re_procdef 表中会生成一个流程定义记录,对应的key是自定义的一个常量
@Override publicProcessDefinitiongetKnowIssueProcessDef(){ Return repositoryService.createProcessDefinitionQuery() .processDefinitionKey(KNOWN_ISSUE_PROCESS_DEF_KEY) .latestVersion() .singleResult(); }
6.针对该流程定义,创建一个实例,也就是开始一个流程的处理,需要由一个实例类对象来承载完成,与此同时,在对应的act_ru_task表中会生成一个该流程的一个子任务,也就是说,流程实例创建后,会对应这多个task任务,比如责任人处理任务,审批任务等,会把当前节点转到第一个子任务上,而不是在一开始的 开始事件
ProcessInstanceprocessInstance=runtimeService.startProcessInstanceByKey(KNOWN_ISSUE_PROCESS_DEF_KEY);
7.状态开始流转,节点任务走完,调用task的接口方法,传递对应的任务id
ProcessInstanceprocessInstance=runtimeService.startProcessInstanceByKey(KNOWN_ISSUE_PROCESS_DEF_KEY); StringprocessInstanceId=processInstance.getId(); Tasktask=getKnownIssueTaskByProcessInstanceId(processInstanceId); @Override publicTaskgetKnownIssueTaskByProcessInstanceId(StringprocessInstanceId){ returntaskService.createTaskQuery() .active() .processInstanceId(processInstanceId) .taskDefinitionKey(KNOWN_ISSUE_TASK_DEF_KEY) .singleResult(); } taskService.complete(task.getId());
8.如果流程只有一个任务节点,那么完成之后,流程就会结束,在act_ru_task表中的任务记录就会删除,并且在 act_hi_taskinst表中会记录着这个任务的历史记录 , act_hi_actinst表中则会记录整个流程过程记录,比如一开始的开始事件--》 到任务节点 --》 到结束事件,分别记录这几条数据,任务节点停留了多长时间
9.流程涉及有审批的话,就会有审批通过与驳回,这时需要增加一个 排他网关节点,通过设定一个全局变量,在审批任务执行完成时,通过内置方设置变量值,我们自定义,值为true则审批通过,流程结束,为false那么就驳回,流程节点回到前一个任务,设置变量记录会在 act_ru_variable表中记录
10.一个流程,调用另外一个子流程
这里直接展开我们业务的遗留问题单电子流的功能设计开发
controller层
package com.xxx.service;
import com.xxx.delegate.ProcessKnownIssueDelegate;
import org.springframework.web.bind.annotation.*;
import com.xxx.model.KnowIssueCreateParam;
import org.springframework.validation.annotation.Validated;
import com.xxx.model.UpdateProgressParam;
import com.xxx.tools.commonlib.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import com.xxx.model.KnownIssueInfo;
import com.xxx.model.ResponseVo;
@RestController
@RequestMapping(value = "/process/knownIssue", produces = {"application/json;charset=UTF-8"})
@Validated
public class ProcessKnownIssueController {
@Autowired(required=false)
private ProcessKnownIssueDelegate delegate;
@RequestMapping(
value = "/closeKnownIssue",
produces = { "application/json" },
method = RequestMethod.POST)
public ResponseVo closeKnownIssue(@RequestBody KnownIssueInfo knownIssueInfo)
throws ServiceException {
return delegate.closeKnownIssue(knownIssueInfo);
}
@RequestMapping(
value = "/createKnownIssue",
produces = { "application/json" },
method = RequestMethod.POST)
public ResponseVo createKnownIssue(@RequestBody KnowIssueCreateParam knowIssueCreateParam)
throws ServiceException {
return delegate.createKnownIssue(knowIssueCreateParam);
}
@RequestMapping(
value = "/getKnownIssueDesc",
produces = { "application/json" },
method = RequestMethod.GET)
public ResponseVo getKnownIssueDesc( @RequestParam(value = "knownIssueId", required = true) String knownIssueId)
throws ServiceException {
return delegate.getKnownIssueDesc(knownIssueId);
}
@RequestMapping(
value = "/getKnownIssueDetails",
produces = { "application/json" },
method = RequestMethod.GET)
public ResponseVo getKnownIssueDetails( @RequestParam(value = "knownIssueId", required = true) String knownIssueId)
throws ServiceException {
return delegate.getKnownIssueDetails(knownIssueId);
}
@RequestMapping(
value = "/getKnownIssueList",
produces = { "application/json" },
method = RequestMethod.GET)
public ResponseVo getKnownIssueList( @RequestParam(value = "pageNo", required = true) Integer pageNo,
@RequestParam(value = "pageSize", required = true) Integer pageSize)
throws ServiceException {
return delegate.getKnownIssueList(pageNo
, pageSize);
}
@RequestMapping(
value = "/getKnownIssueMoreDetails",
produces = { "application/json" },
method = RequestMethod.GET)
public ResponseVo getKnownIssueMoreDetails( @RequestParam(value = "knownIssueId", required = true) String knownIssueId)
throws ServiceException {
return delegate.getKnownIssueMoreDetails(knownIssueId);
}
@RequestMapping(
value = "/getKnownIssueProgress",
produces = { "application/json" },
method = RequestMethod.GET)
public ResponseVo getKnownIssueProgress( @RequestParam(value = "knownIssueId", required = true) String knownIssueId)
throws ServiceException {
return delegate.getKnownIssueProgress(knownIssueId);
}
@RequestMapping(
value = "/updateProgress",
produces = { "application/json" },
method = RequestMethod.POST)
public ResponseVo updateProgress(@RequestBody UpdateProgressParam updateProgressParam)
throws ServiceException {
return delegate.updateProgress(updateProgressParam);
}
}
service层 接口
package com.xxx.delegate;
import com.xxx.model.KnowIssueCreateParam;
import com.xxx.model.KnownIssueInfo;
import com.xxx.model.UpdateProgressParam;
import com.xxx.model.ResponseVo;
import com.xxx.tools.commonlib.exception.ServiceException;
public interface ProcessKnownIssueDelegate {
ResponseVo closeKnownIssue(KnownIssueInfo knownIssueInfo)
throws ServiceException;
ResponseVo createKnownIssue(KnowIssueCreateParam knowIssueCreateParam)
throws ServiceException;
ResponseVo getKnownIssueDesc(String knownIssueId)
throws ServiceException;
ResponseVo getKnownIssueDetails(String knownIssueId)
throws ServiceException;
ResponseVo getKnownIssueList(Integer pageNo,
Integer pageSize)
throws ServiceException;
ResponseVo getKnownIssueMoreDetails(String knownIssueId)
throws ServiceException;
ResponseVo getKnownIssueProgress(String knownIssueId)
throws ServiceException;
ResponseVo updateProgress(UpdateProgressParam updateProgressParam)
throws ServiceException;
}
service层 实现类
这里的业务层比较抽象,下层还有定义了更具象的服务接口,注入该实现类进行调用
package com.xxx.impl.process;
import com.xxx.delegate.ProcessKnownIssueDelegate;
import com.xxx.model.KnowIssueCreateParam;
import com.xxx.model.KnownIssueInfo;
import com.xxx.model.ResponseVo;
import com.xxx.model.UpdateProgressParam;
import com.xxx.energytools.domain.entity.VerifyInfo;
import com.xxx.energytools.service.process.ProcessKnownIssueService;
import com.xxx.energytools.utils.ResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Slf4j
@Service
public class ProcessKnownIssueDelegateImpl implements ProcessKnownIssueDelegate {
@Resource
ProcessKnownIssueService processKnownIssueService;
/**
* closeKnownIssue
*
* @param knownIssueInfo knownIssueInfo
* @return ResponseVo
*/
@Override
public ResponseVo closeKnownIssue(KnownIssueInfo knownIssueInfo) {
boolean closed = processKnownIssueService.closeKnownIssue(knownIssueInfo.getKnownIssueId());
if (closed) {
return ResponseUtils.successResponse("问题关闭成功", "问题关闭成功");
}
return ResponseUtils.errorResponse(null, "问题关闭失败");
}
/**
* createKnownIssue
*
* @param knowIssueCreateParam knowIssueCreateParam
* @return ResponseVo
*/
@Override
public ResponseVo createKnownIssue(KnowIssueCreateParam knowIssueCreateParam) {
VerifyInfo info = verifyKnowIssueCreateParam(knowIssueCreateParam);
if (!info.isPass()) {
return ResponseUtils.errorResponse(info.getMessage(), "创建字段错误");
}
VerifyInfo knownIssue = processKnownIssueService.createKnownIssue(knowIssueCreateParam);
if (knownIssue.isPass()) {
return ResponseUtils.successResponse(knownIssue.getMessage(), "创建遗留问题成功");
}
return ResponseUtils.errorResponse(knownIssue.getMessage(), "创建遗留问题失败");
}
/**
* verifyKnowIssueCreateParam
*
* @param knowIssueCreateParam knowIssueCreateParam
* @return VerifyInfo
*/
private VerifyInfo verifyKnowIssueCreateParam(KnowIssueCreateParam knowIssueCreateParam) {
VerifyInfo result = new VerifyInfo();
if (knowIssueCreateParam == null) {
return result.notPassed("创建字段为空");
}
if (StringUtils.isEmpty(knowIssueCreateParam.getIssueDesc())) {
return result.notPassed("问题描述为空");
}
List<String> handlers = knowIssueCreateParam.getHandlers();
if (handlers == null || handlers.isEmpty()) {
result.notPassed("处理人为空");
}
return result;
}
/**
* getKnownIssueDesc
*
* @param knownIssueId knownIssueId
* @return ResponseVo
*/
@Override
public ResponseVo getKnownIssueDesc(String knownIssueId) {
return ResponseUtils.successResponse(processKnownIssueService.getKnownIssueDesc(knownIssueId), "获取信息成功");
}
/**
* getKnownIssueDetails
*
* @param knownIssueId knownIssueId
* @return ResponseVo
*/
@Override
public ResponseVo getKnownIssueDetails(String knownIssueId) {
return ResponseUtils.successResponse(processKnownIssueService.getKnownIssueDetails(knownIssueId), "获取信息成功");
}
/**
* getKnownIssueList
*
* @param pageNo pageNo
* @param pageSize pageSize
* @return ResponseVo
*/
@Override
public ResponseVo getKnownIssueList(Integer pageNo, Integer pageSize) {
return processKnownIssueService.getKnownIssueList(pageNo, pageSize);
}
/**
* getKnownIssueMoreDetails
*
* @param knownIssueId knownIssueId
* @return ResponseVo
*/
@Override
public ResponseVo getKnownIssueMoreDetails(String knownIssueId) {
return ResponseUtils.successResponse(processKnownIssueService.getKnownIssueDetails(knownIssueId), "获取信息成功");
}
/**
* getKnownIssueProgress
*
* @param knownIssueId knownIssueId
* @return ResponseVo
*/
@Override
public ResponseVo getKnownIssueProgress(String knownIssueId) {
return ResponseUtils.successResponse(processKnownIssueService.getProgressDetailsByKnowIssueId(knownIssueId), "获取信息成功");
}
/**
* updateProgress
*
* @param updateProgressParam updateProgressParam
* @return ResponseVo
*/
@Override
public ResponseVo updateProgress(UpdateProgressParam updateProgressParam) {
String content = updateProgressParam.getContent();
if (StringUtils.isBlank(content)) {
return ResponseUtils.errorResponse(null, "更新进展失败: 进展不能为空");
}
VerifyInfo verifyInfo = processKnownIssueService.updateProcess(updateProgressParam);
if (verifyInfo.isPass()) {
return ResponseUtils.successResponse("更新进展成功", "更新进展成功");
}
return ResponseUtils.errorResponse(null, verifyInfo.getMessage());
}
}
service层 接口
package com.xxx.service.process;
import com.xxx.model.KnowIssueCreateParam;
import com.xxx.model.ResponseVo;
import com.xxx.model.UpdateProgressParam;
import com.xxx.domain.entity.VerifyInfo;
import com.xxx.domain.vo.process.KnownIssueDetailsVo;
import com.xxx.domain.vo.ProgressDetailsVo;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import java.util.List;
public interface ProcessKnownIssueService {
/**
* getKnowIssueProcessDef
*
* @return ProcessDefinition
*/
ProcessDefinition getKnowIssueProcessDef();
/**
* createKnownIssue
*
* @param createParam createParam
* @return VerifyInfo
*/
VerifyInfo createKnownIssue(KnowIssueCreateParam createParam);
/**
* getKnownIssueTaskByProcessInstanceId
*
* @param processInstanceId processInstanceId
* @return Task
*/
Task getKnownIssueTaskByProcessInstanceId(String processInstanceId);
/**
* closeKnownIssue
*
* @param knownIssueId knownIssueId
* @return boolean
*/
boolean closeKnownIssue(String knownIssueId);
/**
* getKnownIssueDetails
*
* @param taskId taskId
* @return KnownIssueDetailsVo
*/
KnownIssueDetailsVo getKnownIssueDetails(String taskId);
/**
* getKnownIssueDesc
*
* @param taskId taskId
* @return String
*/
String getKnownIssueDesc(String taskId);
/**
* getProgressDetailsByKnowIssueId
*
* @param taskId taskId
* @return List<ProgressDetailsVo>
*/
List<ProgressDetailsVo> getProgressDetailsByKnowIssueId(String taskId);
/**
* updateProcess
*
* @param updateProgressParam updateProgressParam
* @return VerifyInfo
*/
VerifyInfo updateProcess(UpdateProgressParam updateProgressParam);
/**
* getKnownIssueList
*
* @param pageNo pageNo
* @param pageSize pageSize
* @return ResponseVo
*/
ResponseVo getKnownIssueList(Integer pageNo, Integer pageSize);
}
service层 实现类
package com.xxx.service.impl.process;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxx.model.KnowIssueCreateParam;
import com.xxx.model.ResponseVo;
import com.xxx.model.UpdateProgressParam;
import com.xxx.adapter.UserAdapter;
import com.xxx.domain.dto.process.ProcessVarHistoryRecordDto;
import com.xxx.domain.entity.VerifyInfo;
import com.xxx.domain.entity.user.UserModel;
import com.xxx.domain.model.DpProcessMessage;
import com.xxx.domain.model.KnownIssueDetailsTab;
import com.xxx.domain.vo.ProgressDetailsVo;
import com.xxx.domain.vo.UserVo;
import com.xxx.domain.vo.process.KnownIssueDetailsVo;
import com.xxx.domain.vo.process.KnownIssueInfoVo;
import com.xxx.enums.State;
import com.xxx.service.UserService;
import com.xxx.service.dao.iservice.process.KnownIssueDetailsService;
import com.xxx.service.dao.mapper.process.ProcessVarHistoryMapper;
import com.xxx.service.process.ProcessKnownIssueService;
import com.xxx.service.process.ProcessMessage;
import com.xxx.utils.ResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.xxx.constants.process.ProcessConstants.CANCELED_STATE;
import static com.xxx.constants.process.ProcessConstants.CLOSE_STATE;
import static com.xxx.constants.process.ProcessConstants.KNOWN_ISSUE_PROCESS_DEF_KEY;
import static com.xxx.constants.process.ProcessConstants.KNOWN_ISSUE_PROGRESS_CONTENT;
import static com.xxx.constants.process.ProcessConstants.KNOWN_ISSUE_PROGRESS_UPDATER;
import static com.xxx.constants.process.ProcessConstants.KNOWN_ISSUE_PROGRESS_VAR;
import static com.xxx.constants.process.ProcessConstants.KNOWN_ISSUE_TASK_DEF_KEY;
import static com.xxx.constants.process.ProcessConstants.KNOWN_ISSUE_TASK_STATE_VAR;
import static com.xxx.constants.process.ProcessConstants.OPEN_STATE;
@Service
@Slf4j
public class ProcessKnownIssueServiceImpl extends ProcessMessage implements ProcessKnownIssueService {
@Resource
RepositoryService repositoryService;
@Resource
RuntimeService runtimeService;
@Resource
TaskService taskService;
@Resource
KnownIssueDetailsService knownIssueDetailsService;
@Resource
ProcessVarHistoryMapper processVarHistoryMapper;
@Resource
UserService userService;
@Resource
UserAdapter userAdapter;
/**
* getKnowIssueProcessDef
* 获取流程定义 key值是在BPMN2.0流程图设计过程中 给变量 process identifier赋值的名称 需要与图中的名称一致才能找到该流程图
* @return ProcessDefinition
*/
@Override
public ProcessDefinition getKnowIssueProcessDef() {
return repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(KNOWN_ISSUE_PROCESS_DEF_KEY)
.latestVersion()
.singleResult();
}
/**
* createKnownIssue
* 创建遗留问题电子流
* @param createParam createParam
* @return VerifyInfo
*/
@Override
public VerifyInfo createKnownIssue(KnowIssueCreateParam createParam) {
VerifyInfo result = new VerifyInfo();
ProcessDefinition knowIssueProcessDef = getKnowIssueProcessDef();
if (knowIssueProcessDef == null) {
return result.notPassed("system error: 未找到 遗留问题 流程定义");
}
//开启流程的一个实例对象,对应的key还是流程图的process identifier值 流程key
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(KNOWN_ISSUE_PROCESS_DEF_KEY);
//获取流程id
String processInstanceId = processInstance.getId();
//通过流程id 获取对应的一个子任务task
Task task = getKnownIssueTaskByProcessInstanceId(processInstanceId);
if (task == null) {
return result.notPassed("system error: 未找到 遗留问题 实例任务");
}
//这里是创建业务的遗留问题单电子流表单,包括了业务的一些信息,以及对应的任务id,流程id 才能去关联对应的流程信息
VerifyInfo createInfo = knownIssueDetailsService.createKnownIssue(task.getId(), task.getProcessInstanceId(),
task.getCreateTime(), createParam);
if (!createInfo.isPass()) {
//创建不成功的话 就设置子任务id,对应的一个变量值 knownIssueState ,赋值CANCELED 并将任务提交complete 由于这个电子流比较简单只有一个处理任务 提交后,整个流程就结束了 这里赋值变量会插入到act_ru_variable表中的 TEXT_字段
log.error("create known issue failed");
taskService.setVariable(task.getId(), KNOWN_ISSUE_TASK_STATE_VAR, CANCELED_STATE);
taskService.complete(task.getId());
return result.notPassed(createInfo.getMessage());
}
//创建成功,则设置状态变量knownIssueState 赋值 OPEN
taskService.setVariable(task.getId(), KNOWN_ISSUE_TASK_STATE_VAR, OPEN_STATE);
//这里是创建一个业务流程电子流表,目的是承载一个简化通用的电子流清单,可能会存在多种业务电子流,用户会有多种业务类型电子流,统一展示在一个表单中,有一个表承载多种业务类型电子流
DpProcessMessage message = new DpProcessMessage();
message.setProcessType("遗留问题清单");
message.setStatus("问题处理中");
message.setMessage(createParam.getIssueDesc());
message.setProcessCode(createInfo.getMessage());
//这里是获取用户信息 电子流可能涉及多个处理人 list封装
List<UserModel> users = userAdapter.getUserInfo(createParam.getHandlers());
StringBuffer userStr = new StringBuffer();
//多个用户进行拼接在一个字符串中,张三 01 是一个用户信息 然后换行放下一个用户信息
users.forEach(user -> userStr.append(user.getNameCn()).append(String.format(" %s\n", user.getId())));
message.setCreateUser(userStr.toString());
message.setDealUser(userStr.toString());
message.setProcessUrl(String.format("/leftIssueDetail?knownIssueId=%s", message.getProcessCode()));
message.setCreateTime(LocalDateTime.now());
sendMessage(message);
return result.pass(createInfo.getMessage());
}
/**
* getKnownIssueTaskByProcessInstanceId
* 获取流程的指定子任务task
* @param processInstanceId processInstanceId
* @return Task
*/
@Override
public Task getKnownIssueTaskByProcessInstanceId(String processInstanceId) {
return taskService.createTaskQuery()
.active()
.processInstanceId(processInstanceId)
.taskDefinitionKey(KNOWN_ISSUE_TASK_DEF_KEY)
.singleResult();
}
/**
* closeKnownIssue
* 关闭电子流
* @param knownIssueId knownIssueId
* @return boolean
*/
@Override
public boolean closeKnownIssue(String knownIssueId) {
//获取指定单号的遗留问题电子流
KnownIssueDetailsTab detailsTab = getDetailTabByKnowIssueId(knownIssueId);
if (detailsTab == null) {
return false;
}
// SR为生产预警单,定时任务自动关闭,不走当前用户判断逻辑
if (!"SR".equals(knownIssueId.substring(0, 2)) && !detailsTab.getHandler()
.contains(userService.getUser().getAccount())) {
return false;
}
Task task = getKnownIssueTaskByProcessInstanceId(detailsTab.getProcessInstanceId());
if (task == null) {
return false;
}
//存在对应电子流,将其子任务 状态变量赋值 CLOSE 并提交完成 流程结束
taskService.setVariable(task.getId(), KNOWN_ISSUE_TASK_STATE_VAR, CLOSE_STATE);
taskService.complete(task.getId());
//删除通用信息表记录,这样用户前台就没有显示问题清单了
deleteMessage(knownIssueId);
return true;
}
/**
* getKnownIssueDetails
* 获取问题电子流的明细
* @param knowIssueId knowIssueId
* @return KnownIssueDetailsVo
*/
@Override
public KnownIssueDetailsVo getKnownIssueDetails(String knowIssueId) {
KnownIssueDetailsTab issueDetailsTab = getDetailTabByKnowIssueId(knowIssueId);
if (!issueDetailsTab.getHandler().contains(userService.getUser().getAccount())) {
return new KnownIssueDetailsVo();
}
return parse2KnownIssueDetailsVo(issueDetailsTab);
}
/**
* parse2KnownIssueDetailsVo
*
* @param detailsTab detailsTab
* @return KnownIssueDetailsVo
*/
private KnownIssueDetailsVo parse2KnownIssueDetailsVo(KnownIssueDetailsTab detailsTab) {
KnownIssueDetailsVo result = new KnownIssueDetailsVo();
if (detailsTab == null) {
return result;
}
result.setKnownIssueId(detailsTab.getId());
result.setLabel(detailsTab.getLabel());
result.setPduName(detailsTab.getPduName());
result.setPlanFinishedDate(detailsTab.getPlanFinishedDate());
//这里是获取是流程对应的一个 状态最新情况 是打开 还是关闭
ProcessVarHistoryRecordDto stateVar = processVarHistoryMapper.findLatestVarByProcInsId(
detailsTab.getProcessInstanceId(), KNOWN_ISSUE_TASK_STATE_VAR);
if (stateVar != null && !StringUtils.isEmpty(stateVar.getVarContent())) {
//这里状态值的设置 由于后台变量记录的是英文 OPEN , 前台需要展示中文,所以我们用枚举类 State 对每个状态进行转换
result.setIssueStatus(State.valueOf(stateVar.getVarContent()).getNameCn());
}
result.setCurrentHandlers(getUserInfo(detailsTab));
return result;
}
/**
* getKnownIssueDesc
* 获取问题的描述信息
* @param knowIssueId knowIssueId
* @return String
*/
@Override
public String getKnownIssueDesc(String knowIssueId) {
KnownIssueDetailsTab detailsTab = getDetailTabByKnowIssueId(knowIssueId);
if (detailsTab == null) {
return null;
}
if (!detailsTab.getHandler().contains(userService.getUser().getAccount())) {
return null;
}
return detailsTab.getIssueDesc();
}
/**
* getProgressDetailsByKnowIssueId
* 获取遗留问题单的进展细节
* @param knowIssueId knowIssueId
* @return List<ProgressDetailsVo>
*/
@Override
public List<ProgressDetailsVo> getProgressDetailsByKnowIssueId(String knowIssueId) {
KnownIssueDetailsTab detailsTab = getDetailTabByKnowIssueId(knowIssueId);
if (detailsTab == null) {
return new ArrayList<>();
}
if (!detailsTab.getHandler().contains(userService.getUser().getAccount())) {
return new ArrayList<>();
}
String taskId = detailsTab.getTaskId();
//通过任务id 以及设置变量 PROGRESS_DETAIL问题进展,查询表中的历史提交进展记录 多次提交就有多个记录
List<ProcessVarHistoryRecordDto> progressRecords = processVarHistoryMapper.findVarHistoryByTaskId(taskId,
KNOWN_ISSUE_PROGRESS_VAR);
return progressRecords.stream().map(this::parseHisDetail).collect(Collectors.toList());
}
/**
* parseHisDetail
* 解析历史进展细节
* @param one one
* @return ProgressDetailsVo
*/
private ProgressDetailsVo parseHisDetail(ProcessVarHistoryRecordDto one) {
ProgressDetailsVo result = new ProgressDetailsVo();
result.setUpdateDate(one.getOperateDate());
//这里的TEXT_值,前台返回的是 包括 更新人,更新内容两个信息 我们转换成json字符串保存{"UPDATER":"用户账号","CONTENT":"<p>进展内容</p>"}
JSONObject varCont = JSONObject.parseObject(one.getVarContent());
//解析JSON对象 获取 UPDATER 和 CONTENT 分别赋值
result.setUser(userAdapter.getUserInfo(varCont.getString(KNOWN_ISSUE_PROGRESS_UPDATER)));
result.setContent(varCont.getString(KNOWN_ISSUE_PROGRESS_CONTENT));
return result;
}
/**
* updateProcess
* 更新遗留问题进展
* @param updateProgressParam updateProgressParam
* @return VerifyInfo
*/
@Override
public VerifyInfo updateProcess(UpdateProgressParam updateProgressParam) {
VerifyInfo result = new VerifyInfo();
Map<String, Object> progressMap = new HashMap<>();
UserVo user = userService.getUser();
if (user == null) {
return result.notPassed("未获取到用户信息");
}
//传参有更新的问题单号,查询该单号的问题记录
KnownIssueDetailsTab tab = getDetailTabByKnowIssueId(updateProgressParam.getKnownIssueId());
if (!tab.getHandler().contains(userService.getUser().getAccount())) {
return result.notPassed("您无权限修改此流程");
}
//获取流程id的流程当前最新状态
State state = getStateByProcInsId(tab.getProcessInstanceId());
if (!State.OPEN.equals(state)) {
return result.notPassed("问题已关闭,无法更新进展");
}
//信息类map插入 更新人 更新内容
progressMap.put(KNOWN_ISSUE_PROGRESS_UPDATER, user.getAccount());
progressMap.put(KNOWN_ISSUE_PROGRESS_CONTENT, updateProgressParam.getContent());
//给对应流程的这个子任务设置任务局部变量 流程进展 赋值为信息类
taskService.setVariableLocal(tab.getTaskId(), KNOWN_ISSUE_PROGRESS_VAR, progressMap);
return result.pass("更新进展成功");
}
/**
* getStateByProcInsId
*
* @param processInstanceId processInstanceId
* @return State
*/
private State getStateByProcInsId(String processInstanceId) {
ProcessVarHistoryRecordDto stateDto = processVarHistoryMapper.findLatestVarByProcInsId(processInstanceId,
KNOWN_ISSUE_TASK_STATE_VAR);
if (stateDto == null) {
return null;
}
return State.valueOf(stateDto.getVarContent());
}
/**
* getKnownIssueList
* 获取问题清单
* @param pageNo pageNo
* @param pageSize pageSize
* @return ResponseVo
*/
@Override
public ResponseVo getKnownIssueList(Integer pageNo, Integer pageSize) {
UserVo user = userService.getUser();
if (user == null) {
return ResponseUtils.unAuthResponse(new ArrayList<>(), "请登录系统");
}
List<KnownIssueDetailsTab> list = knownIssueDetailsService.list(
new LambdaQueryWrapper<KnownIssueDetailsTab>().like(KnownIssueDetailsTab::getHandler,
"%" + user.getAccount() + "%"));
List<String> taskIds = list.stream()
.map(KnownIssueDetailsTab::getTaskId)
.distinct()
.collect(Collectors.toList());
List<String> procInsIds = list.stream()
.map(KnownIssueDetailsTab::getProcessInstanceId)
.distinct()
.collect(Collectors.toList());
Map<String, ProcessVarHistoryRecordDto> progressMap = getLatestProgressMap(taskIds);
Map<String, ProcessVarHistoryRecordDto> stateMap = getStateMap(procInsIds);
List<KnownIssueInfoVo> infos = list.stream()
.filter(item -> item.getHandler().contains(user.getAccount()))
.map(knownIssueDetailsTab -> parseDetailTab(knownIssueDetailsTab, progressMap, stateMap))
.collect(Collectors.toList());
List<KnownIssueInfoVo> result = infos.stream()
.sorted(Comparator.comparing(KnownIssueInfoVo::getKnownIssueId).reversed())
.skip((long) (pageNo - 1) * pageSize)
.limit(pageSize)
.collect(Collectors.toList());
return ResponseUtils.successPageResponse(result, infos.size());
}
/**
* getStateMap
*
* @param procInsIds procInsIds
* @return Map<String,ProcessVarHistoryRecordDto>
*/
private Map<String, ProcessVarHistoryRecordDto> getStateMap(List<String> procInsIds) {
List<ProcessVarHistoryRecordDto> stateVars = processVarHistoryMapper.findLatestVarByProcInsIds(procInsIds,
KNOWN_ISSUE_TASK_STATE_VAR);
return stateVars.stream().collect(Collectors.toMap(ProcessVarHistoryRecordDto::getProcInsId, item -> item));
}
/**
* getLatestProgressMap
*
* @param taskIds taskIds
* @return Map<String,ProcessVarHistoryRecordDto>
*/
private Map<String, ProcessVarHistoryRecordDto> getLatestProgressMap(List<String> taskIds) {
List<ProcessVarHistoryRecordDto> progressVars = processVarHistoryMapper.findLatestVarByTaskIds(taskIds,
KNOWN_ISSUE_PROGRESS_VAR);
return progressVars.stream().collect(Collectors.toMap(ProcessVarHistoryRecordDto::getTaskId, item -> item));
}
/**
* parseDetailTab
*
* @param knownIssueDetailsTab knownIssueDetailsTab
* @param progressMap progressMap
* @param stateMap stateMap
* @return KnownIssueInfoVo
*/
private KnownIssueInfoVo parseDetailTab(KnownIssueDetailsTab knownIssueDetailsTab,
Map<String, ProcessVarHistoryRecordDto> progressMap, Map<String, ProcessVarHistoryRecordDto> stateMap) {
KnownIssueInfoVo result = new KnownIssueInfoVo();
String knownIssueId = knownIssueDetailsTab.getId();
String taskId = knownIssueDetailsTab.getTaskId();
String processInstanceId = knownIssueDetailsTab.getProcessInstanceId();
result.setKnownIssueId(knownIssueId);
result.setIssueDesc(knownIssueDetailsTab.getIssueDesc());
result.setLabel(knownIssueDetailsTab.getLabel());
result.setPduName(knownIssueDetailsTab.getPduName());
result.setPlanFinishedDate(knownIssueDetailsTab.getPlanFinishedDate());
result.setCurrentHandlers(
getUserInfo(knownIssueDetailsTab).stream().map(UserModel::getNameCn).collect(Collectors.joining(",")));
if (progressMap.containsKey(taskId)) {
ProcessVarHistoryRecordDto processVarHistoryRecordDto = progressMap.get(taskId);
String varContent = processVarHistoryRecordDto.getVarContent();
JSONObject jsonObject = JSONObject.parseObject(varContent);
result.setLatestProgress(jsonObject.getString(KNOWN_ISSUE_PROGRESS_CONTENT));
UserModel userInfo = userAdapter.getUserInfo(jsonObject.getString(KNOWN_ISSUE_PROGRESS_UPDATER));
if (userInfo != null) {
result.setLatestUpdater(userInfo.getNameCn());
}
}
if (stateMap.containsKey(processInstanceId)) {
ProcessVarHistoryRecordDto processVarHistoryRecordDto = stateMap.get(processInstanceId);
State state = State.valueOf(processVarHistoryRecordDto.getVarContent());
result.setIssueStatus(state.getNameCn());
if (State.CLOSE.equals(state)) {
result.setCloseDate(processVarHistoryRecordDto.getOperateDate());
}
}
return result;
}
/**
* getUserInfo
*
* @param knownIssueDetailsTab knownIssueDetailsTab
* @return List<UserModel>
*/
private List<UserModel> getUserInfo(KnownIssueDetailsTab knownIssueDetailsTab) {
return userAdapter.getUserInfo(JSONArray.parseArray(knownIssueDetailsTab.getHandler(), String.class));
}
/**
* getDetailTabByKnowIssueId
*
* @param knowIssueId knowIssueId
* @return KnownIssueDetailsTab
*/
private KnownIssueDetailsTab getDetailTabByKnowIssueId(String knowIssueId) {
return knownIssueDetailsService.getOne(
new LambdaQueryWrapper<KnownIssueDetailsTab>().eq(KnownIssueDetailsTab::getId, knowIssueId));
}
}
dao层 接口 创建遗留问题单
package com..service.dao.iservice.process;
import com.model.KnowIssueCreateParam;
import com.domain.entity.VerifyInfo;
import com.domain.model.KnownIssueDetailsTab;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Date;
public interface KnownIssueDetailsService extends IService<KnownIssueDetailsTab> {
/**
* createKnownIssue
*
* @param taskId taskId
* @param procInsId procInsId
* @param createTime createTime
* @param param param
* @return VerifyInfo
*/
VerifyInfo createKnownIssue(String taskId, String procInsId, Date createTime, KnowIssueCreateParam param);
}
dao层 实现 创建遗留问题单
package com..service.impl.dao.iservice.process;
import com.model.KnowIssueCreateParam;
import com.domain.entity.VerifyInfo;
import com.domain.model.KnownIssueDetailsTab;
import com.service.dao.iservice.process.KnownIssueDetailsService;
import com.service.dao.mapper.process.KnownIssueDetailsMapper;
import com.utils.DateUtils;
import com.it.auth.util.StringUtils;
import com.tools.commonlib.exception.ServiceException;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.locks.ReentrantLock;
@Service
@Slf4j
public class KnownIssueDetailsServiceImpl extends ServiceImpl<KnownIssueDetailsMapper, KnownIssueDetailsTab>
implements KnownIssueDetailsService {
//可重入锁 目的就是如果存在大量的问题单在同一时刻创建,那么就会导致 问题单号的重复,因为单号是根据表中当前的数量累加,可能存在第一次请求还没结束 第二次的也接着请求 导致单号最大数值一样了 加锁目的就是为了请求是一次次的完成
private static final ReentrantLock LOCK = new ReentrantLock();
/**
* createKnownIssue
*
* @param taskId taskId
* @param procInsId procInsId
* @param createTime createTime
* @param param param
* @return VerifyInfo
*/
@Override
public VerifyInfo createKnownIssue(String taskId, String procInsId, Date createTime, KnowIssueCreateParam param) {
VerifyInfo result = new VerifyInfo();
KnownIssueDetailsTab saveOne = new KnownIssueDetailsTab();
saveOne.setTaskId(taskId);
saveOne.setProcessInstanceId(procInsId);
saveOne.setIssueDesc(param.getIssueDesc());
//存储处理人 转换成json格式数组
saveOne.setHandler(JSONArray.toJSONString(param.getHandlers()));
saveOne.setLabel(param.getLabel());
saveOne.setPduName(param.getPduName());
saveOne.setCreatedDate(createTime);
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
saveOne.setPlanFinishedDate(dateFormat.parse(param.getPlanFinishedDate()));
} catch (ParseException e) {
log.error("date format error");
return result.notPassed("param error: date format error");
}
try {
LOCK.lock();
String id = "";
if (StringUtils.isEmpty(param.getProblemNo())) {
id = String.format(Locale.ROOT, "KI%s%s", DateUtils.getTimeMillisString(new Date()),
formatNum2Five(baseMapper.getTodayKnownIssueNum() + 1));
saveOne.setId(id);
} else {
id = param.getProblemNo();
}
saveOne.setId(id);
//调用mp的内置方法 插入数据
save(saveOne);
return result.pass(id);
} catch (ServiceException e) {
log.error("create problem failed");
return result.notPassed("system error: create KI id, save data error");
} finally {
LOCK.unlock();
}
}
/**
* formatNum2Five
*
* @param num num
* @return String
* @throws ServiceException ServiceException
*/
private String formatNum2Five(int num) throws ServiceException {
if (num > 99999 || num < 0) {
throw new ServiceException("num out of range");
}
String numStr = String.valueOf(num);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < (5 - numStr.length()); i++) {
builder.append("0");
}
return builder + numStr;
}
}
dao层 mapper接口
package com.service.dao.mapper.process;
import com.domain.model.KnownIssueDetailsTab;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface KnownIssueDetailsMapper extends BaseMapper<KnownIssueDetailsTab> {
/**
* getTodayKnownIssueNum
*
* @return int
*/
@Select("select count(*) from dp_process_known_issue_details where TO_DAYS(created_date) = TO_DAYS(NOW()) ")
int getTodayKnownIssueNum();
}
dao层 mapper接口 获取流程历史记录的变量信息
- 这里我们设定了两种变量 一个是流程状态knownIssueState, 一个是进展细节 PROGRESS_DETAIL ,都是保存在表中的act_hi_detail,这里是历史记录表,会记录这个流程或者任务我们设定的变量的全部过程,比如状态 ,是从 OPEN开始的,闭环了则增加一条 CLOSE的内容,也就是状态变量 记录有2条,进展细节也是同理,一个子任务 提交多少次细节处理,我们就把内容都赋值给变量进行插入记录。对应就有相应条数记录
package com.service.dao.mapper.process;
import com.domain.dto.process.ProcessVarHistoryRecordDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface ProcessVarHistoryMapper {
/**
* 根据 任务id taskId 查询 流程 局部变量信息
*
* @param taskId taskId
* @param varName varName
* @return List<ProcessVarHistoryRecordDto>
*/
List<ProcessVarHistoryRecordDto> findVarHistoryByTaskId(@Param("taskId") String taskId,
@Param("varName") String varName);
/**
* 根据 流程实例id procInsId 查询 流程 变量信息
*
* @param procInsId procInsId
* @param varName varName
* @return List<ProcessVarHistoryRecordDto>
*/
List<ProcessVarHistoryRecordDto> findVarHistoryByProcInsId(@Param("procInsId") String procInsId,
@Param("varName") String varName);
/**
* 根据taskIds 批量获取 遗留问题的最新进展详情
*
* @param taskIds taskIds
* @param varName varName
* @return List<ProcessVarHistoryRecordDto>
*/
List<ProcessVarHistoryRecordDto> findLatestVarByTaskIds(@Param("taskIds") List<String> taskIds,
@Param("varName") String varName);
/**
* 根据procInsIds 批量获取 遗留问题的进展详情
*
* @param procInsIds procInsIds
* @param varName varName
* @return List<ProcessVarHistoryRecordDto>
*/
List<ProcessVarHistoryRecordDto> findLatestVarByProcInsIds(@Param("procInsIds") List<String> procInsIds,
@Param("varName") String varName);
/**
* 根据taskId 获取单个 局部变量 最新的详情
*
* @param taskId taskId
* @param varName varName
* @return ProcessVarHistoryRecordDto
*/
ProcessVarHistoryRecordDto findLatestVarByTaskId(@Param("taskId") String taskId, @Param("varName") String varName);
/**
* 根据procInsId 获取单个 实例变量 最新的详情
*
* @param procInsId procInsId
* @param varName varName
* @return ProcessVarHistoryRecordDto
*/
ProcessVarHistoryRecordDto findLatestVarByProcInsId(@Param("procInsId") String procInsId,
@Param("varName") String varName);
}
dao层 xml映射 获取流程历史记录的变量信息
<?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.service.dao.mapper.process.ProcessVarHistoryMapper">
<select id="findVarHistoryByTaskId" resultType="com.domain.dto.process.ProcessVarHistoryRecordDto">
select
TASK_ID_ as taskId,
PROC_INST_ID_ as procInsId,
NAME_ as varName,
VAR_TYPE_ as varType,
TIME_ as operateDate,
TEXT_ as varContent
from act_hi_detail
where TASK_ID_ = #{taskId} and NAME_ =#{varName}
and TYPE_ = 'VariableUpdate'
order by TIME_ asc
</select>
<select id="findVarHistoryByProcInsId" resultType="com.domain.dto.process.ProcessVarHistoryRecordDto">
select
TASK_ID_ as taskId,
PROC_INST_ID_ as procInsId,
NAME_ as varName,
VAR_TYPE_ as varType,
TIME_ as operateDate,
TEXT_ as varContent
from act_hi_detail
where PROC_INST_ID_ = #{procInsId} and NAME_ =#{varName}
and TYPE_ = 'VariableUpdate'
order by TIME_ asc
</select>
<select id="findLatestVarByTaskIds" resultType="com.domain.dto.process.ProcessVarHistoryRecordDto">
select
a.TASK_ID_ as taskId,
a.PROC_INST_ID_ as procInsId,
a.NAME_ as varName,
a.VAR_TYPE_ as varType,
a.TIME_ as operateDate,
a.TEXT_ as varContent
from (
select *,
row_number() over(partition by TASK_ID_ order by TIME_ desc) as rank_number
from act_hi_detail
<where>
<if test="taskIds != null and taskIds.size > 0">
and TASK_ID_ in
<foreach collection="taskIds" item="taskId" open="(" separator="," close=")">
#{taskId}
</foreach>
</if>
and NAME_ =#{varName}
and TYPE_ = 'VariableUpdate'
</where>
) a
where rank_number = 1
</select>
<select id="findLatestVarByProcInsIds" resultType="com.domain.dto.process.ProcessVarHistoryRecordDto">
select
a.TASK_ID_ as taskId,
a.PROC_INST_ID_ as procInsId,
a.NAME_ as varName,
a.VAR_TYPE_ as varType,
a.TIME_ as operateDate,
a.TEXT_ as varContent
from (
select *,
row_number() over(partition by PROC_INST_ID_ order by TIME_ desc) as rank_number
from act_hi_detail
<where>
<if test="procInsIds != null and procInsIds.size > 0">
and PROC_INST_ID_ in
<foreach collection="procInsIds" item="procInstId" open="(" separator="," close=")">
#{procInstId}
</foreach>
</if>
and NAME_ =#{varName}
and TYPE_ = 'VariableUpdate'
</where>
) a
where rank_number = 1
</select>
<select id="findLatestVarByTaskId" resultType="com.domain.dto.process.ProcessVarHistoryRecordDto">
select
a.TASK_ID_ as taskId,
a.PROC_INST_ID_ as procInsId,
a.NAME_ as varName,
a.VAR_TYPE_ as varType,
a.TIME_ as operateDate,
a.TEXT_ as varContent
from (
select *,
row_number() over(partition by TASK_ID_ order by TIME_ desc) as rank_number
from act_hi_detail
<where>
and TASK_ID_ = #{taskId}
and NAME_ =#{varName}
and TYPE_ = 'VariableUpdate'
</where>
) a
where rank_number = 1
</select>
<select id="findLatestVarByProcInsId" resultType="com.domain.dto.process.ProcessVarHistoryRecordDto">
select
a.TASK_ID_ as taskId,
a.PROC_INST_ID_ as procInsId,
a.NAME_ as varName,
a.VAR_TYPE_ as varType,
a.TIME_ as operateDate,
a.TEXT_ as varContent
from (
select *,
row_number() over(partition by PROC_INST_ID_ order by TIME_ desc) as rank_number
from act_hi_detail
<where>
and PROC_INST_ID_ = #{procInsId}
and NAME_ =#{varName}
and TYPE_ = 'VariableUpdate'
</where>
) a
where rank_number = 1
</select>
</mapper>
通用信息设计接口
- 观察者模式,注入了一个 集合list 目的是后续能得到多个被观察者实现类的内容,之前我们有一篇文章 写导出数据与导出模板用一个接口完成的,就涉及到这个模式设计的运用,利用反射或者每个实现类名去区别不同类方法 【业务功能篇04】Springboot+mybatis-plus+POI模板表头下载以及数据查询下载_studyday1的博客-CSDN博客
controller层
直接调用mapper层内置的查询接口
package com.controller;
import com.domain.dto.process.ProcessContent;
import com.domain.model.DpProcessMessage;
import com.qualitybigdata.model.ResponseVo;
import com.service.UserService;
import com.service.dao.mapper.DpProcessMessageMapper;
import com.utils.ResponseUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.annotation.Resource;
/**
* 流程消息接口
*
*/
@RestController
@RequestMapping("/message")
@Slf4j
public class ProcessMessageController {
@Autowired
DpProcessMessageMapper processMessageMapper;
@Resource
UserService userService;
/**
* getMessage
*
* @param pageNo pageNo
* @param pageSize pageSize
* @param keyword keyword
* @return ResponseVo
*/
@PostMapping("/getMessage")
public ResponseVo getMessage(@RequestParam Long pageNo, @RequestParam Integer pageSize,
@RequestBody ProcessContent keyword) {
return queryMessage(pageNo, pageSize, keyword.getKeyword(),
wrapper -> wrapper.like(DpProcessMessage::getDealUser, userService.getUser().getAccount()));
}
/**
* getApplication
*
* @param pageNo pageNo
* @param pageSize pageSize
* @param keyword keyword
* @return ResponseVo
*/
@PostMapping("/getApplication")
public ResponseVo getApplication(@RequestParam Long pageNo, @RequestParam Integer pageSize,
@RequestBody ProcessContent keyword) {
return queryMessage(pageNo, pageSize, keyword.getKeyword(),
wrapper -> wrapper.like(DpProcessMessage::getCreateUser, userService.getUser().getAccount()));
}
/**
* getApplication
*
* @param keyword keyword
* @param processType processType
* @return ResponseVo
*/
@GetMapping("/getComponentCode")
public ResponseVo getApplication(@RequestParam String keyword, @RequestParam String processType) {
Page<DpProcessMessage> page = new Page<>(1, 5);
LambdaQueryWrapper<DpProcessMessage> wrapper = new LambdaQueryWrapper<>();
if (ObjectUtils.isNotEmpty(keyword)) {
wrapper.like(DpProcessMessage::getMessage, keyword);
}
if ("getMessage".equals(processType)) {
wrapper.like(DpProcessMessage::getDealUser, userService.getUser().getAccount());
} else {
wrapper.like(DpProcessMessage::getCreateUser, userService.getUser().getAccount());
}
wrapper.orderByDesc(DpProcessMessage::getProcessCode);
List<String> list = processMessageMapper.selectPage(page, wrapper)
.getRecords()
.stream()
.map(DpProcessMessage::getMessage)
.collect(Collectors.toList());
return ResponseUtils.successResponse(list, "");
}
/**
* getApplicationNum
*
* @return ResponseVo
*/
@GetMapping("/getApplicationNum")
public ResponseVo getApplicationNum() {
String Account = userService.getUser().getAccount();
return ResponseUtils.successResponse(new Long[] {
countMessage(wrapper -> wrapper.like(DpProcessMessage::getDealUser, Account)),
countMessage(wrapper -> wrapper.like(DpProcessMessage::getCreateUser, Account))
}, "");
}
/**
* countMessage
*
* @param consumer consumer
* @return Long
*/
private Long countMessage(Consumer<LambdaQueryChainWrapper<DpProcessMessage>> consumer) {
LambdaQueryChainWrapper<DpProcessMessage> wrapper = new LambdaQueryChainWrapper<>(processMessageMapper);
consumer.accept(wrapper);
return wrapper.count();
}
/**
* queryMessage
*
* @param pageNo pageNo
* @param pageSize pageSize
* @param keyWord keyWord
* @param consumer consumer
* @return ResponseVo
*/
private ResponseVo queryMessage(Long pageNo, Integer pageSize, String keyWord,
Consumer<LambdaQueryWrapper<DpProcessMessage>> consumer) {
Page<DpProcessMessage> page = new Page<>(pageNo, pageSize);
LambdaQueryWrapper<DpProcessMessage> wrapper = new LambdaQueryWrapper<>();
consumer.accept(wrapper);
if (ObjectUtils.isNotEmpty(keyWord)) {
wrapper.like(DpProcessMessage::getMessage, keyWord);
}
wrapper.orderByDesc(DpProcessMessage::getProcessCode);
return ResponseUtils.successPageResponse(processMessageMapper.selectPage(page, wrapper).getRecords(), page);
}
}
通用信息类
package com.service.process;
import com.domain.model.DpProcessMessage;
import com.observe.ProcessObserve;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import java.util.List;
public abstract class ProcessMessage {
@Value("${Url}")
private String Url;
@Autowired
List<ProcessObserve> observeList;
/**
* sendMessage
*
* @param message message
*/
protected void sendMessage(DpProcessMessage message) {
observeList.forEach(observe -> observe.saveMessage(message));
}
/**
* deleteMessage
*
* @param processCode processCode
*/
protected void deleteMessage(String processCode) {
observeList.forEach(observe -> observe.removeMessage(processCode));
}
}
观察者接口
package comobserve;
import com.domain.model.DpProcessMessage;
public interface ProcessObserve {
/**
* saveMessage
*
* @param message message
*/
void saveMessage(DpProcessMessage message);
/**
* removeMessage
*
* @param processCode processCode
*/
void removeMessage(String processCode);
}
观察者 实现类
package com.observe;
import com.service.dao.mapper.DpProcessMessageMapper;
import com.domain.model.DpProcessMessage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class ProcessMessageImpl implements ProcessObserve {
@Autowired
DpProcessMessageMapper processMessageMapper;
/**
* saveMessage
*
* @param message message
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void saveMessage(DpProcessMessage message) {
deleteByProcessCode(message.getProcessCode());
processMessageMapper.insert(message);
}
/**
* removeMessage
*
* @param processCode processCode
*/
@Override
public void removeMessage(String processCode) {
deleteByProcessCode(processCode);
}
/**
* deleteByProcessCode
*
* @param processCode processCode
*/
private void deleteByProcessCode(String processCode) {
QueryWrapper<DpProcessMessage> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(DpProcessMessage::getProcessCode, processCode);
processMessageMapper.delete(wrapper);
}
}
观察者 mapper接口
package com.service.dao.mapper;
import com.domain.model.DpProcessMessage;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DpProcessMessageMapper extends BaseMapper<DpProcessMessage> {
}
通用信息 实体类
package com.domain.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@NoArgsConstructor
@TableName("dp_process_message")
public class DpProcessMessage implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 流程类型
*/
@TableField("process_type")
private String processType;
/**
* 流程单号
*/
@TableField("process_code")
private String processCode;
/**
* 流程跳转url
*/
@TableField("process_url")
private String processUrl;
/**
* 流程信息
*/
@TableField("message")
private String message;
/**
* 流程状态
*/
@TableField("status")
private String status;
/**
* 创建人
*/
@TableField("create_user")
private String createUser;
/**
* 处理人
*/
@TableField("deal_user")
private String dealUser;
@TableField(value = "msg_create_user", exist = false)
private String msgCreateUser;
/**
* 创建时间
*/
@TableField("create_time")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createTime;
}
涉及部分的实体类
流程常量类
- 方便直接调用
package com.constants.process;
/**
* 流程常量
*
*/
public class ProcessConstants {
/**
* 开始
*/
public static final String START_EVENT_ID = "start";
/**
* 结束
*/
public static final String END_EVENT_ID = "end";
/**
* 遗留问题 流程定义 key
*/
public static final String KNOWN_ISSUE_PROCESS_DEF_KEY = "knownIssue";
/**
* 遗留问题 任务定义 key
*/
public static final String KNOWN_ISSUE_TASK_DEF_KEY = "knownIssueTaskId";
/**
* 遗留问题 任务状态 variables
*/
public static final String KNOWN_ISSUE_TASK_STATE_VAR = "knownIssueState";
/**
* 遗留问题 进展 变量名
*/
public static final String KNOWN_ISSUE_PROGRESS_VAR = "PROGRESS_DETAIL";
/**
* 遗留问题 更新人
*/
public static final String KNOWN_ISSUE_PROGRESS_UPDATER = "UPDATER";
/**
* 遗留问题 更新内容
*/
public static final String KNOWN_ISSUE_PROGRESS_CONTENT = "CONTENT";
/**
* 开启
*/
public static final String OPEN_STATE = "OPEN";
/**
* 关闭
*/
public static final String CLOSE_STATE = "CLOSE";
/**
* 完成
*/
public static final String FINISHED_STATE = "FINISHED";
/**
* 取消
*/
public static final String CANCELED_STATE = "CANCELED";
}
业务流程表单实体类
package com.domain.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("dp_process_known_issue_details")
public class KnownIssueDetailsTab {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
@TableField("proc_ins_id")
private String processInstanceId;
@TableField("task_id")
private String taskId;
@TableField("handler")
private String handler;
@TableField("issue_desc")
private String issueDesc;
@TableField("plan_finished_date")
private Date planFinishedDate;
@TableField("`label`")
private String label;
@TableField("pdu_name")
private String pduName;
@TableField("created_date")
private Date createdDate;
}
状态变量 枚举类
package com.enums;
import lombok.Getter;
public enum State {
OPEN(0, "进行中", "open"),
CLOSE(1, "已关闭", "close"),
FINISHED(2, "已完成", "finished"),
CANCELED(3, "已撤销", "canceled"),
UNDO(4, "未开始", "undo"),
REJECTED(5, "被驳回", "rejected"),
DRAFT(6, "草稿", "draft");
@Getter
private final Integer code;
@Getter
private final String nameCn;
@Getter
private final String nameEn;
State(Integer code, String nameCn, String nameEn) {
this.code = code;
this.nameCn = nameCn;
this.nameEn = nameEn;
}
}
创建遗留问题单 传参类
package com.model;
import java.util.*;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class KnowIssueCreateParam implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("handlers")
private List<String> handlers = new ArrayList<String>();
@JsonProperty("issueDesc")
private String issueDesc = null;
@JsonProperty("planFinishedDate")
private String planFinishedDate = null;
@JsonProperty("label")
private String label = null;
@JsonProperty("pduName")
private String pduName = null;
@JsonProperty("problemNo")
private String problemNo = null;
@JsonProperty("handler")
private String handler = null;
public KnowIssueCreateParam() {
super();
}
/**
**/
public List<String> getHandlers() {
return handlers;
}
public void setHandlers(List<String> handlers) {
this.handlers = handlers;
}
/**
**/
public String getIssueDesc() {
return issueDesc;
}
public void setIssueDesc(String issueDesc) {
this.issueDesc = issueDesc;
}
/**
**/
public String getPlanFinishedDate() {
return planFinishedDate;
}
public void setPlanFinishedDate(String planFinishedDate) {
this.planFinishedDate = planFinishedDate;
}
/**
**/
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
/**
**/
public String getPduName() {
return pduName;
}
public void setPduName(String pduName) {
this.pduName = pduName;
}
/**
**/
public String getProblemNo() {
return problemNo;
}
public void setProblemNo(String problemNo) {
this.problemNo = problemNo;
}
/**
**/
public String getHandler() {
return handler;
}
public void setHandler(String handler) {
this.handler = handler;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
KnowIssueCreateParam knowIssueCreateParam = (KnowIssueCreateParam) o;
return Objects.equals(this.handlers,
knowIssueCreateParam.handlers)
&& Objects.equals(this.issueDesc,
knowIssueCreateParam.issueDesc)
&& Objects.equals(this.planFinishedDate,
knowIssueCreateParam.planFinishedDate)
&& Objects.equals(this.label,
knowIssueCreateParam.label)
&& Objects.equals(this.pduName,
knowIssueCreateParam.pduName)
&& Objects.equals(this.problemNo,
knowIssueCreateParam.problemNo)
&& Objects.equals(this.handler,
knowIssueCreateParam.handler);
}
@Override
public int hashCode() {
return Objects.hash(handlers
, issueDesc
, planFinishedDate
, label
, pduName
, problemNo
, handler);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class KnowIssueCreateParam { ");
sb.append(" handlers: ").append(handlers).append(", ");
sb.append(" issueDesc: ").append(issueDesc).append(", ");
sb.append(" planFinishedDate: ").append(planFinishedDate).append(", ");
sb.append(" label: ").append(label).append(", ");
sb.append(" pduName: ").append(pduName).append(", ");
sb.append(" problemNo: ").append(problemNo).append(", ");
sb.append(" handler: ").append(handler).append(", ");
sb.append("} ");
return sb.toString();
}
}
流程变量封装类
package com.domain.dto.process;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ProcessVarHistoryRecordDto {
private String taskId;
private String procInsId;
private String varName;
private String varType;
private String varContent;
private Date operateDate;
}