当前位置:   article > 正文

springboot特殊问题处理2——springboot集成flowable实现工作流程的完整教程(一)_flowable-spring-boot-starter-process

flowable-spring-boot-starter-process

在实际项目开发过程中,流程相关的业务实现采用工作流会异常清晰明了,但是Activity学习成本和开发难度对追求效率的开发工作者来说异常繁琐,但是作为Activity的亲儿子之一的flowable,其轻量化的使用和对应的api会让开发者感受简单,学习成本很低,值得推荐。

本文案基于springboot2.3.12为例讲解,jdk版本要求至少1.8+,mysql为8.0以上。

一.flowable相关官方网址

官方网站(英文):https://www.flowable.com/

第三方中文用户手册(V6.3.0):https://tkjohn.github.io/flowable-userguide/

二.如何集成springboot

1.引入官方jar或者对应springboot的starter
  1. <dependency>
  2. <groupId>org.flowable</groupId>
  3. <artifactId>flowable-spring-boot-starter</artifactId>
  4. <version>${flowable.version}</version>
  5. </dependency>

我这边根据项目需要只引入相关的flowable-engine

  1. <dependency>
  2. <groupId>org.flowable</groupId>
  3. <artifactId>flowable-engine</artifactId>
  4. <version>6.3.0</version>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.mybatis</groupId>
  8. <artifactId>mybatis</artifactId>
  9. </exclusion>
  10. <exclusion>
  11. <groupId>mysql</groupId>
  12. <artifactId>mysql-connector-java</artifactId>
  13. </exclusion>
  14. </exclusions>
  15. </dependency>
2. 配置项目需要的数据
  • flowable.properties
  1. flowable.url=jdbc:mysql://10.1.0.223:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT&nullCatalogMeansCurrent=true
  2. flowable.username=root
  3. flowable.password=123456
  4. flowable.driverClassName=com.mysql.cj.jdbc.Driver
  5. ###生成数据表
  6. flowable.initialize=true
  7. flowable.name=flowable
  8. ###动态生成流程执行图(定义中文字体为宋体,防止生成的图片资源存在乱码)
  9. flowable.activityFontName=\u5B8B\u4F53
  10. flowable.labelFontName=\u5B8B\u4F53
  11. flowable.annotationFontName=\u5B8B\u4F53
  12. flowable.xml.encoding=UTF-8
  • 项目结构如下 (待补充)

  • 测试需要的流程图 

 

三.flowable项目正确开发使用流程

1.首先正确配置flowable.properties该文件,默认在启动项目时会生成34张工作流数据表(均已ACT_开头)

2.利用tomcat启动flowable-admin.war,然后用flowable-ui创建对应的bpm文件(或者其他的bpm工具)

3.调用相关部署接口,部署已经写好的流程实例,参数参照后台方法说明传递即可
4.分别查看act_re_deployment,act_re_procdef和act_ge_bytearray数据表,如果生成了相关数据即代表部署成功

5.最后就可以在相关模块创建任务开始动态执行流程

四.flowable流程业务实现以及部分关键代码展示

以下关键代码,需要特意说明的是:

  • ProcessEngine是flowable提供对公开BPM和工作流操作的所有服务的访问关键对象。
  • FlowProcessDiagramGenerator是flowable生成流程实例图片的关键,继承自
    org.flowable.image.impl.DefaultProcessDiagramGenerator类
1.流程部署
  1. /**
  2. * 1.部署流程
  3. *
  4. * @return
  5. */
  6. @GetMapping("/deployment")
  7. public String deploymentFlowable() {
  8. RepositoryService repositoryService = processEngine.getRepositoryService();
  9. Deployment deployment = repositoryService.createDeployment()
  10. .addClasspathResource("flowable_xml/test_flowable.bpmn20.xml")
  11. //类别
  12. .category("审批类")
  13. .name("领导审批")
  14. .deploy();
  15. return ResponseResult.ok(deployment);
  16. }
2. 查询流程定义
  1. /**
  2. * 2.查询流程定义
  3. *
  4. * @return
  5. */
  6. @GetMapping("/queryDeployment")
  7. public String queryFlowableDeploy() {
  8. RepositoryService repositoryService = processEngine.getRepositoryService();
  9. //查询所有定义的流程
  10. List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
  11. //查询单个定义的流程
  12. /*ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
  13. .deploymentId("5")
  14. .singleResult();*/
  15. // System.out.println("Found process definition : " + processDefinition.getName());
  16. return ResponseResult.ok(list);
  17. }
3.启动流程实例
  1. /**
  2. * 3.启动流程实例
  3. *
  4. * @return
  5. */
  6. @RequestMapping("/start/instance")
  7. public String startProcessInstance() {
  8. RuntimeService runtimeService = processEngine.getRuntimeService();
  9. //要启动流程实例,需要提供一些初始化流程变量,自定义
  10. Map<String, Object> variables = new HashMap<String, Object>(0);
  11. variables.put("employee", "工作组");
  12. variables.put("nrOfHolidays", 8);
  13. variables.put("description", "请假");
  14. ProcessInstance processInstance =
  15. runtimeService.startProcessInstanceByKey("leader_approval_key", variables);
  16. return ResponseResult.ok(processInstance.getName());
  17. }
4.通过流程执行人员查询任务和流程变量
  1. /**
  2. * 通过流程人员定义查询任务和流程变量
  3. *
  4. * @return
  5. */
  6. @RequestMapping("/query/task")
  7. public String queryProcessInstance() {
  8. TaskService taskService = processEngine.getTaskService();
  9. //通过组查询任务表
  10. // List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
  11. //通过人查询单个任务
  12. Task task = taskService.createTaskQuery().taskAssignee("小王").singleResult();
  13. //通过任务id查询流程变量
  14. Map<String, Object> processVariables = taskService.getVariables(task.getId());
  15. return ResponseResult.ok(processVariables);
  16. }
5.通过任务id完成任务
  1. /**
  2. * 通过任务id完成任务
  3. *
  4. * @return
  5. */
  6. @RequestMapping("/complete/task")
  7. public String completeTask(String taskId) {
  8. TaskService taskService = processEngine.getTaskService();
  9. //领导审批提交的表达信息
  10. Map<String, Object> variables = new HashMap<String, Object>(0);
  11. taskService.complete(taskId, variables);
  12. return ResponseResult.ok();
  13. }
 6.通过流程执行人或者审批人查询审批历史记录
  1. /**
  2. * 通过审批人获取历史任务数据
  3. *
  4. * @param name
  5. * @return
  6. */
  7. @RequestMapping("/history/task")
  8. public String getHistoryTask(@RequestParam("name") String name) {
  9. HistoryService historyService = processEngine.getHistoryService();
  10. //历史任务流程——流程id
  11. List<HistoricActivityInstance> activities =
  12. historyService.createHistoricActivityInstanceQuery()
  13. .processInstanceId("2501")
  14. .finished()
  15. .orderByHistoricActivityInstanceEndTime().asc()
  16. .list();
  17. //历史任务
  18. List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().taskAssignee(name).list();
  19. return ResponseResult.ok(list.toString());
  20. }
 7.通过流程id查询流程执行图(多种获取方式)
  1. /**
  2. * 通过流程id获取流程资源
  3. *
  4. * @return
  5. */
  6. @RequestMapping("/process/resource")
  7. public void getProcessResource(HttpServletResponse response) throws IOException {
  8. RepositoryService repositoryService = processEngine.getRepositoryService();
  9. /*ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
  10. .deploymentId("5085")
  11. .processDefinitionId("defect_report_flowable:1:5088")
  12. // .processDefinitionKey("leader_approval_key")
  13. // .deploymentId("5")
  14. .singleResult();*/
  15. BpmnModel bpmnModel = repositoryService.getBpmnModel("defect_report_flowable:1:4");
  16. InputStream imageStream = processDiagramGenerator.generateDiagram(bpmnModel);
  17. /*String diagramResourceName = processDefinition.getDiagramResourceName();
  18. InputStream imageStream = repositoryService.getResourceAsStream(
  19. processDefinition.getDeploymentId(), diagramResourceName);*/
  20. FileOutputStream fos = new FileOutputStream("D:\\data\\22222.png");
  21. byte[] b = new byte[1024];
  22. int leng = -1;
  23. while ((leng = imageStream.read(b)) != -1) {
  24. fos.write(b, 0, leng);
  25. }
  26. fos.flush();
  27. imageStream.close();
  28. fos.close();
  29. /*
  30. //文件流直接写出
  31. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  32. OutputStream os = response.getOutputStream();
  33. int ch = 0;
  34. while (-1 != (ch = imageStream.read())) {
  35. baos.write(ch);
  36. }
  37. os.write(baos.toByteArray());
  38. imageStream.close();
  39. baos.close();
  40. os.close();*/
  41. }

五.其他相关的功能和问题持续更新,有问题私信 

1.生成流程实例图片的关键代码
  1. @Service
  2. public class FlowProcessDiagramGenerator extends DefaultProcessDiagramGenerator {
  3. private static final String IMAGE_TYPE = "png";
  4. @Value("${flowable.activityFontName}")
  5. private String activityFontName;
  6. @Value("${flowable.labelFontName}")
  7. private String labelFontName;
  8. @Value("${flowable.annotationFontName}")
  9. private String annotationFontName;
  10. @Value("${flowable.xml.encoding}")
  11. private String encoding;
  12. @Autowired
  13. private ProcessEngine processEngine;
  14. /**
  15. * 生成执行动态图片流
  16. *
  17. * @param processDefinitionId 流程定义的id——xml文件规固定的key
  18. * @param businessKey
  19. * @return
  20. */
  21. public InputStream generateActiveDiagram(String processDefinitionId, String businessKey) {
  22. RuntimeService runtimeService = processEngine.getRuntimeService();
  23. HistoryService historyService = processEngine.getHistoryService();
  24. RepositoryService repositoryService = processEngine.getRepositoryService();
  25. //1.获取当前的流程定义
  26. ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
  27. .processDefinitionId(processDefinitionId)
  28. // .processInstanceId(processInstanceId)
  29. .processInstanceBusinessKey(businessKey)
  30. .singleResult();
  31. //流程实例执行的实例id
  32. String processId = null;
  33. List<String> activeActivityIds = new ArrayList<>();
  34. List<String> highLightedFlows = new ArrayList<>();
  35. //3. 获取流程定义id和高亮的节点id
  36. if (processInstance != null) {
  37. //3.1. 正在运行的流程实例
  38. processId = processInstance.getProcessInstanceId();
  39. //2.获取所有的历史轨迹线对象
  40. List<HistoricActivityInstance> historicSquenceFlows = historyService.createHistoricActivityInstanceQuery()
  41. // .processDefinitionId(processInstanceId)
  42. .processInstanceId(processId)
  43. .activityType(BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)
  44. .list();
  45. historicSquenceFlows.forEach(historicActivityInstance -> highLightedFlows.add(historicActivityInstance.getActivityId()));
  46. activeActivityIds = runtimeService.getActiveActivityIds(processId);
  47. } else {
  48. //3.2. 已经结束的流程实例
  49. HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
  50. .processDefinitionId(processDefinitionId)
  51. // .processInstanceId(processId)
  52. .processInstanceBusinessKey(businessKey)
  53. .singleResult();
  54. if(historicProcessInstance == null){
  55. throw new MessageCodeException(MessageCode.FLOWABLE_PROCESS_IS_RELEASE_SUCCESS);
  56. }
  57. processId = historicProcessInstance.getId();
  58. //3.3. 获取结束节点列表
  59. List<HistoricActivityInstance> historicEnds = historyService.createHistoricActivityInstanceQuery()
  60. .processInstanceId(processId)
  61. .activityType(BpmnXMLConstants.ELEMENT_EVENT_END).list();
  62. List<String> finalActiveActivityIds = activeActivityIds;
  63. historicEnds.forEach(historicActivityInstance -> finalActiveActivityIds.add(historicActivityInstance.getActivityId()));
  64. }
  65. //4. 获取bpmnModel对象
  66. BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
  67. //模型 活动节点 高亮线
  68. return generateDiagram(bpmnModel, IMAGE_TYPE, activeActivityIds,
  69. highLightedFlows, activityFontName, labelFontName, annotationFontName,
  70. null, 1.0);
  71. }
  72. /**
  73. * 生成工作流程图
  74. *
  75. * @param bpmnModel 模型
  76. * @return
  77. */
  78. public InputStream generateDiagram(BpmnModel bpmnModel) {
  79. return generateDiagram(bpmnModel, IMAGE_TYPE, activityFontName,
  80. labelFontName, annotationFontName,
  81. null, 1.0);
  82. }
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号