相关文章推荐
温文尔雅的竹笋  ·  input file ...·  6 月前    · 
另类的饼干  ·  PyCharm 中 Django ...·  1 年前    · 
买醉的蛋挞  ·  Get exclusive jobs on ...·  1 年前    · 
< dependency > < groupId > org.springframework.boot </ groupId > < artifactId > spring-boot-starter-web </ artifactId > < version > 2.0.9.RELEASE </ version > </ dependency > <!--flowable工作流依赖--> < dependency > < groupId > org.flowable </ groupId > < artifactId > flowable-spring-boot-starter </ artifactId > < version > 6.3.0 </ version > </ dependency > <!--mysql依赖--> < dependency > < groupId > mysql </ groupId > < artifactId > mysql-connector-java </ artifactId > < version > 8.0.17 </ version > </ dependency > </ dependencies >

2 application.yml配置文件

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
flowable:
  #关闭定时任务JOB
  async-executor-activate: false

3 在resources下创建文件夹processes,创建文件ExpenseProcess.bpmn20.xml

<?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:flowable="http://flowable.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.flowable.org/processdef">
  <process id="Expense" name="ExpenseProcess" isExecutable="true">
    <documentation>报销流程</documentation>
    <startEvent id="start" name="开始"></startEvent>
    <userTask id="fillTask" name="出差报销" flowable:assignee="${taskUser}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler">
          <![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <exclusiveGateway id="judgeTask"></exclusiveGateway>
    <userTask id="directorTak" name="经理审批">
      <extensionElements>
        <flowable:taskListener event="create"
          class="com.cf.Listener.ManagerTaskHandler"></flowable:taskListener>
      </extensionElements>
    </userTask>
    <userTask id="bossTask" name="老板审批">
      <extensionElements>
        <flowable:taskListener event="create"
          class="com.cf.Listener.BossTaskHandler"></flowable:taskListener>
      </extensionElements>
    </userTask>
    <endEvent id="end" name="结束"></endEvent>
    <sequenceFlow id="directorNotPassFlow" name="驳回" sourceRef="directorTak" targetRef="fillTask">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="fillTask">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow1" sourceRef="start" targetRef="fillTask"></sequenceFlow>
    <sequenceFlow id="flow2" sourceRef="fillTask" targetRef="judgeTask"></sequenceFlow>
    <sequenceFlow id="judgeMore" name="大于500元" sourceRef="judgeTask" targetRef="bossTask">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money > 500}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="directorPassFlow" name="通过" sourceRef="directorTak" targetRef="end">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="judgeLess" name="小于500元" sourceRef="judgeTask" targetRef="directorTak">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 500}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_Expense">
    <bpmndi:BPMNPlane bpmnElement="Expense" id="BPMNPlane_Expense">
      <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
        <omgdc:Bounds height="30.0" width="30.0" x="285.0" y="135.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="fillTask" id="BPMNShape_fillTask">
        <omgdc:Bounds height="80.0" width="100.0" x="405.0" y="110.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
        <omgdc:Bounds height="40.0" width="40.0" x="585.0" y="130.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="directorTak" id="BPMNShape_directorTak">
        <omgdc:Bounds height="80.0" width="100.0" x="735.0" y="110.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="bossTask"




    
 id="BPMNShape_bossTask">
        <omgdc:Bounds height="80.0" width="100.0" x="555.0" y="255.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
        <omgdc:Bounds height="28.0" width="28.0" x="771.0" y="281.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="315.0" y="150.0"></omgdi:waypoint>
        <omgdi:waypoint x="405.0" y="150.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="505.0" y="150.16611295681062"></omgdi:waypoint>
        <omgdi:waypoint x="585.4333333333333" y="150.43333333333334"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
        <omgdi:waypoint x="624.5530726256983" y="150.44692737430168"></omgdi:waypoint>
        <omgdi:waypoint x="735.0" y="150.1392757660167"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="directorNotPassFlow" id="BPMNEdge_directorNotPassFlow">
        <omgdi:waypoint x="785.0" y="110.0"></omgdi:waypoint>
        <omgdi:waypoint x="785.0" y="37.0"></omgdi:waypoint>
        <omgdi:waypoint x="455.0" y="37.0"></omgdi:waypoint>
        <omgdi:waypoint x="455.0" y="110.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="bossPassFlow" id="BPMNEdge_bossPassFlow">
        <omgdi:waypoint x="655.0" y="295.0"></omgdi:waypoint>
        <omgdi:waypoint x="771.0" y="295.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
        <omgdi:waypoint x="605.4340277777778" y="169.56597222222223"></omgdi:waypoint>
        <omgdi:waypoint x="605.1384083044983" y="255.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="directorPassFlow" id="BPMNEdge_directorPassFlow">
        <omgdi:waypoint x="785.0" y="190.0"></omgdi:waypoint>
        <omgdi:waypoint x="785.0" y="281.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="bossNotPassFlow" id="BPMNEdge_bossNotPassFlow">
        <omgdi:waypoint x="555.0" y="295.0"></omgdi:waypoint>
        <omgdi:waypoint x="455.0" y="295.0"></omgdi:waypoint>
        <omgdi:waypoint x="455.0" y="190.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

4 创建Controller控制类

package com.cf.controller;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.flowable.bpmn.model.BpmnModel;
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.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 * @Description:
 * @Date: 2021/5/30
@Controller
@RequestMapping("/expense")
public class ExpenseController {
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessEngine processEngine;
     * 添加报销
     * @param userId 用户Id
     * @param money 报销金额
     * @param descption 描述
    @RequestMapping(value = "add")
    @ResponseBody
    public String addExpense(String userId, Integer money) {
        //启动流程
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("taskUser", userId);
        map.put("money", money);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Expense", map);
        return "提交成功.流程Id为:" + processInstance.getId();
     * 获取审批管理列表
    @RequestMapping(value = "/list")
    @ResponseBody
    public Object list(String userId) {
        List<Task> tasks = taskService.createTaskQuery()
                .taskAssignee(userId)
                .orderByTaskCreateTime()
                .desc()
                .list();
        for (Task task : tasks) {
            System.out.println(task.toString());
        return tasks.toString();
     * @param taskId 任务ID
    @RequestMapping(value = "apply")
    @ResponseBody
    public String apply(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId)
                .singleResult();
        if (task == null) {
            throw new RuntimeException("流程不存在");
        //通过审核
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("outcome", "通过");
        taskService.complete(taskId, map);
        return "processed ok!";
    @ResponseBody
    @RequestMapping(value = "reject")
    public String reject(String taskId) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("outcome", "驳回");
        taskService.complete(taskId, map);
        return "reject";
     * 生成流程图
     * @param processId 任务ID
    @RequestMapping(value = "processDiagram")
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId)
            throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processId).singleResult();
        //流程走完的不显示图
        if (pi == null) {
            return;
        Task task = taskService.createTaskQuery()
                .processInstanceId(pi.getId())
                .singleResult();
        //使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();
        //得到正在执行的Activity的Id
        List<String> activityIds = new




    
 ArrayList<String>();
        List<String> flows = new ArrayList<String>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows,
                engconf.getActivityFontName(), engconf.getLabelFontName(),
                engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
        } finally {
            if (in != null) {
                in.close();
            if (out != null) {
                out.close();

5 创建任务处理类BossTaskHandlerManagerTaskHandler

public class BossTaskHandler implements TaskListener {
    public void notify(DelegateTask delegateTask) {
        delegateTask.setAssignee("老板");
public class ManagerTaskHandler implements TaskListener {
    public void notify(DelegateTask delegateTask) {
        delegateTask.setAssignee("经理");

6 添加字体配置类

@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
    public void configure(SpringProcessEngineConfiguration engineConfiguration) {
        engineConfiguration.setActivityFontName("宋体");
        engineConfiguration.setLabelFontName("宋体");
        engineConfiguration.setAnnotationFontName("宋体");

SpringBoot整合Flowable初始化表报Error initialising Content schema问题

参考资料:

flowable 6.3.0版本

Mysql 5.5.40版本

相关配置完成后,启动报错

-- 报错信息
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'expenseController': Unsatisfied dependency expressed through field 'runtimeService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'runtimeServiceBean' defined in class path resource [org/flowable/spring/boot/ProcessEngineAutoConfiguration.class]: Unsatisfied dependency expressed through method 'runtimeServiceBean' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'processEngine': FactoryBean threw exception on object creation; nested exception is org.flowable.engine.common.api.FlowableException: Error initialising Content schema
	Error initialising Content schema
-- 报错原因 
Reason: liquibase.exception.DatabaseException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(6) NULL, CREATED_BY_ VARCHAR(255) NULL, LAST_MODIFIED_ timestamp(6) NULL, LAST_' at line 1 [Failed SQL: CREATE TABLE flowable.ACT_CO_CONTENT_ITEM (ID_ VARCHAR(255) NOT NULL, NAME_ VARCHAR(255) NOT NULL, MIME_TYPE_ VARCHAR(255) NULL, TASK_ID_ VARCHAR(255) NULL, PROC_INST_ID_ VARCHAR(255) NULL, CONTENT_STORE_ID_ VARCHAR(255) NULL, CONTENT_STORE_NAME_ VARCHAR(255) NULL, FIELD_ VARCHAR(400) NULL, CONTENT_AVAILABLE_ BIT(1) DEFAULT 0 NULL, CREATED_ timestamp(6) NULL, CREATED_BY_ VARCHAR(255) NULL, LAST_MODIFIED_ timestamp(6) NULL, LAST_MODIFIED_BY_ VARCHAR(255) NULL, CONTENT_SIZE_ BIGINT DEFAULT 0 NULL, TENANT_ID_ VARCHAR(255) NULL, CONSTRAINT PK_ACT_CO_CONTENT_ITEM PRIMARY KEY (ID_))]

​ 错误提示信息, 检查Mysql的版本, 下列执行的Sql报错. 将Sql拷贝到navicat中运行,报同样错误,怀疑Mysql版本冲突问题. 上网查阅资料, Mysql5.5和5.6版本,在dump中sql语句的时间戳TIMESTAMP有区别, 5.5版本是timestamp , 5.6版本是timestamp(0)后面有跟时间戳.

​ 将以上sql中timestamp后括号去掉, 运行sql成功.

总结: 可通过升级Mysql的版本解决该问题.

  •