因工作需要,本人现在在学习Flowable工作流。此处将自己学习和测试通过的demo展示给大家,希望对同为初学者的你有所帮助。
对于什么是工作流,flowable和activiti的区别,各位可自行百度,此处不再赘述。
直接上demo:
1、环境搭建:jdk1.8+maven+eclipse
创建标准的maven项目,项目框架截图如下:
2、添加相关依赖:pom.xml
<!-- https://mvnrepository.com/artifact/org.flowable/flowable-engine -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>6.5.0</version>
</dependency>
<dependency>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.10</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<!-- 使用h2数据库,方便测试-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.197</version>
</dependency>
3、使用flowable插件创建mywork.bpmn文件(因篇幅问题,只贴关键代码),flowable插件安装请自行百度
mywork.png如下:
mywork.bpmn:
<process id="mywork" name="二级审批流程" isExecutable="true"> <startEvent id="startEvent" name="开始"></startEvent> <userTask id="userDev" name="申请审批流程"> <extensionElements> <activiti:formProperty id="message" name="申请信息" type="string" required="true"></activiti:formProperty> <activiti:formProperty id="name" name="申请人" type="string" required="true"></activiti:formProperty> <activiti:formProperty id="submitTime" name="提交时间" type="date" datePattern="yyyy-MM-dd" required="true"></activiti:formProperty> <activiti:formProperty id="submitType" name="确认申请" type="string" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="userDev"></sequenceFlow> <exclusiveGateway id="Dev_exclusivegateway" name="确认提交"></exclusiveGateway> <sequenceFlow id="flow2" sourceRef="userDev" targetRef="Dev_exclusivegateway"></sequenceFlow> <userTask id="userTL" name="主管审批"> <extensionElements> <activiti:formProperty id="TLApprove" name="主管审批结果" type="string" required="true"></activiti:formProperty> <activiti:formProperty id="TLMessage" name="主管备注" type="string" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow3" sourceRef="Dev_exclusivegateway" targetRef="userTL"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${submitType == "y" || submitType =="Y"}]]></conditionExpression> </sequenceFlow> <endEvent id="endEvent" name="结束"></endEvent> <exclusiveGateway id="TL_exclusivegateway" name="主管审批结果"></exclusiveGateway> <sequenceFlow id="flow8" sourceRef="userTL" targetRef="TL_exclusivegateway"></sequenceFlow> <userTask id="userHR" name="人事审批"> <extensionElements> <activiti:formProperty id="HRApprove" name="人事审批结果" type="string" required="true"></activiti:formProperty> <activiti:formProperty id="HRMessage" name="人事审批备注" type="string" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow9" sourceRef="TL_exclusivegateway" targetRef="userHR"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${TLApprove == "y" || TLApprove =="Y"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow11" sourceRef="TL_exclusivegateway" targetRef="userDev"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${TLApprove == "N" || TLApprove =="n"}]]></conditionExpression> </sequenceFlow> <exclusiveGateway id="HR_exclusivegateway" name="人事审批结果"></exclusiveGateway> <sequenceFlow id="flow12" sourceRef="userHR" targetRef="HR_exclusivegateway"></sequenceFlow> <endEvent id="endEvent1" name="取消"></endEvent> <sequenceFlow id="flow13" sourceRef="HR_exclusivegateway" targetRef="endEvent1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${HRApprove == "y" || HRApprove =="Y"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow14" sourceRef="HR_exclusivegateway" targetRef="userDev"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${HRApprove == "n" || HRApprove =="N"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow15" sourceRef="Dev_exclusivegateway" targetRef="endEvent1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${submitType == "n" || submitType =="N"}]]></conditionExpression> </sequenceFlow> </process>
4、创建主运行类:DemoMain.java
package com.lx.activiti.helloworld; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Scanner; import org.flowable.engine.FormService; import org.flowable.engine.ProcessEngine; import org.flowable.engine.ProcessEngineConfiguration; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.form.FormProperty; import org.flowable.engine.form.TaskFormData; import org.flowable.engine.impl.form.DateFormType; import org.flowable.engine.impl.form.StringFormType; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Maps; /** * 启动类 * @author * */ public class DemoMain { private static final Logger logger = LoggerFactory.getLogger(DemoMain.class); public static void main(String[] args) throws ParseException { logger.info("启动程序"); //抽取各步骤作为方法调用 //1. 创建流程引擎 ProcessEngine processEngine = getProcessEngine(); //2. 部署流程文件 ProcessDefinition processDefinition = getDeployment(processEngine); //3. 启动运行流程 ProcessInstance processInstance =getProcessInstance(processEngine, processDefinition); //4. 处理流程任务 //控制台输入 Scanner scanner = new Scanner(System.in); //判断,当流程实例不为空,且流程没有结束时 while (processInstance!=null && !processInstance.isEnded()) { //获取任务服务组件 TaskService taskService = processEngine.getTaskService(); //创建任务查询,将结果放入list集合中 List<Task> list = taskService.createTaskQuery().list(); logger.info("待处理任务数量: [{}]",list.size()); //遍历list集合 for (Task task : list) { logger.info("待处理任务: [{}]",task.getName()); //获取表单服务组件 FormService formService = processEngine.getFormService(); //获取表单内容的集合formProperties TaskFormData taskFormData = formService.getTaskFormData(task.getId()); List<FormProperty> formProperties = taskFormData.getFormProperties(); HashMap<String, Object> variables = Maps.newHashMap(); String line = null; //遍历formProperties for (FormProperty property : formProperties) { //判断,如果表单中定义的是字符串类型变量,则按该格式输入 if (StringFormType.class.isInstance(property.getType())) { logger.info("请输入 {} ?",property.getName()); line = scanner.nextLine(); variables.put(property.getId(), line); //判断,如果表单中定义的是日期类型变量,按日期格式输入 }else if(DateFormType.class.isInstance(property.getType())) { logger.info("请输入 {} ? 格式 (yyyy-MM-dd)",property.getName()); line = scanner.nextLine(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date = dateFormat.parse(line); variables.put(property.getId(), date); }else { logger.info("类型暂不支持 {} ",property.getType()); } logger.info("你输入的是[{}]",line); } taskService.complete(task.getId(),variables); processInstance = processEngine.getRuntimeService() .createProcessInstanceQuery() .processInstanceId(processInstance.getId()) .singleResult(); } } logger.info("结束程序"); } /** * 3. 获取流程实例:ProcessInstance,启动运行流程 * @param processEngine * @param processDefinition * @return ProcessInstance */ public static ProcessInstance getProcessInstance(ProcessEngine processEngine, ProcessDefinition processDefinition) { //获取运行服务 RuntimeService runtimeService = processEngine.getRuntimeService(); //传入流程定义文件id,调用startProcessInstanceById(),获取流程实例 ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId()); //获取流程部定义文件的key值 logger.info("启动流程[ {}]",processInstance.getProcessDefinitionKey()); return processInstance; } /** * 2 . 获取流程定义文件:ProcessDefinition , 部署流程 * @param processEngine * @return ProcessDefinition */ public static ProcessDefinition getDeployment(ProcessEngine processEngine) { //通过引擎获取仓储服务 RepositoryService repositoryService = processEngine.getRepositoryService(); //通过仓储服务链式调用,部署流程 Deployment deploy = repositoryService.createDeployment()//得到流程部署 .addClasspathResource("diagrams/mywork.bpmn")//加载资源 .deploy();//部署流程 String deployId = deploy.getId(); //获取流程定义文件:processDefinition ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()//创建流程定义文件查询 .deploymentId(deployId)//传入流程部署ID .singleResult();//根据查询条件;到数据库中查询唯一的数据记录,如果没有,则为空,如果有多条,则抛出异常 logger.info("流程定义文件: [ {}] ,流程id: [{}]",processDefinition.getName(),processDefinition.getId()); return processDefinition; } /** * 1. 创建流程引擎 * @return ProcessEngine */ public static ProcessEngine getProcessEngine() { //获取流程配置文件 ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration(); //通过流程文件创建引擎 ProcessEngine processEngine = cfg.buildProcessEngine(); String name = processEngine.getName(); String version = processEngine.VERSION; logger.info("流程引擎名称{},版本 [{}]}", name, version); return processEngine; } }
5、运行该类,截取部分测试结果如下图: