一.前言
前面Activiti工作流的學習,說明了Activiti的基本應用,在我們開發中可以根據實際的業務參考Activiti的API去更好的理解以及鞏固。我們實際的開發中我們基本上都使用spring框架進行開發,現在來說明一下Activiti工作流與spring集成,Activiti工作流與spring集成還算比較簡單,可以參考Activiti的API來進行整合。
二.Activiti常用的表
---------------------------------------------部署對象和流程定義相關的表--------------------------------------------- --部署對象信息表 SELECT T.*, T.ROWID FROM ACT_RE_DEPLOYMENT T; --流程定義表 --ID_ 由KEY_ + VERSION_ + 隨機生成是數組成 SELECT T.*, T.ROWID FROM ACT_RE_PROCDEF T where t.category_='1' order by t.version_ asc; --資源文件表 SELECT T.*, T.ROWID FROM ACT_GE_BYTEARRAY T; --主鍵生成策略表 SELECT T.*, T.ROWID FROM ACT_GE_PROPERTY T; ------------------------------------------流程實例、執行對象、任務------------------------------------------------ --正在執行的執行對象表 -- 執行ID_ 56 流程實例ID_ 56 流程定義ID_ _3701622B-4133-7B3D-F50F-E14B4F21E847:1:55 正在運行的任務定義ID_ 【可變】 USERTASKE736BEF8-4133-7B3D-F510-7B2DE7BEA8C6 SELECT T.*, T.ROWID FROM ACT_RU_EXECUTION T; --流程實例歷史表 開始信息 --歷史流程定義ID_ 56 流程S實例ID_ 56 業務KEY_10000001 流程定義ID_ _3701622B-4133-7B3D-F50F-E14B4F21E847:1:55 開始任務節點ID_ STARTEVENT52B3145F-C133-7B3D-F50F-E6D48BA60EAE SELECT T.*, T.ROWID FROM ACT_HI_PROCINST T; --正在執行的任務對象表 --任務ID_ 68 執行ID_ 56 流程實例ID_ 56 流程定義ID_ _3701622B-4133-7B3D-F50F-E14B4F21E847:1:55 任務節點ID_ USERTASKE736BEF8-4133-7B3D-F510-7B2DE7BEA8C6 SELECT T.*, T.ROWID FROM ACT_RU_TASK T; --歷史任務流程實例信息 --歷史任務ID_ 68 流程實例ID_ 56 執行實例ID_ 56 流程定義ID_ _3701622B-4133-7B3D-F50F-E14B4F21E847:1:55 任務節點ID_ USERTASKE736BEF8-4133-7B3D-F510-7B2DE7BEA8C6 表單KEY_ /PAGES/HOLIDAY/HOLIDAYMANAGE/HOLIDAYFORMHANDLE.JSP --歷史任務ID_ 74 流程實例ID_ 56 執行實例ID_ 56 流程定義ID_ _3701622B-4133-7B3D-F50F-E14B4F21E847:1:55 任務節點ID_ USERTASK04A84BE1-1133-7B3D-F511-1D0B7BB0A668 表單KEY_ /PAGES/HOLIDAY/HOLIDAYMANAGE/HOLIDAYFORMVIEW.JSP SELECT T.*, T.ROWID FROM ACT_HI_TASKINST T; --所有活動節點歷史任務表 --歷史任務ID_58 流程定義ID_ _3701622B-4133-7B3D-F50F-E14B4F21E847:1:55 流程實例ID_ 56 流程執行ID_ 56 任務節點ID_ STARTEVENT52B3145F-C133-7B3D-F50F-E6D48BA60EAE --歷史任務ID_67 流程定義ID_ _3701622B-4133-7B3D-F50F-E14B4F21E847:1:55 流程實例ID_ 56 流程執行ID_ 56 任務節點ID_ USERTASKE736BEF8-4133-7B3D-F510-7B2DE7BEA8C6 任務ID_ 68 --歷史任務ID_73 流程定義ID_ _3701622B-4133-7B3D-F50F-E14B4F21E847:1:55 流程實例ID_ 56 流程執行ID_ 56 任務節點ID_ USERTASK04A84BE1-1133-7B3D-F511-1D0B7BB0A668 任務ID_ 74 SELECT T.*, T.ROWID FROM ACT_HI_ACTINST T; ----------------------------------------流程變量信息-------------------------------------------------- --正在執行的流程變量信息 SELECT T.*, T.ROWID FROM ACT_RU_VARIABLE T; --歷史流程變量信息 存放歷史表單重要信息 --流程實例ID_ 56 執行實例ID_ 56 任務ID_ SELECT T.*, T.ROWID FROM ACT_HI_VARINST T; -------------------------------------------歷史意見信息----------------------------------------------- --歷史審批意見表 --任務ID_ 68 流程定義ID_ 56 SELECT T.*, T.ROWID FROM ACT_HI_COMMENT T; -----------------------------------------節點參與者信息------------------------------------------------- --任務辦理人表(個人任務、組任務) SELECT T.*, T.ROWID FROM ACT_RU_IDENTITYLINK T; --歷史任務辦理人表(個人任務、組任務) SELECT T.*, T.ROWID FROM ACT_HI_IDENTITYLINK T; --臨時對象 SELECT T.*, T.ROWID FROM EA_IST.IST_APPR_BUSI_DATA T
三.Activiti與spring整合xml配置文件
向spring配置文件中,添加一個spring-workflow2-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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!--工作流引擎配置 --> <bean id="processEngineConfiguration" class="com.shine.workflow2.spring.ShineSpringProcessEngineConfiguration"> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager" /> <property name="databaseSchemaUpdate" value="false" /> <property name="jobExecutorActivate" value="false" /> <!-- 組織機構適配 --> <property name="organizationConnector" ref="organizationAdapter" /> </bean> <!-- 組織機構適配實現 --> <bean id="organizationAdapter" class="com.shine.workflow2.organization.impl.OrganizationAdapter" /> <!--工作流引擎 --> <bean id="processEngine" class="com.shine.workflow2.spring.ShineProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration" /> </bean> <!--擴展服務 --> <bean id="processDefinitionService" factory-bean="processEngine" factory-method="getProcessDefinitionService" /> <bean id="processLogService" factory-bean="processEngine" factory-method="getProcessLogService" /> <bean id="processManagementService" factory-bean="processEngine" factory-method="getProcessManagementService" /> <!--原生服務 --> <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" /> <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" /> <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" /> <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" /> <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" /> <bean id="formService" factory-bean="processEngine" factory-method="getFormService" /> <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService" /> </beans>
四.Activiti工作流常用service
1.BaseProcessService
/**
*
*/
package com.shine.eosp.workflow2.common.process;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import com.shine.workflow2.exception.WorkflowException;
/**
*
* 類說明: 常用工作流核心操作封裝 .
*
* <pre>
* 修改日期 修改人 修改原因
* 2016-6-2 hongwz 新建
* </pre>
*/
public interface BaseProcessService {
/**
* 方法說明 : 根據流程定義Key查詢最新流程定義.
*
* @param processDefinitionKey
* @throws WorkflowException
*/
public ProcessDefinition findLatestProcessDefinitionByPrcDefKey(String processDefinitionKey) throws WorkflowException;
/**
* 方法說明 : 根據流程定義Id查詢流程定義.
*
* @param processDefinitionId 流程定義Id
* @throws WorkflowException
*/
public ProcessDefinitionEntity findProcessDefinitionEntityByProcDefId(String processDefinitionId) throws WorkflowException;
/**
*
* 方法說明 : 根據流程實例Id查詢流程實例.
*
* @param processInstanceId 流程實例Id
* @return
* @throws WorkflowException
*/
public ProcessInstance findProcessInstanceByProcInst(String processInstanceId) throws WorkflowException;
/**
* 根據流程實例Id查詢流程實例.
*
* @param processInstanceId
* @throws WorkflowException
*/
public Execution findExecutionByProcInst(String processInstanceId) throws WorkflowException;
/**
* 方法說明 : 根據流程實例Id查詢任務.
*
* @param processInstanceId 流程實例Id
* @throws WorkflowException
*/
public Task findTaskByProcInstId(String processInstanceId) throws WorkflowException;
/**
* 方法說明 : 根據實例Id查詢任務.
*
* @param executionId 實例Id
* @throws WorkflowException
*/
public Task findTaskByExecutionId(String executionId) throws WorkflowException;
/**
* 方法說明 : 根據活動節點查詢任務定義.
*
* @param activityImpl 活動節點
* @throws WorkflowException
*/
public TaskDefinition findTaskDefinitionByActivityImpl(ActivityImpl activityImpl) throws WorkflowException;
/**
* 方法說明 : 查詢上一個節點.
*
* @param activityImpl 活動節點
* @param activityId 當前活動節點ID
* @param elString
* @throws ShineException
*/
public TaskDefinition beforeTaskDefinition(ActivityImpl activityImpl,String activityId, String elString) throws WorkflowException;
/**
* 方法說明 : 查詢下一個節點.
*
* @param activityImpl 活動節點
* @param activityId 當前活動節點ID
* @param elString
* @throws ShineException
*/
public TaskDefinition nextTaskDefinition(ActivityImpl activityImpl,String activityId, String elString) throws WorkflowException;
/**
* 方法說明: 根據活動節點、活動線路查詢線路的連接線.
*
* @throws WorkflowException
*/
public PvmActivity findPvmActivity(ActivityImpl activityImpl, String transitions) throws WorkflowException;
/**
* 方法說明 :根據流程定義Id查詢任務定義
*
* @param processDefinitionId 流程定義Id
* @return
* @throws WorkflowException
*/
public TaskDefinition findTaskDefinition(String processDefinitionId) throws WorkflowException;
/**
* 方法說明 : 添加任務意見.
*
* @param taskId 任務Id
* @param processInstanceId 流程實例Id
* @param comment 意見
* @throws WorkflowException
*/
public void addTaskComment(String taskId, String processInstanceId, String comment) throws WorkflowException;
/**
* 方法說明 : 拾取任務.
*
* @param taskId 任務Id
* @param operator 辦理人
* @throws WorkflowException
*/
public void claimTask(String taskId, String operator) throws WorkflowException;
/**
* 方法說明 : 根據流程定義Id查詢最新流程定義.
*
* @param processDefinitionId 流程定義Id
* @return
* @throws WorkflowException
*/
public ProcessDefinition findProcessDefinitionByPrcDefId(String processDefinitionId) throws WorkflowException;
}
2.BaseProcessServiceImpl
/**
*
*/
package com.shine.eosp.workflow2.common.process;
import java.util.Iterator;
import java.util.List;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
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.task.TaskDefinition;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.shine.util.CollectionUtil;
import com.shine.workflow2.exception.WorkflowException;
/**
*
* 類說明: 常用工作流核心操作封裝 .
*
* <pre>
* 修改日期 修改人 修改原因
* 2016-6-2 hongwz 新建
* </pre>
*/
public class BaseProcessServiceImpl implements BaseProcessService {
/**
* log.
*/
private static Logger logger = LoggerFactory.getLogger(BaseProcessServiceImpl.class);
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
/**
* 方法說明 : 根據流程定義Key查詢最新流程定義.
*
* @param processDefinitionKey 流程定義Key
* @return
* @throws WorkflowException
*/
@Override
public ProcessDefinition findLatestProcessDefinitionByPrcDefKey(String processDefinitionKey) throws WorkflowException{
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(processDefinitionKey)
.latestVersion()
.singleResult();
return processDefinition;
}
/**
* 方法說明 : 根據流程定義Id查詢最新流程定義.
*
* @param processDefinitionId 流程定義Id
* @return
* @throws WorkflowException
*/
@Override
public ProcessDefinition findProcessDefinitionByPrcDefId(String processDefinitionId) throws WorkflowException{
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(processDefinitionId)
.orderByProcessDefinitionVersion()
.desc()
.singleResult();
return processDefinition;
}
/**
* 方法說明 : 根據流程定義Id查詢流程定義.
*
* @param processDefinitionId 流程定義Id
* @return
* @throws WorkflowException
*/
@Override
public ProcessDefinitionEntity findProcessDefinitionEntityByProcDefId(String processDefinitionId) throws WorkflowException{
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(processDefinitionId);
return processDefinitionEntity;
}
/**
*
* 方法說明 : 根據流程實例Id查詢流程實例.
*
* @param processInstanceId 流程實例Id
* @return
* @throws WorkflowException
*/
@Override
public ProcessInstance findProcessInstanceByProcInst(String processInstanceId) throws WorkflowException{
return runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
}
/**
* 根據流程實例Id查詢流程實例.
*
* @param processInstanceId
* @return
* @throws WorkflowException
*/
@Override
public Execution findExecutionByProcInst(String processInstanceId) throws WorkflowException{
return runtimeService.createExecutionQuery().processInstanceId(processInstanceId).singleResult();
}
/**
* 方法說明 : 根據流程實例Id查詢任務.
*
* @param processInstanceId 流程實例Id
* @return
* @throws WorkflowException
*/
@Override
public Task findTaskByProcInstId(String processInstanceId) throws WorkflowException{
return taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
}
/**
* 方法說明 : 根據實例Id查詢任務.
*
* @param executionId 實例Id
* @return
* @throws WorkflowException
*/
@Override
public Task findTaskByExecutionId(String executionId) throws WorkflowException{
return taskService.createTaskQuery().executionId(executionId).singleResult();
}
/**
* 方法說明 : 根據活動節點查詢任務定義.
*
* @param activityImpl 活動節點
* @return
* @throws WorkflowException
*/
@Override
public TaskDefinition findTaskDefinitionByActivityImpl(ActivityImpl activityImpl) throws WorkflowException{
return ((UserTaskActivityBehavior)activityImpl.getActivityBehavior()).getTaskDefinition();
}
/**
* 方法說明 : 查詢上一個節點.
*
* @param activityImpl 活動節點
* @param activityId 當前活動節點ID
* @param elString
* @return
* @throws ShineException
*/
@Override
public TaskDefinition beforeTaskDefinition(ActivityImpl activityImpl,String activityId, String elString) throws WorkflowException {
if("userTask".equals(activityImpl.getProperty("type")) && !activityId.equals(activityImpl.getId())){
TaskDefinition taskDefinition = null;
if(activityImpl != null){
taskDefinition = findTaskDefinitionByActivityImpl(activityImpl);
}
return taskDefinition;
}else{
List<PvmTransition> inTransitions = activityImpl.getIncomingTransitions(); //通過活動節點查詢所有線路
if(!CollectionUtil.isEmpty(inTransitions)){
List<PvmTransition> inTransitionsTemp = null;
for(PvmTransition tr:inTransitions){
PvmActivity ac = tr.getSource(); //獲取線路的前節點
if("exclusiveGateway".equals(ac.getProperty("type"))){
inTransitionsTemp = ac.getIncomingTransitions();
if(inTransitionsTemp.size() == 1){
return beforeTaskDefinition((ActivityImpl)inTransitionsTemp.get(0).getSource(), activityId, elString);
}else if(inTransitionsTemp.size() > 1){
for(PvmTransition tr1 : inTransitionsTemp){
Object s = tr1.getProperty("conditionText");
if(elString.equals(StringUtils.replacePattern(StringUtils.trim(s.toString()), " ", ""))){
return beforeTaskDefinition((ActivityImpl)tr1.getSource(), activityId, elString);
}
}
}
}
}
}
return null;
}
}
/**
* 方法說明 : 查詢下一個節點.
*
* @param activityImpl 活動節點
* @param activityId 當前活動節點ID
* @param elString
* @return
* @throws ShineException
*/
@Override
public TaskDefinition nextTaskDefinition(ActivityImpl activityImpl,String activityId, String elString) throws WorkflowException {
if("userTask".equals(activityImpl.getProperty("type")) && !activityId.equals(activityImpl.getId())){
TaskDefinition taskDefinition = null;
if(activityImpl != null){
taskDefinition = findTaskDefinitionByActivityImpl(activityImpl);
}
return taskDefinition;
}else{
List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions(); //通過活動節點查詢所有線路
if(!CollectionUtil.isEmpty(outTransitions)){
List<PvmTransition> outTransitionsTemp = null;
for(PvmTransition tr:outTransitions){
PvmActivity ac = tr.getDestination(); //獲取線路的終點節點
if("exclusiveGateway".equals(ac.getProperty("type"))){
outTransitionsTemp = ac.getOutgoingTransitions();
if(outTransitionsTemp.size() == 1){
return nextTaskDefinition((ActivityImpl)outTransitionsTemp.get(0).getDestination(), activityId, elString);
}else if(outTransitionsTemp.size() > 1){
for(PvmTransition tr1 : outTransitionsTemp){
Object s = tr1.getProperty("conditionText");
if(s != null && elString.equals(StringUtils.replacePattern(StringUtils.trim(s.toString()), " ", ""))){
return nextTaskDefinition((ActivityImpl)tr1.getDestination(), activityId, elString);
}
}
}
}else if("userTask".equals(ac.getProperty("type"))){
return findTaskDefinitionByActivityImpl((ActivityImpl)ac);
}
else if("startEvent".equals(ac.getProperty("type"))){
return findTaskDefinitionByActivityImpl((ActivityImpl)ac);
}
else{
logger.info(ac.getProperty("type").toString());
}
}
}
return null;
}
}
/**
* 方法說明: 根據活動節點、活動線路查詢線路的連接線.
*
* @return
* @throws WorkflowException
*/
@SuppressWarnings("rawtypes")
@Override
public PvmActivity findPvmActivity(ActivityImpl activityImpl, String transitions) throws WorkflowException{
PvmActivity activity = null;
List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions(); //獲取所有線路
for (Iterator iterator = pvmTransitions.iterator(); iterator.hasNext();) {
PvmTransition pvmTransition = (PvmTransition) iterator.next();
PvmActivity pvmActivity = pvmTransition.getDestination(); //獲取下一個任務節點
String transitionsVal = (String) pvmActivity.getProperty("name");
if(transitions.equals(transitionsVal)){
activity = pvmActivity;
break;
}
}
return activity;
}
/**
* 方法說明 :根據流程定義Id查詢任務定義
*
* @param processDefinitionId 流程定義Id
* @return
* @throws WorkflowException
*/
@Override
public TaskDefinition findTaskDefinition(String processDefinitionId) throws WorkflowException{
//獲取流程定義
ProcessDefinitionEntity processDefinitionEntity = findProcessDefinitionEntityByProcDefId(processDefinitionId);
TaskDefinition tdf = null;
if(processDefinitionEntity != null){
List<ActivityImpl> activityImpls = processDefinitionEntity.getActivities(); //獲取所有活動的節點
for(int i = activityImpls.size() - 1; i > 0; i-- ){
ActivityImpl activityImpl = activityImpls.get(i);
String startEventType = (String) activityImpl.getProperty("type");
if("startEvent".equals(startEventType)){
tdf = nextTaskDefinition(activityImpl, activityImpl.getId(), null);
}
}
}
return tdf;
}
/**
* 方法說明 : 添加任務意見.
*
* @param taskId 任務Id
* @param processInstanceId 流程實例Id
* @param comment 意見
* @throws WorkflowException
*/
@Override
public void addTaskComment(String taskId,String processInstanceId,String comment) throws WorkflowException{
taskService.addComment(taskId, processInstanceId, comment);
}
/**
* 方法說明 : 拾取任務.
*
* @param taskId 任務Id
* @param operator 辦理人
* @throws WorkflowException
*/
@Override
public void claimTask(String taskId,String operator) throws WorkflowException{
taskService.claim(taskId, operator);
}
}
