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/ 前言 最近一段时间处理了较多锁的问题,包括锁等待导致业务连接堆积或超时,死锁导致业务失败等,这类问题对业务可能会 ...
随机推荐
- SQL Server 2012 自动增长列,值跳跃问题(自增增加1000)
介绍 从 SQL Server 2012 版本开始, 当SQL Server 实例重启之后,表格的自动增长列的值会发生跳跃,而具体的跳跃值的大小是根据增长列的数据类型而定的.如果数据类型是 整型(in ...
- STM32的TAMPER-RTC管脚作为Tamper的使用[转]
问题一: 当 TAMPER引脚上的信号从 0变成1或者从 1变成 0(取决于备份控制寄存器BKP_CR的 TPAL位),会产生一个侵入检测事件.侵入检测事件将所有数据备份寄存器内容清除. 然而为了 ...
- css实现圆形头像
<div style="width:400px; height:90px; padding-left:10px; padding-top:10px; background-color: ...
- MySQL递归查询树状表的子节点、父节点
表结构和表数据就不公示了,查询的表user_role,主键是id,每条记录有parentid字段; 如下mysql查询函数即可实现根据一个节点查询所有的子节点,根据一个子节点查询所有的父节点.对于数据 ...
- 自然语言交流系统 phxnet团队 创新实训 项目博客 (十一)
神经网络的计算过程 神经网络结构如下图所示,最左边的是输入层,最右边的是输出层,中间是多个隐含层,隐含层和输出层的每个神经节点,都是由上一层节点乘以其权重累加得到,标上“+1”的圆圈为截距项b,对输入 ...
- moodle中的完形填空题的文本编写方法
moodle中的完形填空题的文本编写方法 [完形填空题]考题把一段文字挖去一些空,让考生根据上下文正确地完成这些填空.完型填空题中的一段短文可以包括各种题目,如选择,填空,和数字题等. 题目的编辑是在 ...
- Android Error: This attribute must be localized.
在android中使用mmm命令编译程序是出现错误. 这种问题一般情况是因为在res/xml文件夹下的中, 或者在res/layout下的文件中出现了没有多语言话的文本例. 解决方法: 不直接在布局文 ...
- JUnit规则
在本节中,我们学习和了解JUnit中叫做规则的新功能,它允许非常灵活在测试类重新定义每个测试方法的行为.为了这个目的,@Rule注解被使用来标出测试类的公共字段.这些字段类型为MethodRule,这 ...
- perl学习(二)正则表达式
模式分组: /fred+/会匹配freddd这样的 /(fred)+/会匹配fredfredfred这样的 /(fred)*/则会匹配abcdef任意的 圆括号同时也使得重新使用某些字符串成为可能.反 ...
- unity-------------UI的界面调节
Rect Transform 我们都知道,Unity3D中所有的GameObject都必须要携带一个Transform组件,且该组件无法移除,那么作为UI显示的GameObject则不是携带Trans ...