1、简单介绍
Activiti是一个开源的工作流引擎,它实现了BPMN 2.0规范,可以发布设计好的流程定义,并通过api进行流程调度。
Activiti 作为一个遵从 Apache 许可的工作流和业务流程管理开源平台,其核心是基于 Java 的超快速、超稳定的 BPMN 2.0 流程引擎,强调流程服务的可嵌入性和可扩展性,同时更加强调面向业务人员。
Activiti 流程引擎重点关注在系统开发的易用性和轻量性上。每一项 BPM 业务功能 Activiti 流程引擎都以服务的形式提供给开发人员。通过使用这些服务,开发人员能够构建出功能丰富、轻便且高效的 BPM 应用程序。
2、Activiti 的持久化方式
Activiti 使用 Mybatis3 做持久化工作,可以在配置中设置流程引擎启动时创建表。
Activiti 使用到的表都是 ACT_开头的。
ACT_RE_*:流程定义存储。
ACT_RU_*:流程执行记录,记录流程启动到结束的所有动作,流程结束后会清除相关记录。
ACT_ID_*:用户记录,流程中使用到的用户和组。
ACT_HI_*:流程执行的历史记录。
ACT_GE_*:通用数据及设置。
使用到的表:
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:执行中的变量记录。
3、名词解释
关键对象
Deployment:流程部署对象,部署一个流程是创建。
ProcessDefinitions:流程定义,部署成功后自动创建。
ProcessInstances:流程实例,启动流程是创建。
Task:任务,在 Activiti 中的 Task 仅指有角色参与的任务,即定义中的 UserTask。
Execution:执行计划,流程实例和流程执行中的所有节点都是 Execution,如 UserTask、ServiceTask 等。
服务接口
ProcessEngine:流程引擎接口,提供流程管理和运作的所有接口。
RuntimeService:运行时服务接口,提供流程启动服务,运行中流程查询,运行变量设置和获取。
TaskService:用户任务接口(UserTask) ,提供运行时任务查询、领取、完成、删除及变量设置用户管理等服务。
IdentityService:用户和组管理接口。
ManagementService:流程引擎管理接口。
HistoryService:流程处理查询接口,包括执行中流程查询和历史流程查询。
4、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); } }