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.  流程定义

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <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">
  3. <process id="expenseAccount" name="expenseAccount" isExecutable="true">
  4. <startEvent id="startevent1" name="开始"></startEvent>
  5. <userTask id="usertask1" name="部门经理">
  6. <extensionElements>
  7. <activiti:taskListener event="create" expression="${todoListService.createToDoList(task,execution)}"></activiti:taskListener>
  8. </extensionElements>
  9. </userTask>
  10. <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
  11. <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
  12. <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="exclusivegateway1"></sequenceFlow>
  13. <userTask id="usertask2" name="公司副总审批">
  14. <extensionElements>
  15. <activiti:taskListener event="create" expression="${todoListService.createToDoList(task,execution)}"></activiti:taskListener>
  16. </extensionElements>
  17. </userTask>
  18. <exclusiveGateway id="exclusivegateway2" name="Exclusive Gateway"></exclusiveGateway>
  19. <sequenceFlow id="flow4" sourceRef="usertask2" targetRef="exclusivegateway2"></sequenceFlow>
  20. <userTask id="usertask3" name="财务审批">
  21. <extensionElements>
  22. <activiti:taskListener event="create" expression="${todoListService.createToDoList(task,execution)}"></activiti:taskListener>
  23. </extensionElements>
  24. </userTask>
  25. <sequenceFlow id="flow5" name="同意" sourceRef="exclusivegateway2" targetRef="usertask3">
  26. <conditionExpression xsi:type="tFormalExpression"><![CDATA[${AssistantCEOPass}]]></conditionExpression>
  27. </sequenceFlow>
  28. <exclusiveGateway id="exclusivegateway3" name="Exclusive Gateway"></exclusiveGateway>
  29. <sequenceFlow id="flow6" name="同意" sourceRef="exclusivegateway1" targetRef="exclusivegateway3">
  30. <conditionExpression xsi:type="tFormalExpression"><![CDATA[${managerPass}]]></conditionExpression>
  31. </sequenceFlow>
  32. <sequenceFlow id="flow7" name="价格大于10000" sourceRef="exclusivegateway3" targetRef="usertask2">
  33. <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money > 10000}]]></conditionExpression>
  34. </sequenceFlow>
  35. <endEvent id="endevent1" name="End"></endEvent>
  36. <sequenceFlow id="flow8" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
  37. <sequenceFlow id="flow9" name="拒绝" sourceRef="exclusivegateway1" targetRef="endevent1">
  38. <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!managePass}]]></conditionExpression>
  39. </sequenceFlow>
  40. <sequenceFlow id="flow10" name="价格小于10001" sourceRef="exclusivegateway3" targetRef="usertask3">
  41. <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 10000}]]></conditionExpression>
  42. </sequenceFlow>
  43. <sequenceFlow id="flow11" name="拒绝" sourceRef="exclusivegateway2" targetRef="endevent1">
  44. <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!AssistantCEOPass}]]></conditionExpression>
  45. </sequenceFlow>
  46. </process>
  47. </definitions>

4.2.  结合spring(3.X)配置

配置文件:application-activiti-service.xml

  1. <!-- activiti start -->
  2.  
  3. <!-- 定义 Activiti 配置 -->
  4. <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
  5. <property name="dataSource" ref="dataSource" />
  6. <property name="transactionManager" ref="transactionManager" />
  7. <property name="databaseSchemaUpdate" value="true" />
  8.  
  9. <property name="jobExecutorActivate" value="false" />
  10. <property name="activityFontName" value="宋体" />
  11. <property name="labelFontName" value="宋体"/>
  12. <property name="idGenerator"><bean class="org.activiti.engine.impl.persistence.StrongUuidGenerator" /></property>
  13. </bean>
  14.  
  15. <!-- 定义流程引擎 -->
  16. <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
  17. <property name="processEngineConfiguration" ref="processEngineConfiguration" />
  18. </bean>
  19.  
  20. <!-- 定义流程中使用的对象 -->
  21. <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
  22. <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
  23. <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
  24. <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
  25. <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
  26.  
  27. <!-- activiti end -->

4.3.  流程部署

可以调用原生接口部署流程

  1. RepositoryService repositoryService = processEngine.getRepositoryService();
  2. Deployment deployment = repositoryService.createDeployment().addClasspathResource("FinancialReportProcess.bpmn20.xml").deploy();
    //还可以通过字符串,zip 包,inputStream 等方式部署流程

也可以通过调用下面已抽取好的接口来部署

  1. //@Test
  2. public void deployProcess(){
  3. String sourceStr = "C:/WorkSouce/DemoSouce/wef_activiti_demo/src/resource/bpmn/expenseAccount.zip";
  4. workflowService.deploySingleResource(sourceStr, "expenseAccount");
  5. System.out.println("================= deploy success = OK");
  6. }

自动部署

在配置文件application-activiti-service.xml中加入以下配置即可:

  1. <!-- 自动部署开关 -->
  2. <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供业务系统直接调用。代码如下:

  1. public interface WorkflowService extends BaseService {
  2. //临时20140504
  3. public String findNextTaskEntity(String CurrTask);
  4. /**
  5. * 通过当前流程实例ID获取下一个运行的UserTask
  6. * @param procInstID
  7. * @return
  8. */
  9. public String getNextTaskDefinition(String businessId, Map<String,Object> variables);
  10.  
  11. public SysTodoService getSysTodoService();
  12.  
  13. public InputStream getCurrResource(String taskId);
  14. /*
  15. * 自动部署(non-Javadoc)
  16. *
  17. * @see com.cks.workflow.service.WorkflowService#autoDeployResources()
  18. */
  19. public void autoDeployResources();
  20. /*
  21. * 部署单个文件(non-Javadoc)
  22. *
  23. * @see
  24. * com.cks.workflow.service.WorkflowService#deploySingleResource(java.lang
  25. * .String, java.lang.String)
  26. */
  27. public void deploySingleResource(String source, String deployName);
  28. /**
  29. * V1.0 20140417 Bylinrh 通过流程定义ID获取流程定义(non-Javadoc)
  30. *
  31. * @author linrh
  32. * @version v1.0
  33. * @see
  34. * com.cks.workflow.service.WorkflowService#findProcessDefinitionById(java
  35. * .lang.String)
  36. */
  37. public ProcessDefinition findProcDefinitionById(
  38. String processDefinitionId);
  39. /**
  40. * V1.0 20140417 Bylinrh 通过流程定义Key获取最新的流程定义;Key会查询到所有版本(non-Javadoc)
  41. *
  42. * @author linrh
  43. * @version v1.0
  44. * @see
  45. * com.cks.workflow.service.WorkflowService#findProcessDefinitionByKeyToLatest(java
  46. * .lang.String)
  47. */
  48. public ProcessDefinition findProcDefinitionByKeyToLatest(
  49. String processDefinitionKey);
  50. /**
  51. * V1.0 20140417 Bylinrh 通过流程定义Key及变更,启动流程定义实例(non-Javadoc)
  52. *
  53. * @parm processDefitioKey:@leave businessKey :业务主键(non-Javadoc)
  54. * @author linrh
  55. * @version v1.0
  56. * @see
  57. * com.cks.workflow.service.WorkflowService#startProcess(java
  58. * .lang.String,java.util.Map<String,Object>)
  59. */
  60. public ProcessInstance startProcess(String processDefitionKey,
  61. Map<String, Object> variables);
  62.  
  63. /*
  64. * 进行下一步 用户节点
  65. *
  66. * @parm usertask taskId:任务列表的id (non-Javadoc)
  67. *
  68. * @see
  69. * com.cks.workflow.service.WorkflowService#signalProcess(java.lang.String,
  70. * java.util.Map)
  71. */
  72. public void signalProcess(String taskId, Map<String, Object> variables);
  73.  
  74. /**
  75. * V1.0 20140417 Bylinrh 通过流程实例ID获取流程实例信息(non-Javadoc)
  76. *
  77. * @author linrh
  78. * @version v1.0
  79. * @see
  80. * com.cks.workflow.service.WorkflowService#findProcessInstanceById(java
  81. * .lang.String)
  82. */
  83. public ProcessInstance findProcInstById(String processInstanceId);
  84. /**
  85. * V1.0 20140417 Bylinrh 通过节点ID获取流程实例信息(non-Javadoc)
  86. *
  87. * @author linrh
  88. * @version v1.0
  89. * @see
  90. * com.cks.workflow.service.WorkflowService#findProcessInstanceById(java
  91. * .lang.String)
  92. */
  93. public ProcessInstance findProcInstByTaskId(String taskId);
  94. /**
  95. * V1.0 20140417 Bylinrh 通过业务ID获取流程实例信息(non-Javadoc)
  96. *
  97. * @author linrh
  98. * @version v1.0
  99. * @see
  100. * com.cks.workflow.service.WorkflowService#findProcessInstanceByBusinessId(java
  101. * .lang.String)
  102. */
  103. public ProcessInstance findProcInstByBusinessId(String businessId);
  104. /**
  105. * V1.0 20140417 Bylinrh 通过当前任务ID获取流程实例实体(non-Javadoc)
  106. *
  107. * @author linrh
  108. * @version v1.0
  109. * @see
  110. * com.cks.workflow.service.WorkflowService#findProcDefinitionEntityByTaskId(java
  111. * .lang.String)
  112. */
  113. public ProcessDefinitionEntity findProcDefinitionEntityByTaskId(String currTaskId);
  114. /**
  115. * V1.0 20140417 Bylinrh 通过流程实例ID获取流程实例实体(non-Javadoc)
  116. *
  117. * @author linrh
  118. * @version v1.0
  119. * @see
  120. * com.cks.workflow.service.WorkflowService#findProcDefinitionEntityByProcDefId(java
  121. * .lang.String)
  122. */
  123. public ProcessDefinitionEntity findProcDefinitionEntityByProcDefId(String procDefId);
  124. /*
  125. * 获取任务实体(non-Javadoc)
  126. *
  127. * @see
  128. * com.cks.workflow.service.WorkflowService#findTaskEntityById(java.lang.String)
  129. */
  130. public TaskEntity findTaskEntityById(String taskId);
  131. /*
  132. * 获取活动的流程 不经常使用(non-Javadoc)
  133. *
  134. * @instanceId 流程ID
  135. *
  136. * @see
  137. * com.cks.workflow.service.WorkflowService#traceProcess(java.lang.String)
  138. */
  139. public InputStream getProcessDiagram(String instanceId);
  140.  
  141. /*
  142. * 部署单个文件(non-Javadoc)
  143. *
  144. * @see
  145. * com.cks.workflow.service.WorkflowService#deploySingleResource(java.lang
  146. * .String, java.lang.String)
  147. */
  148. public ActivityImpl traceProcess(String instanceId);
  149.  
  150. /**
  151. * V1.0 20140417 Bylinrh 通过当前节点ID获取当前的流程图(non-Javadoc)
  152. *
  153. * @author linrh
  154. * @version v1.0
  155. * @see
  156. * com.cks.workflow.service.WorkflowService#getCurrTaskImageStream(java
  157. * .lang.String)
  158. */
  159. public InputStream getCurrTaskImageStream(String taskId);
  160.  
  161. public InputStream getResourceAsStream(String deploymentId,
  162. String resourceName);
  163.  
  164. public ExecutionEntity findExecutionEntityByTaskId(String taskId);
  165.  
  166. /*
  167. * 通过目录是部署文件(non-Javadoc)
  168. *
  169. * @see
  170. * com.cks.workflow.service.WorkflowService#deploymentInstance(java.lang
  171. * .String)
  172. */
  173. public Deployment deploymentInstance(String processFilePath);
  174.  
  175. /**
  176. * 查询所有流程定义(版本为最新的)
  177. * @return List<ProcessDefinition>
  178. */
  179. public List<ProcessDefinition> findAllLatestVersionProcessDefinitions();
  180.  
  181. /**
  182. * V1.0 20140417 ByLinrh 根据流程定义Key获取所有的用户节点
  183. * @param processDefinitionKey
  184. * @return
  185. * @author linrh
  186. * @version V1.0
  187. */
  188. public List<ActivityImpl> findUserTaskActivityImplByProcessDefinitionKey(String processDefinitionKey);
  189. /**
  190. * V1.1 20140417 ByLinrh 根据流程定义ID获取所有的用户节点 修改方法名称
  191. * V1.0 20140101 Bybaodk 根据流程定义获取所有节点
  192. * @param processDefinition
  193. * @return
  194. * @author baodk
  195. * @version V1.1
  196. */
  197. //@Override
  198. public List<ActivityImpl> findUserTaskActivityImplByProcessDefinitionId(String processDefinitionId);
  199.  
  200. /**
  201. * V1.0 20140417 ByLinrh 根据流程定义Key获取所有节点
  202. * @param processDefinitionKey
  203. * @return
  204. * @author linrh
  205. * @version V1.0
  206. */
  207. public List<ActivityImpl> findActivityImplByProcessDefinitionKey(String processDefinitionKey);
  208.  
  209. /**
  210. * V1.0 20140417 ByLinrh 根据流程定义获取所有节点
  211. * @param processDefinition
  212. * @return
  213. * @author linrh
  214. * @version V1.0
  215. */
  216. public List<ActivityImpl> findActivityImplByProcessDefinitionId(String processDefinitionId);
  217. /*
  218. * 查询流程实例通过id
  219. */
  220. public String findCurrentActivitiImplId(String instanceId);
  221.  
  222. /*
  223. * 查询业务id获取流程实例id
  224. */
  225. public String findCurrentActivitiImplIdByBusinessId(String businessId);
  226. }

4.5.  单元测试

单元测试包括部署流程、启动流程、流程审批,如下:

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(locations={"classpath:/spring/*.xml"})
  3. public class DynamicAddProcTest {
  4.  
  5. @Autowired
  6. private WorkflowService workflowService;
  7. @Autowired
  8. private SysTodoService sysTodoService;
  9. @Autowired
  10. private DynamicActProcService dynamicActProcService;
  11.  
  12. /**
  13. * 部署流程
  14. */
  15. public void deployProcess(){
  16. String sourceStr = "C:/WorkSouce/DemoSouce/wef_activiti_demo/src/resource/bpmn/expenseAccount.zip";
  17. workflowService.deploySingleResource(sourceStr, "expenseAccount");
  18. System.out.println("================= deploy success = OK");
  19. }
  20.  
  21. /**
  22. * 启动流程
  23. */
  24. //@Test
  25. public void startProcess(){
  26. String startProcessName = "processAuto第一个";
  27. String strBusinessID = UUID.randomUUID().toString();
  28. String strAssignee = "linrh";
  29.  
  30. Map<String,Object> variables = new HashMap<String,Object>();
  31. variables.put(WorkflowConstants.BUSINESS_ID, strBusinessID);
  32. variables.put(WorkflowConstants.ASSIGNEE_USER,strAssignee);
  33. ProcessInstance processInstance = workflowService.startProcess(startProcessName,variables);
  34. assertNotNull(processInstance);
  35.  
  36. System.out.println("startProcessTaskID == " + processInstance.getId() + " **** BusinessID=" + strBusinessID );
  37. }
  38.  
  39. /**
  40. * 流程审批
  41. */
  42. //@Test
  43. public void signalProcess(){
  44. //startProcessTaskID == e57806ff-c3a7-11e3-9b1a-e89a8f8209ae **** BusinessID=79dea4e4-0e27-48fb-9bdb-0c633d85d680
  45. String taskID = "";
  46. String strBusinessID = "46903b3b-517b-4e1a-a287-571e5f02e71e";
  47. taskID = workflowService.findCurrentActivitiImplIdByBusinessId(strBusinessID);
  48. String taskUuid = "";
  49.  
  50. ActGillionTodo sysTodo = sysTodoService.findSysTodo(strBusinessID, null);
  51. taskUuid = sysTodo.getTaskInstId();
  52.  
  53. String strAssignee = "linrh";
  54.  
  55. if(taskUuid != ""){
  56.  
  57. Map<String,Object> variables = new HashMap<String,Object>();
  58. variables.put(WorkflowConstants.ASSIGNEE_USER,strAssignee);
  59. workflowService.signalProcess(taskUuid,variables);
  60. }
  61.  
  62. }
  63. }

4.7. 兼容低版本的spring(2.5.6)

Activiti 5.1.4默认支持spring3.0以上版本,如果实际项目的spring版本不是3.0以上,则需要做兼容。这里需要重构processEngineConfiguration,具体实现如下:

1 在配置文件application-activiti-service.xml 的processEngineConfiguration节点下添加以下属性

  1. <!-- Spring2.5表达式支持 -->
  2. <property name="expressionManager">
  3. <bean class="com.gillion.workflow.util.SpringExpressionManagerFactoryBean">
  4. <property name="processEngineConfiguration" ref="processEngineConfiguration"></property>
  5. </bean>
  6. </property>

2 重构processEngineConfiguration

  1. public class SpringExpressionManagerFactoryBean implements FactoryBean {
  2.  
  3. ProcessEngineConfiguration processEngineConfiguration;
  4.  
  5. public Object getObject() throws Exception {
  6.  
  7. return new SpringExpressionManager(ActSpringManager.getApplicationContext(), ((ProcessEngineConfigurationImpl)processEngineConfiguration).getBeans());
  8. }
  9.  
  10. public Class getObjectType() {
  11. return SpringExpressionManager.class;
  12. }
  13.  
  14. public boolean isSingleton() {
  15. return true;
  16. }
  17.  
  18. public void setProcessEngineConfiguration(
  19. ProcessEngineConfiguration processEngineConfiguration) {
  20. this.processEngineConfiguration = processEngineConfiguration;
  21. }
  22. }

4.8. 动态创建并部署流程

在4.1流程定义里面我们可以通过Eclipse的activiti插件来拖拽节点进行流程定义,另外一种方式是根据业务需要,直接采用代码生成的方式进行动态创建流程。

1.  配置

首先,我们在activiti配置文件application-activiti-service.xml中配置spring上下文,以便注入到需要动态创建的类当中,如下:

  1. <!-- Spring上下文,主要用于Dynamic Create UserTask Listener -->
  2. <bean id="actSpringManager" class="com.gillion.workflow.util.ActSpringManager" scope="singleton"/>

2.  定义接口及实现

先定义动态流程实体,作为动态创建方法的参数

  1. public class DynamicProcEntity {
  2.  
  3. private String procName;
  4.  
  5. private List<DynamicProcTask> procTasks;
  6.  
  7. /**
  8. * 流程名称
  9. * @return
  10. */
  11. public String getProcName() {
  12. return procName;
  13. }
  14.  
  15. /**
  16. * 流程名称
  17. * @param procName
  18. */
  19. public void setProcName(String procName) {
  20. this.procName = procName;
  21. }
  22.  
  23. /**
  24. * 流程节点信息列表
  25. * @return
  26. */
  27. public List<DynamicProcTask> getProcTasks() {
  28. return procTasks;
  29. }
  30.  
  31. /**
  32. * 流程节点信息列表
  33. * @param procTasks
  34. */
  35. public void setProcTasks(List<DynamicProcTask> procTasks) {
  36. this.procTasks = procTasks;
  37. }
  38.  
  39. }

定义接口

  1. public interface DynamicActProcService extends BaseService {
  2.  
  3. public void dynamicCreateProcess(DynamicProcEntity procEntity);
  4. }

接口实现

  1. public class DynamicActProcServiceImpl extends BaseServiceImpl implements
  2. DynamicActProcService {
  3.  
  4. protected Log logger = LogFactory.getLog(getClass());
  5.  
  6. @Rule
  7. public ActivitiRule activitiRule;
  8.  
  9. private ActGillionLinkService actGillionLinkService;
  10. private ActGillionLinkRoleService actGillionLinkRoleService;
  11.  
  12. private String procPath = "";
  13.  
  14. public void dynamicCreateProcess(DynamicProcEntity procEntity){
  15. if(procEntity == null || procEntity.getProcName().equals("") ){
  16. throw new ActivitiException(
  17. "请传入正确的值");
  18. }
  19.  
  20. BpmnModel model = new BpmnModel();
  21. Process process = new Process();
  22. model.addProcess(process);
  23.  
  24. //create process
  25. process.setId(procEntity.getProcName());
  26. process.setName(procEntity.getProcName());
  27.  
  28. //create process node
  29. //startevent1
  30. process.addFlowElement(createStartEvent());
  31. //添加用户节点
  32. for(DynamicProcTask task : procEntity.getProcTasks()){
  33. process.addFlowElement(CreateUserTask(task));
  34. }
  35. //endevent1
  36. process.addFlowElement(createEndEvent());
  37.  
  38. //create process SequenceFlow
  39.  
  40. List<SequenceFlow> addSeqFlows = this.initSequenceFlow(procEntity.getProcTasks());
  41. for(SequenceFlow seqflow : addSeqFlows){
  42. process.addFlowElement(seqflow);
  43. }
  44.  
  45. // Generate graphical information
  46. new BpmnAutoLayout(model).execute();
  47.  
  48. /*try {*/
  49.  
  50. // 3. Deploy the process to the engine
  51. String bpmnName = procEntity.getProcName() + ".bpmn";
  52. Deployment deployment = activitiRule.getRepositoryService().createDeployment()
  53. .addBpmnModel(bpmnName, model).deploy();
  54.  
  55. // 4. Start a process instance
  56. //ProcessInstance processInstance = activitiRule.getRuntimeService()
  57. // .startProcessInstanceByKey(procEntity.getProcName());
  58.  
  59. ProcessDefinition procDef = activitiRule.getRepositoryService().createProcessDefinitionQuery()
  60. .deploymentId(deployment.getId()).singleResult();
  61. //.processDefinitionId(procEntity.getProcName()).latestVersion().singleResult();
  62.  
  63. String procID = procDef.getId();
  64.  
  65. ActGillionLink addActGillionLink = null;
  66. String linkID = "";
  67. for(DynamicProcTask task : procEntity.getProcTasks()){
  68. addActGillionLink = new ActGillionLink();
  69. addActGillionLink.setActiveId(task.getTaskID());
  70. addActGillionLink.setActiveName(task.getTaskName());
  71. addActGillionLink.setProcessKey(procID);
  72. addActGillionLink.setRowStatus(BaseObject.ROWSTATUS_ADDED);
  73.  
  74. linkID = actGillionLinkService.saveOrUpdateLink(addActGillionLink).getLinkId();
  75. String[] roles = task.getAssignee().split(";");
  76. if(roles.length > 0){
  77. ActGillionLinkRole actGillionLinkRole = null;
  78. for(String strRoleID : roles){
  79. actGillionLinkRole = new ActGillionLinkRole();
  80. actGillionLinkRole.setLinkId(linkID);
  81. actGillionLinkRole.setRoleId(strRoleID);
  82. actGillionLinkRole.setRowStatus(BaseObject.ROWSTATUS_ADDED);
  83.  
  84. actGillionLinkRoleService.saveOrUpdateLinkrole(actGillionLinkRole);
  85. }
  86. }
  87.  
  88. }
  89. }
  90. /**
  91. * 创建用户节点
  92. * @param procTask
  93. * @return
  94. */
  95. protected UserTask CreateUserTask(DynamicProcTask procTask) {
  96. //添加用户节点 Listener
  97. ActivitiListener listener = new ActivitiListener();
  98. listener.setEvent("create");
  99. //Spring配置以变量形式调用无法写入,只能通过继承TaskListener方法,
  100. //By linrh 20140515
  101. listener.setImplementationType("class");
  102. listener.setImplementation("com.workflow.service.impl.TaskExceptionOnCreate");
  103.  
  104. List<ActivitiListener> actListeners = new ArrayList<ActivitiListener>();
  105. actListeners.add(listener);
  106.  
  107. UserTask userTask = new UserTask();
  108. userTask.setName(procTask.getTaskName());
  109. userTask.setId(procTask.getTaskID());
  110. // userTask.setAssignee(assignee);
  111. userTask.setTaskListeners(actListeners);
  112. //userTask.setExtensionElements(createElement());
  113. return userTask;
  114. }
  115.  
  116. /**
  117. * 创建二个节点之间的关键节点
  118. * @param from
  119. * @param to
  120. * @return
  121. */
  122. protected SequenceFlow createSequenceFlow(String from, String to) {
  123. SequenceFlow flow = new SequenceFlow();
  124. flow.setSourceRef(from);
  125. flow.setTargetRef(to);
  126. return flow;
  127. }
  128.  
  129. /**
  130. * 创建开始结点
  131. * @return
  132. */
  133. protected StartEvent createStartEvent() {
  134. StartEvent startEvent = new StartEvent();
  135. startEvent.setId("startevent1");
  136. startEvent.setName("开始");
  137. return startEvent;
  138. }
  139.  
  140. /**
  141. * 创建结束节点
  142. * @return
  143. */
  144. protected EndEvent createEndEvent() {
  145. EndEvent endEvent = new EndEvent();
  146. endEvent.setId("endevent1");
  147. endEvent.setName("结束");
  148. return endEvent;
  149. }
  150.  
  151. /**
  152. * 通过用户节点列表添加所有连接节点
  153. * @param tasks
  154. * @return
  155. */
  156. protected List<SequenceFlow> initSequenceFlow(List<DynamicProcTask> tasks){
  157. List<SequenceFlow> workedSeqFlow = new ArrayList<SequenceFlow>();
  158.  
  159. int i= 0;
  160. int lstSize = tasks.size();
  161. String prexTaskid = "";
  162.  
  163. for(DynamicProcTask task:tasks){
  164. if(i == 0){
  165. workedSeqFlow.add(createSequenceFlow("startevent1", task.getTaskID()));
  166. }else if(i == (lstSize - 1)){
  167. workedSeqFlow.add(createSequenceFlow(prexTaskid,task.getTaskID()));
  168. workedSeqFlow.add(createSequenceFlow(task.getTaskID(),"endevent1"));
  169. }else{
  170. workedSeqFlow.add(createSequenceFlow(prexTaskid,task.getTaskID()));
  171. }
  172. prexTaskid = task.getTaskID();
  173. i = i + 1;
  174. }
  175.  
  176. return workedSeqFlow;
  177. }
  178.  
  179. /**
  180. * 拆分权限组
  181. * @param linkRoleValue
  182. * @return
  183. */
  184. private List<String> splitRole(String linkRoleValue){
  185. if(linkRoleValue == ""){
  186. return null;
  187. }
  188.  
  189. String[] roles = linkRoleValue.split(";");
  190. List<String> roleLst = new ArrayList<String>();
  191. for(String str : roles){
  192. roleLst.add(str);
  193. }
  194.  
  195. return roleLst;
  196. }
  197. }

3.  单元测试

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(locations={"classpath:/spring/*.xml"})
  3. public class DynamicProceTest {
  4.  
  5. @Autowired
  6. private WorkflowService workflowService;
  7.  
  8. @Autowired
  9. private DynamicActProcService dynamicActProcService;
  10.  
  11. /**
  12. * 创建流程
  13. */
  14. @Test
  15. public void createProcess(){
  16. DynamicProcEntity entity = new DynamicProcEntity();
  17. //entity.se
  18. List<DynamicProcTask> taskList = new ArrayList<DynamicProcTask>();
  19. taskList.add(new DynamicProcTask("",1,"task1","我是第一",""));
  20. taskList.add(new DynamicProcTask("",2,"task2","我是第二",""));
  21. taskList.add(new DynamicProcTask("",3,"task3","我是第三",""));
  22.  
  23. entity.setProcName("processAuto第一个");
  24. entity.setProcTasks(taskList);
  25.  
  26. dynamicActProcService.dynamicCreateProcess(entity);
  27.  
  28. }
  29. }

Activiti 5.1.4最佳实践的更多相关文章

  1. ASP.NET跨平台最佳实践

    前言 八年的坚持敌不过领导的固执,最终还是不得不阔别已经成为我第二语言的C#,转战Java阵营.有过短暂的失落和迷茫,但技术转型真的没有想象中那么难.回头审视,其实单从语言本身来看,C#确实比Java ...

  2. 《AngularJS深度剖析与最佳实践》简介

    由于年末将至,前阵子一直忙于工作的事务,不得已暂停了微信订阅号的更新,我将会在后续的时间里尽快的继续为大家推送更多的博文.毕竟一个人的力量微薄,精力有限,希望大家能理解,仍然能一如既往的关注和支持sh ...

  3. ASP.NET MVC防范CSRF最佳实践

    XSS与CSRF 哈哈,有点标题党,但我保证这篇文章跟别的不太一样. 我认为,网站安全的基础有三块: 防范中间人攻击 防范XSS 防范CSRF 注意,我讲的是基础,如果更高级点的话可以考虑防范机器人刷 ...

  4. 快速web开发中的前后端框架选型最佳实践

    这个最佳实践是我目前人在做的一个站点,主要功能: oauth登录 发布文章(我称为"片段"),片段可以自定义一些和内容有关的指标,如“文中人物:12”.支持自定义排版.插图.建立相 ...

  5. Spring Batch在大型企业中的最佳实践

    在大型企业中,由于业务复杂.数据量大.数据格式不同.数据交互格式繁杂,并非所有的操作都能通过交互界面进行处理.而有一些操作需要定期读取大批量的数据,然后进行一系列的后续处理.这样的过程就是" ...

  6. Atitit.log日志技术的最佳实践attilax总结

    Atitit.log日志技术的最佳实践attilax总结 1. 日志的意义与作用1 1.1. 日志系统是一种不可或缺的单元测试,跟踪调试工具1 2. 俩种实现[1]日志系统作为一种服务进程存在 [2] ...

  7. PHP核心技术与最佳实践——全局浏览

    难得买到并喜欢一本好书,‘PHP核心技术与最佳实践’. 几天时间,先看了个大概,总结一下整体是什么样子的,怎么看怎么学. 1.总共14章: 2.第1.2章讲PHP的OOP: 其中第一章侧重于PHP的O ...

  8. Abp集成Swagger的最佳实践

    1.在项目中添加nuget包 Abp.Web.Api.SwaggerTool 2.在项目Abp模块的DependsOn添加AbpWebApiSwaggerToolModule Run It,启动项目, ...

  9. MySQL · 答疑解惑 · MySQL 锁问题最佳实践

    http://mysql.taobao.org/monthly/2016/03/10/ 前言 最近一段时间处理了较多锁的问题,包括锁等待导致业务连接堆积或超时,死锁导致业务失败等,这类问题对业务可能会 ...

随机推荐

  1. sql 表连接基本的语法

    SQL连接能够分为内连接.外连接.交叉连接. 1.内连接:内连接查询操作列出与连接条件匹配的数据行,它使用比較运算符比較被连接列的列值. 1.1 select * from Table1 as a, ...

  2. android开发(30) 使用WebView,点击网页中的链接建立QQ 临时会话 WPA

    在PC端,我们可以通过一个URL链接,点击后启动QQ,这是很好的用户跳转体验.很方便. 使用的链接如下: <a target="_blank" href="http ...

  3. 如何在Linux系统上安装字体

    libreoffice添加字体 TrueType字体文件的扩展名是.ttf,ttf就是TrueType Font的首字母缩写 一般在 /usr/share/fonts/truetype/ 目录下,这个 ...

  4. Textrank权值提取文本标签提取:

    Textrank权值提取文本标签提取: 我已经爬取到了指定博主的新浪微博,然后我想从微博中提取出可以代表该博主兴趣特征的100个关键词,然后由这100个关键词提取出10个标签,代表博主的兴趣.我们此处 ...

  5. USB2.0学习笔记连载(十):关于WIN8及以上系统哈希值问题

    笔者上一篇博客讲解了关于驱动的安装,笔者使用的系统是win8.1系统,那么对于win8系统及以上系统,会对外部设备,没有在windows系统中进行签名过的,都是不允许在windows系统中进行安装的, ...

  6. Eclipse导入到web项目没有run on server

    由于以前的项目都是用myeclipse开发的,现在要换成eclipse来开发.但是项目导入到eclipse中发现该项目并不是web项目,也不能部署到tomcat里面去. 现在解决了这个问题了.     ...

  7. (笔记)Linux下的ioctl()函数详解

    我这里说的ioctl函数是指驱动程序里的,因为我不知道还有没有别的场合用到了它,所以就规定了我们讨论的范围.写这篇文章是因为我前一阵子被ioctl给搞混了,这几天才弄明白它,于是在这里清理一下头脑. ...

  8. Yum 安装并设置 MySQL

    本质上都是设置一个yum源,然后yum安装即可.   不过添加yum源有两个方法,一种是自己新建一个 /etc/yum.repos.d/mysql-community.repo :另一种是使用MySQ ...

  9. MySQL迁移数据库(mysqldump)

    一.导出导入所有数据库的数据 1.导出 mysqldump -u root -p123456 --all-databases > all.sql 2.导入 mysql -u root -p123 ...

  10. 使用Maven构建项目

    要构建一个基于Maven的项目,打开控制台,进入到 pom.xml 文件所放的项目文件夹,并发出以下命令: mvn package 这将执行Maven的“package”阶段. Maven构建生命周期 ...