如何使用 SpringBoot flowable 来整合工作流开发

简介: 我是小假 期待与你的下一次相遇 ~

1、相关依赖

  1. <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
  2. <dependency>
  3.  <groupId>io.springfox</groupId>
  4.  <artifactId>springfox-swagger2</artifactId>
  5.  <version>2.9.2</version>
  6. </dependency>
  7. <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
  8. <dependency>
  9.  <groupId>io.springfox</groupId>
  10.  <artifactId>springfox-swagger-ui</artifactId>
  11.  <version>2.9.2</version>
  12. </dependency>
  13. <!-- https://mvnrepository.com/artifact/com.github.xiaoymin/swagger-bootstrap-ui -->
  14. <dependency>
  15.  <groupId>com.github.xiaoymin</groupId>
  16.  <artifactId>swagger-bootstrap-ui</artifactId>
  17.  <version>1.8.5</version>
  18. </dependency>
  19. <dependency>
  20.  <groupId>com.alibaba</groupId>
  21.  <artifactId>druid-spring-boot-starter</artifactId>
  22.  <version>1.1.13</version>
  23. </dependency>
  24. <dependency>
  25.  <groupId>mysql</groupId>
  26.  <artifactId>mysql-connector-java</artifactId>
  27.  <version>8.0.19</version>
  28. </dependency>
  29. <dependency>
  30.  <groupId>org.flowable</groupId>
  31.  <artifactId>flowable-spring-boot-starter</artifactId>
  32.  <version>6.5.0</version>
  33. </dependency>

2、flowable以及数据库的配置

  1. mysql:
  2.  url: jdbc:mysql:///test?serverTimezone=UTC
  3.  username: root
  4.  password: 123456
  5.  driverClassName: com.mysql.cj.jdbc.Driver
  6. spring:
  7.  application:
  8.    name: ServiceActiviti
  9.  datasource:
  10.    type: com.alibaba.druid.pool.DruidDataSource
  11.    url: ${mysql.url}
  12.    driver-class-name: ${mysql.driverClassName}
  13.    username: ${mysql.username}
  14.    password: ${mysql.password}
  15.    druid: # #
  16.      url: ${mysql.url}
  17.      username: ${mysql.username}
  18.      password: ${mysql.password}
  19.      driver-class-name: ${mysql.driverClassName}
  20.      initial-size: 10
  21.      max-active: 200
  22.      min-idle: 10
  23.      max-wait: 60000
  24.      pool-prepared-statements: false
  25.      validation-query: SELECT 1 FROM DUAL
  26.      test-on-borrow: false
  27.      test-on-return: false
  28.      test-while-idle: true
  29.      time-between-eviction-runs-millis: 60000
  30.      min-evictable-idle-time-millis: 30000
  31.      max-pool-prepared-statement-per-connection-size: 20
  32.      aop-patterns: com.msyyt.crm.activity.*
  33.      filter: # 状态监控
  34.        stat:
  35.          enabled: true
  36.          db-type: mysql
  37.          log-slow-sql: true
  38.          slow-sql-millis: 2000
  39.      web-stat-filter: # 监控过滤器
  40.        enabled: true #是否启用 默认true
  41.        exclusions:
  42.          - '*.js'
  43.          - '*.gif'
  44.          - '*.jpg'
  45.          - '*.png'
  46.          - '*.css'
  47.          - '*.ico'
  48.          - /druid/*
  49.      stat-view-servlet: # druid 监控页面
  50.        enabled: true
  51.        url-pattern: /druid/*
  52.        reset-enable: false
  53.        allow:  # 白名单
  54.        deny:   # 黑名单
  55.        login-username: admin
  56.        login-password:  admin
  57. # 工作流
  58. flowable:
  59.  #关闭定时任务JOB
  60.  async-executor-activate: false
  61.  #  将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
  62.  database-schema-update: true

3、运行项目生成数据库表

4、定义标准的BPMN流程文件ExpenseProcess.bpmn20.xml放至resource目录下新建processes目录下

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.             xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
  4.             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
  5.             typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath"
  6.             targetNamespace="http://www.flowable.org/processdef">
  7.    <process id="Expense" name="ExpenseProcess" isExecutable="true">
  8.        <documentation>报销流程</documentation>
  9.        <startEvent id="start" name="开始"></startEvent>
  10.        <userTask id="fillTask" name="出差报销" flowable:assignee="${taskUser}">
  11.            <extensionElements>
  12.                <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler">
  13.                    <![CDATA[false]]></modeler:initiator-can-complete>
  14.            </extensionElements>
  15.        </userTask>
  16.        <exclusiveGateway id="judgeTask"></exclusiveGateway>
  17.        <userTask id="directorTak" name="经理审批">
  18.            <extensionElements>
  19.                <flowable:taskListener event="create"
  20.                                       class="com.fcant.service_flowable.handler.ManagerTaskHandler"></flowable:taskListener>
  21.            </extensionElements>
  22.        </userTask>
  23.        <userTask id="bossTask" name="老板审批">
  24.            <extensionElements>
  25.                <flowable:taskListener event="create"
  26.                                       class="com.fcant.service_flowable.handler.BossTaskHandler"></flowable:taskListener>
  27.            </extensionElements>
  28.        </userTask>
  29.        <endEvent id="end" name="结束"></endEvent>
  30.        <sequenceFlow id="directorNotPassFlow" name="驳回" sourceRef="directorTak" targetRef="fillTask">
  31.            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
  32.        </sequenceFlow>
  33.        <sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="fillTask">
  34.            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
  35.        </sequenceFlow>
  36.        <sequenceFlow id="flow1" sourceRef="start" targetRef="fillTask"></sequenceFlow>
  37.        <sequenceFlow id="flow2" sourceRef="fillTask" targetRef="judgeTask"></sequenceFlow>
  38.        <sequenceFlow id="judgeMore" name="大于500元" sourceRef="judgeTask" targetRef="bossTask">
  39.            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money > 500}]]></conditionExpression>
  40.        </sequenceFlow>
  41.        <sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
  42.            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
  43.        </sequenceFlow>
  44.        <sequenceFlow id="directorPassFlow" name="通过" sourceRef="directorTak" targetRef="end">
  45.            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
  46.        </sequenceFlow>
  47.        <sequenceFlow id="judgeLess" name="小于500元" sourceRef="judgeTask" targetRef="directorTak">
  48.            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 500}]]></conditionExpression>
  49.        </sequenceFlow>
  50.    </process>
  51.    <bpmndi:BPMNDiagram id="BPMNDiagram_Expense">
  52.        <bpmndi:BPMNPlane bpmnElement="Expense" id="BPMNPlane_Expense">
  53.            <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
  54.                <omgdc:Bounds height="30.0" width="30.0" x="285.0" y="135.0"></omgdc:Bounds>
  55.            </bpmndi:BPMNShape>
  56.            <bpmndi:BPMNShape bpmnElement="fillTask" id="BPMNShape_fillTask">
  57.                <omgdc:Bounds height="80.0" width="100.0" x="405.0" y="110.0"></omgdc:Bounds>
  58.            </bpmndi:BPMNShape>
  59.            <bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
  60.                <omgdc:Bounds height="40.0" width="40.0" x="585.0" y="130.0"></omgdc:Bounds>
  61.            </bpmndi:BPMNShape>
  62.            <bpmndi:BPMNShape bpmnElement="directorTak" id="BPMNShape_directorTak">
  63.                <omgdc:Bounds height="80.0" width="100.0" x="735.0" y="110.0"></omgdc:Bounds>
  64.            </bpmndi:BPMNShape>
  65.            <bpmndi:BPMNShape bpmnElement="bossTask" id="BPMNShape_bossTask">
  66.                <omgdc:Bounds height="80.0" width="100.0" x="555.0" y="255.0"></omgdc:Bounds>
  67.            </bpmndi:BPMNShape>
  68.            <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
  69.                <omgdc:Bounds height="28.0" width="28.0" x="771.0" y="281.0"></omgdc:Bounds>
  70.            </bpmndi:BPMNShape>
  71.            <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
  72.                <omgdi:waypoint x="315.0" y="150.0"></omgdi:waypoint>
  73.                <omgdi:waypoint x="405.0" y="150.0"></omgdi:waypoint>
  74.            </bpmndi:BPMNEdge>
  75.            <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
  76.                <omgdi:waypoint x="505.0" y="150.16611295681062"></omgdi:waypoint>
  77.                <omgdi:waypoint x="585.4333333333333" y="150.43333333333334"></omgdi:waypoint>
  78.            </bpmndi:BPMNEdge>
  79.            <bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
  80.                <omgdi:waypoint x="624.5530726256983" y="150.44692737430168"></omgdi:waypoint>
  81.                <omgdi:waypoint x="735.0" y="150.1392757660167"></omgdi:waypoint>
  82.            </bpmndi:BPMNEdge>
  83.            <bpmndi:BPMNEdge bpmnElement="directorNotPassFlow" id="BPMNEdge_directorNotPassFlow">
  84.                <omgdi:waypoint x="785.0" y="110.0"></omgdi:waypoint>
  85.                <omgdi:waypoint x="785.0" y="37.0"></omgdi:waypoint>
  86.                <omgdi:waypoint x="455.0" y="37.0"></omgdi:waypoint>
  87.                <omgdi:waypoint x="455.0" y="110.0"></omgdi:waypoint>
  88.            </bpmndi:BPMNEdge>
  89.            <bpmndi:BPMNEdge bpmnElement="bossPassFlow" id="BPMNEdge_bossPassFlow">
  90.                <omgdi:waypoint x="655.0" y="295.0"></omgdi:waypoint>
  91.                <omgdi:waypoint x="771.0" y="295.0"></omgdi:waypoint>
  92.            </bpmndi:BPMNEdge>
  93.            <bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
  94.                <omgdi:waypoint x="605.4340277777778" y="169.56597222222223"></omgdi:waypoint>
  95.                <omgdi:waypoint x="605.1384083044983" y="255.0"></omgdi:waypoint>
  96.            </bpmndi:BPMNEdge>
  97.            <bpmndi:BPMNEdge bpmnElement="directorPassFlow" id="BPMNEdge_directorPassFlow">
  98.                <omgdi:waypoint x="785.0" y="190.0"></omgdi:waypoint>
  99.                <omgdi:waypoint x="785.0" y="281.0"></omgdi:waypoint>
  100.            </bpmndi:BPMNEdge>
  101.            <bpmndi:BPMNEdge bpmnElement="bossNotPassFlow" id="BPMNEdge_bossNotPassFlow">
  102.                <omgdi:waypoint x="555.0" y="295.0"></omgdi:waypoint>
  103.                <omgdi:waypoint x="455.0" y="295.0"></omgdi:waypoint>
  104.                <omgdi:waypoint x="455.0" y="190.0"></omgdi:waypoint>
  105.            </bpmndi:BPMNEdge>
  106.        </bpmndi:BPMNPlane>
  107.    </bpmndi:BPMNDiagram>
  108. </definitions>

5、添加代理类

A.ManagerTaskHandler.java

  1. package com.fcant.service_flowable.handler;
  2. import org.flowable.engine.delegate.TaskListener;
  3. import org.flowable.task.service.delegate.DelegateTask;
  4. /**
  5. * ManagerTaskHandler
  6. * <p>
  7. * encoding:UTF-8
  8. *
  9. * @author Fcant 下午 19:42 2020/8/2/0002
  10. */
  11. public class ManagerTaskHandler implements TaskListener {
  12.    @Override
  13.    public void notify(DelegateTask delegateTask) {
  14.        delegateTask.setAssignee("经理");
  15.    }
  16. }

B.BossTaskHandler.java

  1. package com.fcant.service_flowable.handler;
  2. import org.flowable.engine.delegate.TaskListener;
  3. import org.flowable.task.service.delegate.DelegateTask;
  4. /**
  5. * BossTaskHandler
  6. * <p>
  7. * encoding:UTF-8
  8. *
  9. * @author Fcant 下午 19:43 2020/8/2/0002
  10. */
  11. public class BossTaskHandler implements TaskListener {
  12.    @Override
  13.    public void notify(DelegateTask delegateTask) {
  14.        delegateTask.setAssignee("老板");
  15.    }
  16. }

C.以上代理类可以使用标签进行替换

  1. <userTask id="holidayApprovedTask" name="Holiday approved" flowable:assignee="${employee}"/>

D.代理类完成后需要在BPMN进行类指定

6、业务逻辑层以及测试接口

A.ExpenseService.java

  1. package com.fcant.service_flowable.service;
  2. import javax.servlet.http.HttpServletResponse;
  3. /**
  4. * ExpenseService
  5. * <p>
  6. * encoding:UTF-8
  7. *
  8. * @author Fcant 下午 20:10 2020/8/2/0002
  9. */
  10. public interface ExpenseService {
  11.    /**
  12.     * 添加报销
  13.     *
  14.     * @param userId 用户Id
  15.     * @param money 报销金额
  16.     * @param descption 描述
  17.     * @return String
  18.     * @author Fcant 下午 20:02 2020/8/2/0002
  19.     */
  20.    public String addExpense(String userId, Integer money, String descption);
  21.    /**
  22.     * 获取审批管理列表
  23.     *
  24.     * @param userId 对应用户的审批列表
  25.     * @return Object
  26.     * @author Fcant 下午 20:01 2020/8/2/0002
  27.     */
  28.    public Object list(String userId);
  29.    /**
  30.     * 批准
  31.     *
  32.     * @param taskId 批准的工作流ID
  33.     * @return
  34.     * @author Fcant 下午 20:01 2020/8/2/0002
  35.     */
  36.    public String apply(String taskId);
  37.    /**
  38.     * 拒绝
  39.     *
  40.     * @param taskId 拒绝的工作流ID
  41.     * @return String
  42.     * @author Fcant 下午 20:00 2020/8/2/0002
  43.     */
  44.    public String reject(String taskId);
  45.    /**
  46.     * 生成流程图
  47.     *
  48.     * @param processId 任务ID
  49.     * @author Fcant 下午 19:59 2020/8/2/0002
  50.     */
  51.    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception;
  52. }

B.ExpenseServiceImpl.java

  1. package com.fcant.service_flowable.service.impl;
  2. import com.fcant.service_flowable.service.ExpenseService;
  3. import org.flowable.bpmn.model.BpmnModel;
  4. import org.flowable.engine.*;
  5. import org.flowable.engine.runtime.Execution;
  6. import org.flowable.engine.runtime.ProcessInstance;
  7. import org.flowable.image.ProcessDiagramGenerator;
  8. import org.flowable.task.api.Task;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.stereotype.Service;
  11. import javax.servlet.http.HttpServletResponse;
  12. import java.io.InputStream;
  13. import java.io.OutputStream;
  14. import java.util.ArrayList;
  15. import java.util.HashMap;
  16. import java.util.List;
  17. /**
  18. * ExpenseServiceImpl
  19. * <p>
  20. * encoding:UTF-8
  21. *
  22. * @author Fcant 下午 20:10 2020/8/2/0002
  23. */
  24. @Service
  25. public class ExpenseServiceImpl implements ExpenseService {
  26.    @Autowired
  27.    private RuntimeService runtimeService;
  28.    @Autowired
  29.    private TaskService taskService;
  30.    @Autowired
  31.    private RepositoryService repositoryService;
  32.    @Autowired
  33.    private ProcessEngine processEngine;
  34.    /**
  35.     * 添加报销
  36.     *
  37.     * @param userId 用户Id
  38.     * @param money 报销金额
  39.     * @param descption 描述
  40.     * @return String
  41.     * @author Fcant 下午 20:02 2020/8/2/0002
  42.     */
  43.    @Override
  44.    public String addExpense(String userId, Integer money, String descption) {
  45.        //启动流程
  46.        HashMap<String, Object> map = new HashMap<>();
  47.        map.put("taskUser", userId);
  48.        map.put("money", money);
  49.        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Expense", map);
  50.        return "提交成功.流程Id为:" + processInstance.getId();
  51.    }
  52.    /**
  53.     * 获取审批管理列表
  54.     *
  55.     * @param userId 对应用户的审批列表
  56.     * @return Object
  57.     * @author Fcant 下午 20:01 2020/8/2/0002
  58.     */
  59.    @Override
  60.    public Object list(String userId) {
  61.        List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
  62.        for (Task task : tasks) {
  63.            System.out.println(task.toString());
  64.        }
  65.        return tasks.toArray().toString();
  66.    }
  67.    /**
  68.     * 批准
  69.     *
  70.     * @param taskId 批准的工作流ID
  71.     * @return
  72.     * @author Fcant 下午 20:01 2020/8/2/0002
  73.     */
  74.    @Override
  75.    public String apply(String taskId) {
  76.        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
  77.        if (task == null) {
  78.            throw new RuntimeException("流程不存在");
  79.        }
  80.        //通过审核
  81.        HashMap<String, Object> map = new HashMap<>();
  82.        map.put("outcome", "通过");
  83.        taskService.complete(taskId, map);
  84.        return "processed ok!";
  85.    }
  86.    /**
  87.     * 拒绝
  88.     *
  89.     * @param taskId 拒绝的工作流ID
  90.     * @return String
  91.     * @author Fcant 下午 20:00 2020/8/2/0002
  92.     */
  93.    @Override
  94.    public String reject(String taskId) {
  95.        HashMap<String, Object> map = new HashMap<>();
  96.        map.put("outcome", "驳回");
  97.        taskService.complete(taskId, map);
  98.        return "reject";
  99.    }
  100.    /**
  101.     * 生成流程图
  102.     *
  103.     * @param processId 任务ID
  104.     * @author Fcant 下午 19:59 2020/8/2/0002
  105.     */
  106.    @Override
  107.    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
  108.        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
  109.        //流程走完的不显示图
  110.        if (pi == null) {
  111.            return;
  112.        }
  113.        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
  114.        //使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象
  115.        String InstanceId = task.getProcessInstanceId();
  116.        List<Execution> executions = runtimeService
  117.                .createExecutionQuery()
  118.                .processInstanceId(InstanceId)
  119.                .list();
  120.        //得到正在执行的Activity的Id
  121.        List<String> activityIds = new ArrayList<>();
  122.        List<String> flows = new ArrayList<>();
  123.        for (Execution exe : executions) {
  124.            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
  125.            activityIds.addAll(ids);
  126.        }
  127.        //获取流程图
  128.        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
  129.        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
  130.        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
  131.        InputStream in = diagramGenerator.generateDiagram(bpmnModel,
  132.                "png", activityIds, flows, engconf.getActivityFontName(),
  133.                engconf.getLabelFontName(), engconf.getAnnotationFontName(),
  134.                engconf.getClassLoader(), 1.0, true);
  135.        OutputStream out = null;
  136.        byte[] buf = new byte[1024];
  137.        int legth = 0;
  138.        try {
  139.            out = httpServletResponse.getOutputStream();
  140.            while ((legth = in.read(buf)) != -1) {
  141.                out.write(buf, 0, legth);
  142.            }
  143.        } finally {
  144.            if (in != null) {
  145.                in.close();
  146.            }
  147.            if (out != null) {
  148.                out.close();
  149.            }
  150.        }
  151.    }
  152. }

C.ExpenseController.java

  1. package com.fcant.service_flowable.controller;
  2. import com.fcant.service_flowable.service.ExpenseService;
  3. import io.swagger.annotations.Api;
  4. import io.swagger.annotations.ApiOperation;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Controller;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.ResponseBody;
  9. import javax.servlet.http.HttpServletResponse;
  10. /**
  11. * ExpenseController
  12. * <p>
  13. * encoding:UTF-8
  14. *
  15. * @author Fcant 下午 19:46 2020/8/2/0002
  16. */
  17. @Api(tags = "expense",value = "工作流控制器")
  18. @Controller
  19. @RequestMapping("/expense")
  20. public class ExpenseController {
  21.    @Autowired
  22.    ExpenseService expenseService;
  23.    /**
  24.     * 添加报销
  25.     *
  26.     * @param userId 用户Id
  27.     * @param money 报销金额
  28.     * @param descption 描述
  29.     * @return String
  30.     * @author Fcant 下午 20:02 2020/8/2/0002
  31.     */
  32.    @ApiOperation(value="添加报销")
  33.    @RequestMapping(value = "/add")
  34.    @ResponseBody
  35.    public String addExpense(String userId, Integer money, String descption) {
  36.        return expenseService.addExpense(userId, money, descption);
  37.    }
  38.    /**
  39.     * 获取审批管理列表
  40.     *
  41.     * @param userId 对应用户的审批列表
  42.     * @return Object
  43.     * @author Fcant 下午 20:01 2020/8/2/0002
  44.     */
  45.    @ApiOperation(value="获取审批管理列表")
  46.    @RequestMapping(value = "/list")
  47.    @ResponseBody
  48.    public Object list(String userId) {
  49.        return expenseService.list(userId);
  50.    }
  51.    /**
  52.     * 批准
  53.     *
  54.     * @param taskId 批准的工作流ID
  55.     * @return
  56.     * @author Fcant 下午 20:01 2020/8/2/0002
  57.     */
  58.    @ApiOperation(value="批准")
  59.    @RequestMapping(value = "/apply")
  60.    @ResponseBody
  61.    public String apply(String taskId) {
  62.        expenseService.apply(taskId);
  63.        return "processed ok!";
  64.    }
  65.    /**
  66.     * 拒绝
  67.     *
  68.     * @param taskId 拒绝的工作流ID
  69.     * @return String
  70.     * @author Fcant 下午 20:00 2020/8/2/0002
  71.     */
  72.    @ApiOperation(value="拒绝")
  73.    @ResponseBody
  74.    @RequestMapping(value = "/reject")
  75.    public String reject(String taskId) {
  76.        expenseService.reject(taskId);
  77.        return "reject";
  78.    }
  79.    /**
  80.     * 生成流程图
  81.     *
  82.     * @param processId 任务ID
  83.     * @author Fcant 下午 19:59 2020/8/2/0002
  84.     */
  85.    @ApiOperation(value="生成流程图")
  86.    @RequestMapping(value = "/processDiagram")
  87.    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
  88.        expenseService.genProcessDiagram(httpServletResponse, processId);
  89.    }
  90. }

7、配置生成的流图的字体(防止/解决生成流程图片的乱码问题)

  1. package com.fcant.service_flowable.config;
  2. import org.flowable.spring.SpringProcessEngineConfiguration;
  3. import org.flowable.spring.boot.EngineConfigurationConfigurer;
  4. import org.springframework.context.annotation.Configuration;
  5. /**
  6. * FlowableConfig
  7. * <p>
  8. * encoding:UTF-8
  9. *
  10. * @author Fcant 下午 19:51 2020/8/2/0002
  11. */
  12. @Configuration
  13. public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
  14.    @Override
  15.    public void configure(SpringProcessEngineConfiguration engineConfiguration) {
  16.        engineConfiguration.setActivityFontName("宋体");
  17.        engineConfiguration.setLabelFontName("宋体");
  18.        engineConfiguration.setAnnotationFontName("宋体");
  19.    }
  20. }

8、配置Swagger

  1. package com.fcant.service_flowable.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  5. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  6. import springfox.documentation.builders.ApiInfoBuilder;
  7. import springfox.documentation.builders.PathSelectors;
  8. import springfox.documentation.builders.RequestHandlerSelectors;
  9. import springfox.documentation.service.ApiInfo;
  10. import springfox.documentation.service.Contact;
  11. import springfox.documentation.spi.DocumentationType;
  12. import springfox.documentation.spring.web.plugins.Docket;
  13. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  14. /**
  15. * SwaggerConfig
  16. * <p>
  17. * encoding:UTF-8
  18. *
  19. * @author Fcant 下午 23:41 2020/8/1/0001
  20. */
  21. @Configuration
  22. @EnableSwagger2
  23. public class SwaggerConfig implements WebMvcConfigurer {
  24.    @Override
  25.    public void addResourceHandlers(ResourceHandlerRegistry registry) {
  26.        registry.addResourceHandler("swagger-ui.html")
  27.                .addResourceLocations("classpath:/META-INF/resources/");
  28.        registry.addResourceHandler("/webjars/**")
  29.                .addResourceLocations("classpath:/META-INF/resources/webjars/");
  30.    }
  31.    /**
  32.     * @author Fcant 13:44 2019/12/5
  33.     */
  34.    @Bean
  35.    public Docket petApi() {
  36.        return new Docket(DocumentationType.SWAGGER_2)
  37.                .apiInfo(apiInfo())
  38.                .select()
  39.                .apis(RequestHandlerSelectors.basePackage("com.fcant.service_flowable.controller"))
  40.                .paths(PathSelectors.any())
  41.                .build();
  42.    }
  43.    /**
  44.     * 该套 API 说明,包含作者、简介、版本、host、服务URL
  45.     * @return
  46.     */
  47.    private ApiInfo apiInfo() {
  48.        return new ApiInfoBuilder()
  49.                .title("Flowable Service API")
  50.                .contact(new Contact("fcant","null","fcscanf@outlook.com"))
  51.                .version("0.1")
  52.                .termsOfServiceUrl("www.yuque.com/fcant")
  53.                .description("Flowable Service API")
  54.                .build();
  55.    }
  56. }

9、启动项目,访问Swagger页面进行接口测试


相关文章
|
1月前
|
XML 数据可视化 Java
|
1月前
|
Java API Nacos
OpenFeign与Nacos结合使用时获取服务提供者的真实IP地址的方法
最终,当服务调用一次次执行,数据一次次精准传递时,这个寻找真实IP地址的宝藏狩猎,就顺利完成了。这不单单是原创性的解决方案,更是创意性地结合了现代微服务技术,和你一起编织了这场寻宝之旅的冒险故事。
107 25
|
前端开发 JavaScript Java
【实训项目】易行APP设计(c2c二手交易平台)
【实训项目】易行APP设计(c2c二手交易平台)
331 0
|
9月前
|
XML Java 数据格式
Spring从入门到入土(xml配置文件的基础使用方式)
本文详细介绍了Spring框架中XML配置文件的使用方法,包括读取配置文件、创建带参数的构造对象、使用工厂方法和静态方法创建对象、对象生命周期管理以及单例和多例模式的测试。
401 7
Spring从入门到入土(xml配置文件的基础使用方式)
|
7月前
|
存储 编解码 Dart
腾讯开源混元视频生成模型,这效果!太稳了吧!
腾讯开源了HunyuanVideo,这是一个超过130亿参数的视频生成模型,具备高性能的图像-视频联合生成能力。通过创新的模型架构和高效的训练基础设施,HunyuanVideo在视觉质量、运动多样性和文本-视频对齐等方面表现出色,超越了多个现有模型。该项目旨在推动视频生成技术的发展,促进社区交流与创新。
366 11
腾讯开源混元视频生成模型,这效果!太稳了吧!
|
8月前
欧拉服务器修改系统时间
【10月更文挑战第27天】欧拉服务器修改系统时间
1990 1
|
分布式计算 负载均衡 数据安全/隐私保护
什么是RPC?有哪些RPC框架?
RPC(Remote Procedure Call,远程过程调用)是一种允许运行在一台计算机上的程序调用另一台计算机上子程序的技术。这种技术屏蔽了底层的网络通信细节,使得程序间的远程通信如同本地调用一样简单。RPC机制使得开发者能够构建分布式计算系统,其中不同的组件可以分布在不同的计算机上,但它们之间可以像在同一台机器上一样相互调用。
317 8
|
12月前
|
网络协议 Dubbo Java
什么是RPC?RPC和HTTP对比?RPC有什么缺点?市面上常用的RPC框架?
选择合适的RPC框架和通信协议,对于构建高效、稳定的分布式系统至关重要。开发者需要根据自己的业务需求和系统架构,综合考虑各种因素,做出适宜的技术选型。
941 1
|
安全 前端开发 Java
学习从Struts迁移到Spring的策略概述
从Struts框架迁移到Spring框架是一个常见的升级路径,主要是为了利用Spring框架提供的更多功能、更好的模块化支持以及更广泛的社区资源。
202 3
|
12月前
|
存储 Docker 容器
docker查看日志:docker service logs 与 docker container logs
docker查看日志:docker service logs 与 docker container logs
634 0