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); }
}

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. jQuery笔记二——基础/动画

    1. jQuery的基础语法: $(selector).action() 2. 很多jQuery的语句放在ready里面 $(document).ready(function(){ // jQuery ...

  2. awk和sed (十二)

    [教程主题]:4.awk和sed [主要内容] [1]awk AWK是贝尔实验室1977年搞出来的文本出现神器.之所以叫AWK是因为其取了三位创始人 Alfred Aho,Peter Weinberg ...

  3. WPF中ComboBox使用

    1.数据绑定 前台代码: <ComboBox Height="23" HorizontalAlignment="Left" Margin="86 ...

  4. 关于Unity3D中鼠标移动指定物体的解决方案

    一.鼠标拾取物体的原理 在Unity3D当中,想要在观察面(Aspect)中拾取物体(有碰撞属性)的方法一般如下: 1.声明一个观察的摄像机.一个从摄像机原点出发的射线Ray以及一个用于检测碰撞的Ra ...

  5. win10 + linux 制作双系统教程(我本身是win10系统)

    1.制作启动U盘 准备工作: .linux镜像 .硬盘空余空间>8G,越大越好 .制作启动U盘的软件 .最好3.0U盘一个>4G 下载启动软件的工具(UItraIOS制作的U盘启动盘无法安 ...

  6. Android wpa_supplicant 启动过程

    记录wpa_supplicant启动过程 ini脚本: service wpa_supplicant /vendor/bin/hw/wpa_supplicant \ -ip2p0 -Dnl80211 ...

  7. Maven是一个项目管理工具

    Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Depen ...

  8. erlang 二进制中 拼接 变量或者函数 报错

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVsAAACiCAIAAABgR/nfAAAM5ElEQVR4nO2dzZrcKBJF9Zjd/tnOdN

  9. 互联网公司GitHub repo 语言使用情况

    转自: https://laike9m.com/blog/hu-lian-wang-gong-si-github-repo-yu-yan-shi-yong-qing-kuang,56/ 现在基本上所有 ...

  10. mysql错误代码对照表较完整 mysql_errno()

    From: http://blog.csdn.net/aidenliu/article/details/5925604 mysql错误代码对照表较完整  0101 属于其他进程的专用标志. 0102 ...