5月份的时候,公司需要开发一个新项目,其中涉及到审批的相关业务流程,我首先到网络上面搜索到了常用的工作流引擎有哪些,我这里不做介绍了,最终选择了activiti工作流引擎。
在工作了7年多的时间里,我从来没有用到过工作流,但是对我们开发者来说,工作流引擎这种技术,只要我们深入研究该工作流引擎的API,也就能够很清楚的去使用工作流引擎了,但是在实际的开发中,业务对接工作流遇到了很多的问题,我都是一个一个的挑灯夜战的去攻关,一个一个去击破,最终把遇到的所有问题都解决了。然后我根据我的想法去封装了这套在业务中需要使用的工作流的体系,下面直接上代码。
第一步,首先项目用的是maven,我们首先引入依赖
5.18.0
org.activiti
activiti-engine
org.activiti
activiti-bpmn-model
org.activiti
activiti-bpmn-converter
org.activiti
activiti-process-validation
org.activiti
activiti-spring
org.activiti
activiti-diagram-rest
${activiti.version}
org.activiti
activiti-json-converter
${activiti.version}
org.activiti
activiti-image-generator
${activiti.version}
第二部,添加Spring的配置文件src/main/resources/spring/applicationContext-activiti.xml
第三部,我们创建一个工厂类,把工作流引擎需要用到的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 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 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 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 taskCandidateUser(String userId,int start,int limit);
public List taskAssignee(String userId,int start,int limit);
public List taskCandidateOrAssigned(String userId,int start,int limit);
public List taskCandidateUserByCondition(String userId,Map variables,int start,int limit);
public List taskAssigneeByCondition(String userId,Map variables,int start,int limit);
public List taskCandidateOrAssignedByCondition(String userId,Map 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 variables);
public long countTaskAssigneeByCondition(String userId,Map variables);
public long countTaskCandidateOrAssignedByCondition(String userId,Map variables);
public List taskAssigneeHistory(String userId,int start,int limit);
public long countTaskAssigneeByTaskQuery(String assignee, TaskQuery query);
public List 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 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 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 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 taskCandidateUser(String candidateUser,int start,int limit) {
return createTaskQuery().taskCandidateUser(candidateUser)
.orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List taskAssignee(String assignee,int start,int limit) {
return createTaskQuery().taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List taskCandidateOrAssigned(String userId,int start,int limit) {
return createTaskQuery().taskCandidateOrAssigned(userId).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List taskAssigneeHistory(String assignee,int start,int limit) {
return createHistoricTaskInstanceQuery().taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
public TaskQuery buildeTaskQueryByvariables(Map args){
TaskQuery tq = createTaskQuery();
if (args != null && args.size() >0) {
for(Entry 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 taskCandidateUserByCondition(String candidateUser, Map variables, int start, int limit) {
return buildeTaskQueryByvariables(variables).taskCandidateUser(candidateUser)
.orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List taskAssigneeByCondition(String assignee, Map variables, int start, int limit) {
return buildeTaskQueryByvariables(variables).taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
@Override
public List taskCandidateOrAssignedByCondition(String userId, Map 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 variables) {
return buildeTaskQueryByvariables(variables).taskCandidateUser(candidateUser)
.orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public long countTaskAssigneeByCondition(String assignee, Map variables) {
return buildeTaskQueryByvariables(variables).taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.count();
}
@Override
public long countTaskCandidateOrAssignedByCondition(String userId, Map 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 taskAssigneeByTaskQuery(String assignee, TaskQuery query, int start, int limit) {
return query.taskAssignee(assignee).orderByTaskPriority().desc()
.orderByTaskCreateTime().asc()
.listPage(start, limit);
}
}
目前通过该封装的相关代码,就可以保证当前的业务可以正常进行审批操作。
当然我们前期需要定义相关的工作流配置,截图如下:
关于activiti工作流引擎,还有很多细节,后面我会再给大家展示一下业务如何创建工作流,及业务审批是如何进行操作的相关代码。