Activiti 5.1.4最佳实践
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最佳实践的更多相关文章
- ASP.NET跨平台最佳实践
前言 八年的坚持敌不过领导的固执,最终还是不得不阔别已经成为我第二语言的C#,转战Java阵营.有过短暂的失落和迷茫,但技术转型真的没有想象中那么难.回头审视,其实单从语言本身来看,C#确实比Java ...
- 《AngularJS深度剖析与最佳实践》简介
由于年末将至,前阵子一直忙于工作的事务,不得已暂停了微信订阅号的更新,我将会在后续的时间里尽快的继续为大家推送更多的博文.毕竟一个人的力量微薄,精力有限,希望大家能理解,仍然能一如既往的关注和支持sh ...
- ASP.NET MVC防范CSRF最佳实践
XSS与CSRF 哈哈,有点标题党,但我保证这篇文章跟别的不太一样. 我认为,网站安全的基础有三块: 防范中间人攻击 防范XSS 防范CSRF 注意,我讲的是基础,如果更高级点的话可以考虑防范机器人刷 ...
- 快速web开发中的前后端框架选型最佳实践
这个最佳实践是我目前人在做的一个站点,主要功能: oauth登录 发布文章(我称为"片段"),片段可以自定义一些和内容有关的指标,如“文中人物:12”.支持自定义排版.插图.建立相 ...
- Spring Batch在大型企业中的最佳实践
在大型企业中,由于业务复杂.数据量大.数据格式不同.数据交互格式繁杂,并非所有的操作都能通过交互界面进行处理.而有一些操作需要定期读取大批量的数据,然后进行一系列的后续处理.这样的过程就是" ...
- Atitit.log日志技术的最佳实践attilax总结
Atitit.log日志技术的最佳实践attilax总结 1. 日志的意义与作用1 1.1. 日志系统是一种不可或缺的单元测试,跟踪调试工具1 2. 俩种实现[1]日志系统作为一种服务进程存在 [2] ...
- PHP核心技术与最佳实践——全局浏览
难得买到并喜欢一本好书,‘PHP核心技术与最佳实践’. 几天时间,先看了个大概,总结一下整体是什么样子的,怎么看怎么学. 1.总共14章: 2.第1.2章讲PHP的OOP: 其中第一章侧重于PHP的O ...
- Abp集成Swagger的最佳实践
1.在项目中添加nuget包 Abp.Web.Api.SwaggerTool 2.在项目Abp模块的DependsOn添加AbpWebApiSwaggerToolModule Run It,启动项目, ...
- MySQL · 答疑解惑 · MySQL 锁问题最佳实践
http://mysql.taobao.org/monthly/2016/03/10/ 前言 最近一段时间处理了较多锁的问题,包括锁等待导致业务连接堆积或超时,死锁导致业务失败等,这类问题对业务可能会 ...
随机推荐
- jQuery笔记二——基础/动画
1. jQuery的基础语法: $(selector).action() 2. 很多jQuery的语句放在ready里面 $(document).ready(function(){ // jQuery ...
- awk和sed (十二)
[教程主题]:4.awk和sed [主要内容] [1]awk AWK是贝尔实验室1977年搞出来的文本出现神器.之所以叫AWK是因为其取了三位创始人 Alfred Aho,Peter Weinberg ...
- WPF中ComboBox使用
1.数据绑定 前台代码: <ComboBox Height="23" HorizontalAlignment="Left" Margin="86 ...
- 关于Unity3D中鼠标移动指定物体的解决方案
一.鼠标拾取物体的原理 在Unity3D当中,想要在观察面(Aspect)中拾取物体(有碰撞属性)的方法一般如下: 1.声明一个观察的摄像机.一个从摄像机原点出发的射线Ray以及一个用于检测碰撞的Ra ...
- win10 + linux 制作双系统教程(我本身是win10系统)
1.制作启动U盘 准备工作: .linux镜像 .硬盘空余空间>8G,越大越好 .制作启动U盘的软件 .最好3.0U盘一个>4G 下载启动软件的工具(UItraIOS制作的U盘启动盘无法安 ...
- Android wpa_supplicant 启动过程
记录wpa_supplicant启动过程 ini脚本: service wpa_supplicant /vendor/bin/hw/wpa_supplicant \ -ip2p0 -Dnl80211 ...
- Maven是一个项目管理工具
Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Depen ...
- erlang 二进制中 拼接 变量或者函数 报错
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVsAAACiCAIAAABgR/nfAAAM5ElEQVR4nO2dzZrcKBJF9Zjd/tnOdN
- 互联网公司GitHub repo 语言使用情况
转自: https://laike9m.com/blog/hu-lian-wang-gong-si-github-repo-yu-yan-shi-yong-qing-kuang,56/ 现在基本上所有 ...
- mysql错误代码对照表较完整 mysql_errno()
From: http://blog.csdn.net/aidenliu/article/details/5925604 mysql错误代码对照表较完整 0101 属于其他进程的专用标志. 0102 ...