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. SQL Server 2012 自动增长列,值跳跃问题(自增增加1000)

    介绍 从 SQL Server 2012 版本开始, 当SQL Server 实例重启之后,表格的自动增长列的值会发生跳跃,而具体的跳跃值的大小是根据增长列的数据类型而定的.如果数据类型是 整型(in ...

  2. STM32的TAMPER-RTC管脚作为Tamper的使用[转]

    问题一: 当 TAMPER引脚上的信号从 0变成1或者从 1变成 0(取决于备份控制寄存器BKP_CR的 TPAL位),会产生一个侵入检测事件.侵入检测事件将所有数据备份寄存器内容清除.   然而为了 ...

  3. css实现圆形头像

    <div style="width:400px; height:90px; padding-left:10px; padding-top:10px; background-color: ...

  4. MySQL递归查询树状表的子节点、父节点

    表结构和表数据就不公示了,查询的表user_role,主键是id,每条记录有parentid字段; 如下mysql查询函数即可实现根据一个节点查询所有的子节点,根据一个子节点查询所有的父节点.对于数据 ...

  5. 自然语言交流系统 phxnet团队 创新实训 项目博客 (十一)

    神经网络的计算过程 神经网络结构如下图所示,最左边的是输入层,最右边的是输出层,中间是多个隐含层,隐含层和输出层的每个神经节点,都是由上一层节点乘以其权重累加得到,标上“+1”的圆圈为截距项b,对输入 ...

  6. moodle中的完形填空题的文本编写方法

    moodle中的完形填空题的文本编写方法 [完形填空题]考题把一段文字挖去一些空,让考生根据上下文正确地完成这些填空.完型填空题中的一段短文可以包括各种题目,如选择,填空,和数字题等. 题目的编辑是在 ...

  7. Android Error: This attribute must be localized.

    在android中使用mmm命令编译程序是出现错误. 这种问题一般情况是因为在res/xml文件夹下的中, 或者在res/layout下的文件中出现了没有多语言话的文本例. 解决方法: 不直接在布局文 ...

  8. JUnit规则

    在本节中,我们学习和了解JUnit中叫做规则的新功能,它允许非常灵活在测试类重新定义每个测试方法的行为.为了这个目的,@Rule注解被使用来标出测试类的公共字段.这些字段类型为MethodRule,这 ...

  9. perl学习(二)正则表达式

    模式分组: /fred+/会匹配freddd这样的 /(fred)+/会匹配fredfredfred这样的 /(fred)*/则会匹配abcdef任意的 圆括号同时也使得重新使用某些字符串成为可能.反 ...

  10. unity-------------UI的界面调节

    Rect Transform 我们都知道,Unity3D中所有的GameObject都必须要携带一个Transform组件,且该组件无法移除,那么作为UI显示的GameObject则不是携带Trans ...