一、簡單介紹java
Activiti是一個開源的工做流引擎,它實現了BPMN 2.0規範,能夠發佈設計好的流程定義,並經過api進行流程調度。 node
Activiti 做爲一個聽從 Apache 許可的工做流和業務流程管理開源平臺,其核心是基於 Java 的超快速、超穩定的 BPMN 2.0 流程引擎,強調流程服務的可嵌入性和可擴展性,同時更增強調面向業務人員。 spring
Activiti 流程引擎重點關注在系統開發的易用性和輕量性上。每一項 BPM 業務功能 Activiti 流程引擎都以服務的形式提供給開發人員。經過使用這些服務,開發人員可以構建出功能豐富、輕便且高效的 BPM 應用程序。express
二、Activiti 的持久化方式api
Activiti 使用 Mybatis3 作持久化工做,能夠在配置中設置流程引擎啓動時建立表。
Activiti 使用到的表都是 ACT_開頭的。
ACT_RE_*:流程定義存儲。
ACT_RU_*:流程執行記錄,記錄流程啓動到結束的全部動做,流程結束後會清除相關記錄。
ACT_ID_*:用戶記錄,流程中使用到的用戶和組。
ACT_HI_*:流程執行的歷史記錄。
ACT_GE_*:通用數據及設置。app
使用到的表:
ACT_GE_BYTEARRAY:流程部署的數據。
ACT_GE_PROPERTY:通用設置。
ACT_HI_ACTINST:流程活動的實例。
ACT_HI_ATTACHMENT:
ACT_HI_COMMENT:
ACT_HI_DETAIL:
ACT_HI_PROCINST:流程實例。
ACT_HI_TASKINST:任務實例。
ACT_ID_GROUP:用戶組。
ACT_ID_INFO:
ACT_ID_MEMBERSHIP:
ACT_ID_USER:用戶。
ACT_RE_DEPLOYMENT:部署記錄。
ACT_RE_PROCDEF:流程定義。
ACT_RU_EXECUTION:流程執行記錄。
ACT_RU_IDENTITYLINK:
ACT_RU_JOB:
ACT_RU_TASK:執行的任務記錄。
ACT_RU_VARIABLE:執行中的變量記錄。dom
三、名詞解釋ide
關鍵對象單元測試
Deployment:流程部署對象,部署一個流程是建立。測試
ProcessDefinitions:流程定義,部署成功後自動建立。
ProcessInstances:流程實例,啓動流程是建立。
Task:任務,在 Activiti 中的 Task 僅指有角色參與的任務,即定義中的 UserTask。
Execution:執行計劃,流程實例和流程執行中的全部節點都是 Execution,如 UserTask、ServiceTask 等。
服務接口
ProcessEngine:流程引擎接口,提供流程管理和運做的全部接口。
RuntimeService:運行時服務接口,提供流程啓動服務,運行中流程查詢,運行變量設置和獲取。
TaskService:用戶任務接口(UserTask) ,提供運行時任務查詢、領取、完成、刪除及變量設置用戶管理等服務。
IdentityService:用戶和組管理接口。
ManagementService:流程引擎管理接口。
HistoryService:流程處理查詢接口,包括執行中流程查詢和歷史流程查詢。
四、Activiti的使用
4.1. 流程定義
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <process id="expenseAccount" name="expenseAccount" isExecutable="true"> <startEvent id="startevent1" name="開始"></startEvent> <userTask id="usertask1" name="部門經理"> <extensionElements> <activiti:taskListener event="create" expression="${todoListService.createToDoList(task,execution)}"></activiti:taskListener> </extensionElements> </userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway> <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="exclusivegateway1"></sequenceFlow> <userTask id="usertask2" name="公司副總審批"> <extensionElements> <activiti:taskListener event="create" expression="${todoListService.createToDoList(task,execution)}"></activiti:taskListener> </extensionElements> </userTask> <exclusiveGateway id="exclusivegateway2" name="Exclusive Gateway"></exclusiveGateway> <sequenceFlow id="flow4" sourceRef="usertask2" targetRef="exclusivegateway2"></sequenceFlow> <userTask id="usertask3" name="財務審批"> <extensionElements> <activiti:taskListener event="create" expression="${todoListService.createToDoList(task,execution)}"></activiti:taskListener> </extensionElements> </userTask> <sequenceFlow id="flow5" name="贊成" sourceRef="exclusivegateway2" targetRef="usertask3"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${AssistantCEOPass}]]></conditionExpression> </sequenceFlow> <exclusiveGateway id="exclusivegateway3" name="Exclusive Gateway"></exclusiveGateway> <sequenceFlow id="flow6" name="贊成" sourceRef="exclusivegateway1" targetRef="exclusivegateway3"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${managerPass}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow7" name="價格大於10000" sourceRef="exclusivegateway3" targetRef="usertask2"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money > 10000}]]></conditionExpression> </sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow8" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow> <sequenceFlow id="flow9" name="拒絕" sourceRef="exclusivegateway1" targetRef="endevent1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!managePass}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow10" name="價格小於10001" sourceRef="exclusivegateway3" targetRef="usertask3"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 10000}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow11" name="拒絕" sourceRef="exclusivegateway2" targetRef="endevent1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!AssistantCEOPass}]]></conditionExpression> </sequenceFlow> </process> </definitions>
4.2. 結合spring(3.X)配置
配置文件:application-activiti-service.xml
<!-- activiti start --> <!-- 定義 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="activityFontName" value="宋體" /> <property name="labelFontName" value="宋體"/> <property name="idGenerator"><bean class="org.activiti.engine.impl.persistence.StrongUuidGenerator" /></property> </bean> <!-- 定義流程引擎 --> <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration" /> </bean> <!-- 定義流程中使用的對象 --> <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" /> <!-- activiti end -->
4.3. 流程部署
能夠調用原生接口部署流程
RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deployment = repositoryService.createDeployment().addClasspathResource("FinancialReportProcess.bpmn20.xml").deploy();
//還能夠經過字符串,zip 包,inputStream 等方式部署流程
也能夠經過調用下面已抽取好的接口來部署
//@Test public void deployProcess(){ String sourceStr = "C:/WorkSouce/DemoSouce/wef_activiti_demo/src/resource/bpmn/expenseAccount.zip"; workflowService.deploySingleResource(sourceStr, "expenseAccount"); System.out.println("================= deploy success = OK"); }
自動部署
在配置文件application-activiti-service.xml中加入如下配置便可:
<!-- 自動部署開關 --> <property name="deploymentResources" value="classpath*:/autodeployment/*.zip" />
4.4. 權限設計
由於activiti自己也有一套權限模塊,而咱們的業務系統一樣也有一套權限,爲了避免同時去維護兩套權限,咱們在activiti使用之處加入三張權限關聯表,讓activiti使用咱們業務系統的權限。以下:
1 act_re_gillion_link ,任務節點表,能夠動態添加節點
2 act_re_gillion_link_role,節點權限表
3 act_ru_gillion_todo,節點代辦事項表
4.5. 最佳實踐
Activiti自己提供了幾乎全部操做工做流的方法接口,可是爲了統一調用以及後期版本升級,咱們將activiti自帶的方法接口從新抽取成一個服務類WorkflowService供業務系統直接調用。代碼以下:
public interface WorkflowService extends BaseService { //臨時20140504 public String findNextTaskEntity(String CurrTask); /** * 經過當前流程實例ID獲取下一個運行的UserTask * @param procInstID * @return */ public String getNextTaskDefinition(String businessId, Map<String,Object> variables); public SysTodoService getSysTodoService(); public InputStream getCurrResource(String taskId); /* * 自動部署(non-Javadoc) * * @see com.cks.workflow.service.WorkflowService#autoDeployResources() */ public void autoDeployResources(); /* * 部署單個文件(non-Javadoc) * * @see * com.cks.workflow.service.WorkflowService#deploySingleResource(java.lang * .String, java.lang.String) */ public void deploySingleResource(String source, String deployName); /** * V1.0 20140417 Bylinrh 經過流程定義ID獲取流程定義(non-Javadoc) * * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#findProcessDefinitionById(java * .lang.String) */ public ProcessDefinition findProcDefinitionById( String processDefinitionId); /** * V1.0 20140417 Bylinrh 經過流程定義Key獲取最新的流程定義;Key會查詢到全部版本(non-Javadoc) * * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#findProcessDefinitionByKeyToLatest(java * .lang.String) */ public ProcessDefinition findProcDefinitionByKeyToLatest( String processDefinitionKey); /** * V1.0 20140417 Bylinrh 經過流程定義Key及變動,啓動流程定義實例(non-Javadoc) * * @parm processDefitioKey:@leave businessKey :業務主鍵(non-Javadoc) * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#startProcess(java * .lang.String,java.util.Map<String,Object>) */ public ProcessInstance startProcess(String processDefitionKey, Map<String, Object> variables); /* * 進行下一步 用戶節點 * * @parm usertask taskId:任務列表的id (non-Javadoc) * * @see * com.cks.workflow.service.WorkflowService#signalProcess(java.lang.String, * java.util.Map) */ public void signalProcess(String taskId, Map<String, Object> variables); /** * V1.0 20140417 Bylinrh 經過流程實例ID獲取流程實例信息(non-Javadoc) * * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#findProcessInstanceById(java * .lang.String) */ public ProcessInstance findProcInstById(String processInstanceId); /** * V1.0 20140417 Bylinrh 經過節點ID獲取流程實例信息(non-Javadoc) * * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#findProcessInstanceById(java * .lang.String) */ public ProcessInstance findProcInstByTaskId(String taskId); /** * V1.0 20140417 Bylinrh 經過業務ID獲取流程實例信息(non-Javadoc) * * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#findProcessInstanceByBusinessId(java * .lang.String) */ public ProcessInstance findProcInstByBusinessId(String businessId); /** * V1.0 20140417 Bylinrh 經過當前任務ID獲取流程實例實體(non-Javadoc) * * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#findProcDefinitionEntityByTaskId(java * .lang.String) */ public ProcessDefinitionEntity findProcDefinitionEntityByTaskId(String currTaskId); /** * V1.0 20140417 Bylinrh 經過流程實例ID獲取流程實例實體(non-Javadoc) * * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#findProcDefinitionEntityByProcDefId(java * .lang.String) */ public ProcessDefinitionEntity findProcDefinitionEntityByProcDefId(String procDefId); /* * 獲取任務實體(non-Javadoc) * * @see * com.cks.workflow.service.WorkflowService#findTaskEntityById(java.lang.String) */ public TaskEntity findTaskEntityById(String taskId); /* * 獲取活動的流程 不常常使用(non-Javadoc) * * @instanceId 流程ID * * @see * com.cks.workflow.service.WorkflowService#traceProcess(java.lang.String) */ public InputStream getProcessDiagram(String instanceId); /* * 部署單個文件(non-Javadoc) * * @see * com.cks.workflow.service.WorkflowService#deploySingleResource(java.lang * .String, java.lang.String) */ public ActivityImpl traceProcess(String instanceId); /** * V1.0 20140417 Bylinrh 經過當前節點ID獲取當前的流程圖(non-Javadoc) * * @author linrh * @version v1.0 * @see * com.cks.workflow.service.WorkflowService#getCurrTaskImageStream(java * .lang.String) */ public InputStream getCurrTaskImageStream(String taskId); public InputStream getResourceAsStream(String deploymentId, String resourceName); public ExecutionEntity findExecutionEntityByTaskId(String taskId); /* * 經過目錄是部署文件(non-Javadoc) * * @see * com.cks.workflow.service.WorkflowService#deploymentInstance(java.lang * .String) */ public Deployment deploymentInstance(String processFilePath); /** * 查詢全部流程定義(版本爲最新的) * @return List<ProcessDefinition> */ public List<ProcessDefinition> findAllLatestVersionProcessDefinitions(); /** * V1.0 20140417 ByLinrh 根據流程定義Key獲取全部的用戶節點 * @param processDefinitionKey * @return * @author linrh * @version V1.0 */ public List<ActivityImpl> findUserTaskActivityImplByProcessDefinitionKey(String processDefinitionKey); /** * V1.1 20140417 ByLinrh 根據流程定義ID獲取全部的用戶節點 修改方法名稱 * V1.0 20140101 Bybaodk 根據流程定義獲取全部節點 * @param processDefinition * @return * @author baodk * @version V1.1 */ //@Override public List<ActivityImpl> findUserTaskActivityImplByProcessDefinitionId(String processDefinitionId); /** * V1.0 20140417 ByLinrh 根據流程定義Key獲取全部節點 * @param processDefinitionKey * @return * @author linrh * @version V1.0 */ public List<ActivityImpl> findActivityImplByProcessDefinitionKey(String processDefinitionKey); /** * V1.0 20140417 ByLinrh 根據流程定義獲取全部節點 * @param processDefinition * @return * @author linrh * @version V1.0 */ public List<ActivityImpl> findActivityImplByProcessDefinitionId(String processDefinitionId); /* * 查詢流程實例經過id */ public String findCurrentActivitiImplId(String instanceId); /* * 查詢業務id獲取流程實例id */ public String findCurrentActivitiImplIdByBusinessId(String businessId); }
4.5. 單元測試
單元測試包括部署流程、啓動流程、流程審批,以下:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:/spring/*.xml"}) public class DynamicAddProcTest { @Autowired private WorkflowService workflowService; @Autowired private SysTodoService sysTodoService; @Autowired private DynamicActProcService dynamicActProcService; /** * 部署流程 */ public void deployProcess(){ String sourceStr = "C:/WorkSouce/DemoSouce/wef_activiti_demo/src/resource/bpmn/expenseAccount.zip"; workflowService.deploySingleResource(sourceStr, "expenseAccount"); System.out.println("================= deploy success = OK"); } /** * 啓動流程 */ //@Test public void startProcess(){ String startProcessName = "processAuto第一個"; String strBusinessID = UUID.randomUUID().toString(); String strAssignee = "linrh"; Map<String,Object> variables = new HashMap<String,Object>(); variables.put(WorkflowConstants.BUSINESS_ID, strBusinessID); variables.put(WorkflowConstants.ASSIGNEE_USER,strAssignee); ProcessInstance processInstance = workflowService.startProcess(startProcessName,variables); assertNotNull(processInstance); System.out.println("startProcessTaskID == " + processInstance.getId() + " **** BusinessID=" + strBusinessID ); } /** * 流程審批 */ //@Test public void signalProcess(){ //startProcessTaskID == e57806ff-c3a7-11e3-9b1a-e89a8f8209ae **** BusinessID=79dea4e4-0e27-48fb-9bdb-0c633d85d680 String taskID = ""; String strBusinessID = "46903b3b-517b-4e1a-a287-571e5f02e71e"; taskID = workflowService.findCurrentActivitiImplIdByBusinessId(strBusinessID); String taskUuid = ""; ActGillionTodo sysTodo = sysTodoService.findSysTodo(strBusinessID, null); taskUuid = sysTodo.getTaskInstId(); String strAssignee = "linrh"; if(taskUuid != ""){ Map<String,Object> variables = new HashMap<String,Object>(); variables.put(WorkflowConstants.ASSIGNEE_USER,strAssignee); workflowService.signalProcess(taskUuid,variables); } } }
4.7. 兼容低版本的spring(2.5.6)
Activiti 5.1.4默認支持spring3.0以上版本,若是實際項目的spring版本不是3.0以上,則須要作兼容。這裏須要重構processEngineConfiguration,具體實現以下:
1 在配置文件application-activiti-service.xml 的processEngineConfiguration節點下添加如下屬性
<!-- Spring2.5表達式支持 --> <property name="expressionManager"> <bean class="com.gillion.workflow.util.SpringExpressionManagerFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration"></property> </bean> </property>
2 重構processEngineConfiguration
public class SpringExpressionManagerFactoryBean implements FactoryBean { ProcessEngineConfiguration processEngineConfiguration; public Object getObject() throws Exception { return new SpringExpressionManager(ActSpringManager.getApplicationContext(), ((ProcessEngineConfigurationImpl)processEngineConfiguration).getBeans()); } public Class getObjectType() { return SpringExpressionManager.class; } public boolean isSingleton() { return true; } public void setProcessEngineConfiguration( ProcessEngineConfiguration processEngineConfiguration) { this.processEngineConfiguration = processEngineConfiguration; } }
4.8. 動態建立並部署流程
在4.1流程定義裏面咱們能夠經過Eclipse的activiti插件來拖拽節點進行流程定義,另一種方式是根據業務須要,直接採用代碼生成的方式進行動態建立流程。
1. 配置
首先,咱們在activiti配置文件application-activiti-service.xml中配置spring上下文,以便注入到須要動態建立的類當中,以下:
<!-- Spring上下文,主要用於Dynamic Create UserTask Listener --> <bean id="actSpringManager" class="com.gillion.workflow.util.ActSpringManager" scope="singleton"/>
2. 定義接口及實現
先定義動態流程實體,做爲動態建立方法的參數
public class DynamicProcEntity { private String procName; private List<DynamicProcTask> procTasks; /** * 流程名稱 * @return */ public String getProcName() { return procName; } /** * 流程名稱 * @param procName */ public void setProcName(String procName) { this.procName = procName; } /** * 流程節點信息列表 * @return */ public List<DynamicProcTask> getProcTasks() { return procTasks; } /** * 流程節點信息列表 * @param procTasks */ public void setProcTasks(List<DynamicProcTask> procTasks) { this.procTasks = procTasks; } }
定義接口
public interface DynamicActProcService extends BaseService { public void dynamicCreateProcess(DynamicProcEntity procEntity); }
接口實現
public class DynamicActProcServiceImpl extends BaseServiceImpl implements DynamicActProcService { protected Log logger = LogFactory.getLog(getClass()); @Rule public ActivitiRule activitiRule; private ActGillionLinkService actGillionLinkService; private ActGillionLinkRoleService actGillionLinkRoleService; private String procPath = ""; public void dynamicCreateProcess(DynamicProcEntity procEntity){ if(procEntity == null || procEntity.getProcName().equals("") ){ throw new ActivitiException( "請傳入正確的值"); } BpmnModel model = new BpmnModel(); Process process = new Process(); model.addProcess(process); //create process process.setId(procEntity.getProcName()); process.setName(procEntity.getProcName()); //create process node //startevent1 process.addFlowElement(createStartEvent()); //添加用戶節點 for(DynamicProcTask task : procEntity.getProcTasks()){ process.addFlowElement(CreateUserTask(task)); } //endevent1 process.addFlowElement(createEndEvent()); //create process SequenceFlow List<SequenceFlow> addSeqFlows = this.initSequenceFlow(procEntity.getProcTasks()); for(SequenceFlow seqflow : addSeqFlows){ process.addFlowElement(seqflow); } // Generate graphical information new BpmnAutoLayout(model).execute(); /*try {*/ // 3. Deploy the process to the engine String bpmnName = procEntity.getProcName() + ".bpmn"; Deployment deployment = activitiRule.getRepositoryService().createDeployment() .addBpmnModel(bpmnName, model).deploy(); // 4. Start a process instance //ProcessInstance processInstance = activitiRule.getRuntimeService() // .startProcessInstanceByKey(procEntity.getProcName()); ProcessDefinition procDef = activitiRule.getRepositoryService().createProcessDefinitionQuery() .deploymentId(deployment.getId()).singleResult(); //.processDefinitionId(procEntity.getProcName()).latestVersion().singleResult(); String procID = procDef.getId(); ActGillionLink addActGillionLink = null; String linkID = ""; for(DynamicProcTask task : procEntity.getProcTasks()){ addActGillionLink = new ActGillionLink(); addActGillionLink.setActiveId(task.getTaskID()); addActGillionLink.setActiveName(task.getTaskName()); addActGillionLink.setProcessKey(procID); addActGillionLink.setRowStatus(BaseObject.ROWSTATUS_ADDED); linkID = actGillionLinkService.saveOrUpdateLink(addActGillionLink).getLinkId(); String[] roles = task.getAssignee().split(";"); if(roles.length > 0){ ActGillionLinkRole actGillionLinkRole = null; for(String strRoleID : roles){ actGillionLinkRole = new ActGillionLinkRole(); actGillionLinkRole.setLinkId(linkID); actGillionLinkRole.setRoleId(strRoleID); actGillionLinkRole.setRowStatus(BaseObject.ROWSTATUS_ADDED); actGillionLinkRoleService.saveOrUpdateLinkrole(actGillionLinkRole); } } } } /** * 建立用戶節點 * @param procTask * @return */ protected UserTask CreateUserTask(DynamicProcTask procTask) { //添加用戶節點 Listener ActivitiListener listener = new ActivitiListener(); listener.setEvent("create"); //Spring配置以變量形式調用沒法寫入,只能經過繼承TaskListener方法, //By linrh 20140515 listener.setImplementationType("class"); listener.setImplementation("com.workflow.service.impl.TaskExceptionOnCreate"); List<ActivitiListener> actListeners = new ArrayList<ActivitiListener>(); actListeners.add(listener); UserTask userTask = new UserTask(); userTask.setName(procTask.getTaskName()); userTask.setId(procTask.getTaskID()); // userTask.setAssignee(assignee); userTask.setTaskListeners(actListeners); //userTask.setExtensionElements(createElement()); return userTask; } /** * 建立二個節點之間的關鍵節點 * @param from * @param to * @return */ protected SequenceFlow createSequenceFlow(String from, String to) { SequenceFlow flow = new SequenceFlow(); flow.setSourceRef(from); flow.setTargetRef(to); return flow; } /** * 建立開始結點 * @return */ protected StartEvent createStartEvent() { StartEvent startEvent = new StartEvent(); startEvent.setId("startevent1"); startEvent.setName("開始"); return startEvent; } /** * 建立結束節點 * @return */ protected EndEvent createEndEvent() { EndEvent endEvent = new EndEvent(); endEvent.setId("endevent1"); endEvent.setName("結束"); return endEvent; } /** * 經過用戶節點列表添加全部鏈接節點 * @param tasks * @return */ protected List<SequenceFlow> initSequenceFlow(List<DynamicProcTask> tasks){ List<SequenceFlow> workedSeqFlow = new ArrayList<SequenceFlow>(); int i= 0; int lstSize = tasks.size(); String prexTaskid = ""; for(DynamicProcTask task:tasks){ if(i == 0){ workedSeqFlow.add(createSequenceFlow("startevent1", task.getTaskID())); }else if(i == (lstSize - 1)){ workedSeqFlow.add(createSequenceFlow(prexTaskid,task.getTaskID())); workedSeqFlow.add(createSequenceFlow(task.getTaskID(),"endevent1")); }else{ workedSeqFlow.add(createSequenceFlow(prexTaskid,task.getTaskID())); } prexTaskid = task.getTaskID(); i = i + 1; } return workedSeqFlow; } /** * 拆分權限組 * @param linkRoleValue * @return */ private List<String> splitRole(String linkRoleValue){ if(linkRoleValue == ""){ return null; } String[] roles = linkRoleValue.split(";"); List<String> roleLst = new ArrayList<String>(); for(String str : roles){ roleLst.add(str); } return roleLst; } }
3. 單元測試
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:/spring/*.xml"}) public class DynamicProceTest { @Autowired private WorkflowService workflowService; @Autowired private DynamicActProcService dynamicActProcService; /** * 建立流程 */ @Test public void createProcess(){ DynamicProcEntity entity = new DynamicProcEntity(); //entity.se List<DynamicProcTask> taskList = new ArrayList<DynamicProcTask>(); taskList.add(new DynamicProcTask("",1,"task1","我是第一","")); taskList.add(new DynamicProcTask("",2,"task2","我是第二","")); taskList.add(new DynamicProcTask("",3,"task3","我是第三","")); entity.setProcName("processAuto第一個"); entity.setProcTasks(taskList); dynamicActProcService.dynamicCreateProcess(entity); } }