版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinosoft12345/article/details/81199907
5月份的时候,公司需要开发一个新项目,其中涉及到审批的相关业务流程,我首先到网络上面搜索到了常用的工作流引擎有哪些,我这里不做介绍了,最终选择了activiti工作流引擎。
在工作了7年多的时间里,我从来没有用到过工作流,但是对我们开发者来说,工作流引擎这种技术,只要我们深入研究该工作流引擎的API,也就能够很清楚的去使用工作流引擎了,但是在实际的开发中,业务对接工作流遇到了很多的问题,我都是一个一个的挑灯夜战的去攻关,一个一个去击破,最终把遇到的所有问题都解决了。然后我根据我的想法去封装了这套在业务中需要使用的工作流的体系,下面直接上代码。
第一步,首先项目用的是maven,我们首先引入依赖
<activiti.version>5.18.0</activiti.version>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-process-validation</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-diagram-rest</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-image-generator</artifactId>
<version>${activiti.version}</version>
</dependency>
第二部,添加Spring的配置文件src/main/resources/spring/applicationContext-activiti.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- Activiti引擎配置 -->
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<!-- 如果表不存在,就创建表,如果表存在,就直接操作 -->
<property name="databaseSchemaUpdate" value="true" />
<property name="jobExecutorActivate" value="false" />
<property name="deploymentResources" value="classpath*:bpmn/*.bpmn20.xml" />
</bean>
<!-- Activiti引擎工厂 -->
<bean id="processEngineFactory" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
<!-- Activiti的服务 -->
<bean id="repositoryService" factory-bean="processEngineFactory" factory-method="getRepositoryService" />
<bean id="runtimeService" factory-bean="processEngineFactory" factory-method="getRuntimeService" />
<bean id="formService" factory-bean="processEngineFactory" factory-method="getFormService" />
<bean id="identityService" factory-bean="processEngineFactory" factory-method="getIdentityService" />
<bean id="taskService" factory-bean="processEngineFactory" factory-method="getTaskService" />
<bean id="historyService" factory-bean="processEngineFactory" factory-method="getHistoryService" />
<bean id="managementService" factory-bean="processEngineFactory" factory-method="getManagementService" />
</beans>
第三部,我们创建一个工厂类,把工作流引擎需要用到的service服务引入依赖
import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ProcessServiceFactory {
@Autowired
protected RepositoryService repositoryService;
@Autowired
protected RuntimeService runtimeService;
@Autowired
protected IdentityService identityService;
@Autowired
protected TaskService taskService;
@Autowired
protected FormService formService;
@Autowired
protected HistoryService historyService;
@Autowired
protected ManagementService managementService;
}
第四部,我们定义一些接口类,为了后面能够扩展
import java.util.Map;
import org.activiti.engine.runtime.ProcessInstance;
public interface WorkFlow {
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables) throws RuntimeException,Exception;
void suspendProcessInstanceById(String processInstanceId) throws RuntimeException,Exception;
void deleteProcessInstance(String processInstanceId, String deleteReason) throws RuntimeException,Exception;
/** 设置流程开始节点发起人*/
void setAuthenticatedUserId(String authenticatedUserId);
}
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
public interface WorkFlowQuery {
public ProcessInstanceQuery createProcessInstanceQuery();
public ProcessInstance processInstanceId(String processInstanceId);
public ProcessInstance processInstanceBusinessKey(String processInstanceBusinessKey);
public ProcessInstance taskId(String taskId);
public boolean isProcessfinished(String processInstanceId);
}
import java.util.List;
import java.util.Map;
import org.activiti.engine.task.Comment;
public interface WorkFlowTask {
public void setVariableLocal(String taskId, String variableName, Object value);
public void claim(String taskId, String userId) throws RuntimeException,Exception;
public void unclaim(String taskId)throws RuntimeException,Exception;
public void complete(String taskId)throws RuntimeException,Exception;
public void complete(String taskId, Map<String, Object> variables)throws RuntimeException,Exception;
public void setAssignee(String taskId, String userId)throws RuntimeException,Exception;
public void addCandidateUser(String taskId, String userId)throws RuntimeException,Exception;
public Comment addComment(String taskId, String processInstanceId, String message)throws RuntimeException,Exception;
public List<Comment> getTaskComments(String taskId)throws RuntimeException,Exception;
}
import java.util.List;
import java.util.Map;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
public interface WorkFlowTaskQuery {
public TaskQuery createTaskQuery();
public String findVariableByTaskId(String taskId,String variableName);
public String findBusinessKeyByTaskId(String taskId);
public HistoricTaskInstanceQuery createHistoricTaskInstanceQuery();
public Task taskId(String taskId);
public Task processInstanceId(String processInstanceId);
public List<Task> taskCandidateUser(String userId,int start,int limit);
public List<Task> taskAssignee(String userId,int start,int limit);
public List<Task> taskCandidateOrAssigned(String userId,int start,int limit);
public List<Task> taskCandidateUserByCondition(String userId,Map<String, Object> variables,int start,int limit);
public List<Task> taskAssigneeByCondition(String userId,Map<String, Object> variables,int start,int limit);
public List<Task> taskCandidateOrAssignedByCondition(String userId,Map<String, Object> variables,int start,int limit);
public long countTaskCandidateUser(String userId);
public long countTaskAssignee(String userId);
public long countTaskCandidateOrAssigned(String userId);
public long countTaskCandidateUserByCondition(String userId,Map<String, Object> variables);
public long countTaskAssigneeByCondition(String userId,Map<String, Object> variables);
public long countTaskCandidateOrAssignedByCondition(String userId,Map<String, Object> variables);
public List<HistoricTaskInstance> taskAssigneeHistory(String userId,int start,int limit);
public long countTaskAssigneeByTaskQuery(String assignee, TaskQuery query);
public List<Task> taskAssigneeByTaskQuery(String assignee, TaskQuery query,int start,int limit);
}
第五步,我们封装出一些业务需要调用的类,供业务使用
import java.util.Map;
import org.activiti.engine.runtime.ProcessInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.puxinasset.framework.workflow.WorkFlow;
import com.puxinasset.framework.workflow.base.ProcessServiceFactory;
@Component
public class WorkFlowHandler extends ProcessServiceFactory implements WorkFlow{
protected static Logger logger = LoggerFactory.getLogger(WorkFlowHandler.class);
@Override
public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey,
Map<String, Object> variables) throws RuntimeException,Exception {
ProcessInstance pi = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
return pi;
}
@Override
public void suspendProcessInstanceById(String processInstanceId) throws RuntimeException,Exception{
runtimeService.suspendProcessInstanceById(processInstanceId);
}
@Override
public void deleteProcessInstance(String processInstanceId, String deleteReason) throws RuntimeException,Exception{
runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
}
@Override
public void setAuthenticatedUserId(String authenticatedUserId) {
identityService.setAuthenticatedUserId(authenticatedUserId);
}
}
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.puxinasset.framework.workflow.WorkFlowQuery;
import com.puxinasset.framework.workflow.base.ProcessServiceFactory;
@Component
public class WorkFlowQueryHandler extends ProcessServiceFactory implements WorkFlowQuery{
protected static Logger logger = LoggerFactory.getLogger(WorkFlowQueryHandler.class);
@Override
public ProcessInstanceQuery createProcessInstanceQuery() {
return runtimeService.createProcessInstanceQuery();
}
@Override
public ProcessInstance processInstanceId(String processInstanceId) {
return createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
}
@Override
public ProcessInstance processInstanceBusinessKey(String processInstanceBusinessKey) {
return createProcessInstanceQuery().processInstanceBusinessKey(processInstanceBusinessKey).singleResult();
}
@Override
public boolean isProcessfinished(String processInstanceId) {
ProcessInstance pi = processInstanceId(processInstanceId);
return pi == null;
}
@Override
public ProcessInstance taskId(String taskId) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
String processInstId = task.getProcessInstanceId();
return this.processInstanceId(processInstId);
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.puxinasset.framework.workflow.WorkFlowTask;
import com.puxinasset.framework.workflow.base.ProcessServiceFactory;
@Component
public class WorkFlowTaskhandler extends ProcessServiceFactory implements WorkFlowTask{
protected static Logger logger = LoggerFactory.getLogger(WorkFlowTaskhandler.class);
@Override
public void claim(String taskId, String userId) throws RuntimeException, Exception {
taskService.claim(taskId, userId);
}
@Override
public void unclaim(String taskId) throws RuntimeException, Exception {
taskService.unclaim(taskId);
}
@Override
public void complete(String taskId) throws RuntimeException, Exception {
this.complete(taskId, null);
logger.info("-----------任务ID:{},已完成-----------",taskId);
}
@Override
public void complete(String taskId, Map<String, Object> variables) throws RuntimeException, Exception {
taskService.complete(taskId, variables);
}
@Override
public void setAssignee(String taskId, String userId) throws RuntimeException, Exception {
taskService.setAssignee(taskId, userId);
}
@Override
public void addCandidateUser(String taskId, String userId) throws RuntimeException, Exception {
taskService.addCandidateUser(taskId, userId);
}
@Override
public Comment addComment(String taskId, String processInstanceId, String message)
throws RuntimeException, Exception {
return taskService.addComment(taskId, processInstanceId, message);
}
@Override
public List<Comment> getTaskComments(String taskId) throws RuntimeException, Exception {
return taskService.getTaskComments(taskId);
}
@Override
public void setVariableLocal(String taskId, String variableName, Object value) {
taskService.setVariableLocal(taskId, variableName, value);
}
}
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.puxinasset.framework.workflow.WorkFlowTaskQuery;
import com.puxinasset.framework.workflow.base.ProcessServiceFactory;
import com.puxinasset.link.enums.WFVariablesEnum;
@Component
public class WorkFlowTaskQueryHandler extends ProcessServiceFactory implements WorkFlowTaskQuery{
protected static Logger logger = LoggerFactory.getLogger(WorkFlowTaskQueryHandler.class);
@Override
public TaskQuery createTaskQuery() {
return taskService.createTaskQuery();
}
@Override
public HistoricTaskInstanceQuery createHistoricTaskInstanceQuery() {
return historyService.createHistoricTaskInstanceQuery();
}
@Override
public Task taskId(String taskId){
return createTaskQuery().taskId(taskId).singleResult();
}
@Override
public List<Task> taskCandidateUser(String candidateUser,int start,int limit) {
return createTaskQuery().taskCandidateUser(candidateUser)
.orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List<Task> taskAssignee(String assignee,int start,int limit) {
return createTaskQuery().taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List<Task> taskCandidateOrAssigned(String userId,int start,int limit) {
return createTaskQuery().taskCandidateOrAssigned(userId).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List<HistoricTaskInstance> taskAssigneeHistory(String assignee,int start,int limit) {
return createHistoricTaskInstanceQuery().taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
public TaskQuery buildeTaskQueryByvariables(Map<String, Object> args){
TaskQuery tq = createTaskQuery();
if (args != null && args.size() >0) {
for(Entry<String, Object> entry : args.entrySet()){
if (WFVariablesEnum.activityName.toString().equals(entry.getKey()) ||
WFVariablesEnum.orgName.toString().equals(entry.getKey())) {
tq.processVariableValueLike(entry.getKey(), String.valueOf(entry.getValue()));
}else {
tq.processVariableValueEquals(entry.getKey(),entry.getValue());
}
}
}
return tq;
}
@Override
public List<Task> taskCandidateUserByCondition(String candidateUser, Map<String, Object> variables, int start, int limit) {
return buildeTaskQueryByvariables(variables).taskCandidateUser(candidateUser)
.orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List<Task> taskAssigneeByCondition(String assignee, Map<String, Object> variables, int start, int limit) {
return buildeTaskQueryByvariables(variables).taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List<Task> taskCandidateOrAssignedByCondition(String userId, Map<String, Object> variables, int start,
int limit) {
return buildeTaskQueryByvariables(variables).taskCandidateOrAssigned(userId).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public long countTaskCandidateUser(String candidateUser) {
return createTaskQuery().taskCandidateUser(candidateUser)
.orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public long countTaskAssignee(String assignee) {
return createTaskQuery().taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public long countTaskCandidateOrAssigned(String userId) {
return createTaskQuery().taskCandidateOrAssigned(userId).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public long countTaskCandidateUserByCondition(String candidateUser, Map<String, Object> variables) {
return buildeTaskQueryByvariables(variables).taskCandidateUser(candidateUser)
.orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public long countTaskAssigneeByCondition(String assignee, Map<String, Object> variables) {
return buildeTaskQueryByvariables(variables).taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public long countTaskCandidateOrAssignedByCondition(String userId, Map<String, Object> variables) {
return createTaskQuery().taskCandidateOrAssigned(userId).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public Task processInstanceId(String processInstanceId) {
return createTaskQuery().processInstanceId(processInstanceId).singleResult();
}
@Override
public String findBusinessKeyByTaskId(String taskId) {
Task task = this.createTaskQuery().taskId(taskId).singleResult();
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
if (pi != null) {
return pi.getBusinessKey();
}
return null;
}
@Override
public String findVariableByTaskId(String taskId, String variableName) {
Object value = taskService.getVariable(taskId, variableName);
return String.valueOf(value);
}
@Override
public long countTaskAssigneeByTaskQuery(String assignee, TaskQuery query) {
return query.taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public List<Task> taskAssigneeByTaskQuery(String assignee, TaskQuery query, int start, int limit) {
return query.taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
}
目前通过该封装的相关代码,就可以保证当前的业务可以正常进行审批操作。
当然我们前期需要定义相关的工作流配置,截图如下:
关于activiti工作流引擎,还有很多细节,后面我会再给大家展示一下业务如何创建工作流,及业务审批是如何进行操作的相关代码。