springboot整合flowable框架入门步骤

最近工作中有用到工作流的开发,引入了flowable工作流框架,在此记录一下springboot整合flowable工作流框架的过程,以便后续再次使用到时可以做一些参考使用,如果项目中有涉及到流程审批的话,可以使用该框架帮我们实现流程图示化展示的功能,为了快速了解flowable工作流框架的一个使用过程,我们直接步入主题,springboot整合flowable工作流框架的步骤如下:

1、首先创建一个springboot工程,然后引入flowable pom依赖,代码如下:

<dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter</artifactId>
            <version>6.7.0</version>
        </dependency>

2、创建流程图定义文档

这里有一个使用flowable-ui可视化的工程来创建流程图定义文档,https://www.wandouip.com/t5i212543/,具体实施过程如下:

先从 https://github.com/flowable/flowable-engine/releases 上下载一个发布文档,这里选择Flowable 6.7.2 release;然后解压缩文件,将里面的wars文档下的两个jar包(flowable-rest.war、flowable-ui.war)部署到tomcat下,放到webapps文件加下,点击运行,运行存在一个解压缩文件的过程,会产生flowable-rest、flowable-ui文件夹,浏览器输入 http://localhost:8080/flowable-ui,如下图:

用户名密码输入admin/test,如下图:

点击建模器应用程序,点击右上角”创建流程“,填写相关信息,进去后就可以可视化地创建流程,如下图:

上面初步展示了使用可视化制作工具制作流程图的过程,然后导出BPMN2文件,文件内容大概如下:

<?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:xsd="http://www.w3.org/2001/XMLSchema" 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" exporter="Flowable Open Source Modeler" exporterVersion="6.7.2">
  <process id="test" name="test" isExecutable="true">
    <startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
    <userTask id="sid-EE908BC6-94A5-4C9A-B53A-68890D1241BB" name="初级管理员" flowable:formFieldValidation="true"></userTask>
    <sequenceFlow id="sid-BD25A451-66F1-4AF1-B954-5EE5BC5A5782" sourceRef="startEvent1" targetRef="sid-EE908BC6-94A5-4C9A-B53A-68890D1241BB"></sequenceFlow>
    <exclusiveGateway id="sid-57C003F8-C0F3-4499-8B1D-0B29223DB541"></exclusiveGateway>
    <sequenceFlow id="sid-D9571C82-9071-41EA-9858-D10FF50B4396" sourceRef="sid-EE908BC6-94A5-4C9A-B53A-68890D1241BB" targetRef="sid-57C003F8-C0F3-4499-8B1D-0B29223DB541"></sequenceFlow>
    <userTask id="sid-1EF0B969-8092-4EC5-9899-16D066122EC8" name="高级管理员" flowable:formFieldValidation="true"></userTask>
    <sequenceFlow id="sid-7E40EF52-4ED7-4785-954B-3530C3400D81" sourceRef="sid-57C003F8-C0F3-4499-8B1D-0B29223DB541" targetRef="sid-1EF0B969-8092-4EC5-9899-16D066122EC8"></sequenceFlow>
    <intermediateThrowEvent id="sid-13E2B97C-78C9-4A4B-BAD8-A47038668B5F"></intermediateThrowEvent>
    <sequenceFlow id="sid-72B217BF-4F36-446E-B48F-741E3F38B66F" sourceRef="sid-57C003F8-C0F3-4499-8B1D-0B29223DB541" targetRef="sid-13E2B97C-78C9-4A4B-BAD8-A47038668B5F"></sequenceFlow>
    <exclusiveGateway id="sid-DB335453-27CB-4992-824A-3C060312F59F"></exclusiveGateway>
    <sequenceFlow id="sid-60B0EF34-8DB4-421C-A265-59E8A5B7C35F" sourceRef="sid-1EF0B969-8092-4EC5-9899-16D066122EC8" targetRef="sid-DB335453-27CB-4992-824A-3C060312F59F"></sequenceFlow>
    <intermediateThrowEvent id="sid-D6512D07-3215-48FC-A568-227A718EC174"></intermediateThrowEvent>
    <sequenceFlow id="sid-0ABE9D33-F08C-4787-A827-27639909C63A" sourceRef="sid-DB335453-27CB-4992-824A-3C060312F59F" targetRef="sid-D6512D07-3215-48FC-A568-227A718EC174"></sequenceFlow>
    <intermediateThrowEvent id="sid-3F43BAB4-6D7A-4705-A527-D78CF919EEC2"></intermediateThrowEvent>
    <sequenceFlow id="sid-50C31AEE-6B3A-48A2-92D3-7D640E5FF60E" sourceRef="sid-DB335453-27CB-4992-824A-3C060312F59F" targetRef="sid-3F43BAB4-6D7A-4705-A527-D78CF919EEC2"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_test">
    <bpmndi:BPMNPlane bpmnElement="test" id="BPMNPlane_test">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="90.0" y="166.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-EE908BC6-94A5-4C9A-B53A-68890D1241BB" id="BPMNShape_sid-EE908BC6-94A5-4C9A-B53A-68890D1241BB">
        <omgdc:Bounds height="80.0" width="100.0" x="240.0" y="141.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-57C003F8-C0F3-4499-8B1D-0B29223DB541" id="BPMNShape_sid-57C003F8-C0F3-4499-8B1D-0B29223DB541">
        <omgdc:Bounds height="40.0" width="40.0" x="385.0" y="161.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-1EF0B969-8092-4EC5-9899-16D066122EC8" id="BPMNShape_sid-1EF0B969-8092-4EC5-9899-16D066122EC8">
        <omgdc:Bounds height="80.0" width="100.0" x="470.0" y="141.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-13E2B97C-78C9-4A4B-BAD8-A47038668B5F" id="BPMNShape_sid-13E2B97C-78C9-4A4B-BAD8-A47038668B5F">
        <omgdc:Bounds height="30.0" width="30.0" x="390.0" y="270.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-DB335453-27CB-4992-824A-3C060312F59F" id="BPMNShape_sid-DB335453-27CB-4992-824A-3C060312F59F">
        <omgdc:Bounds height="40.0" width="40.0" x="615.0" y="161.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-D6512D07-3215-48FC-A568-227A718EC174" id="BPMNShape_sid-D6512D07-3215-48FC-A568-227A718EC174">
        <omgdc:Bounds height="30.0" width="30.0" x="700.0" y="166.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-3F43BAB4-6D7A-4705-A527-D78CF919EEC2" id="BPMNShape_sid-3F43BAB4-6D7A-4705-A527-D78CF919EEC2">
        <omgdc:Bounds height="30.0" width="30.0" x="620.0" y="270.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-0ABE9D33-F08C-4787-A827-27639909C63A" id="BPMNEdge_sid-0ABE9D33-F08C-4787-A827-27639909C63A" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="15.0" flowable:targetDockerY="15.0">
        <omgdi:waypoint x="654.557806573957" y="181.379746835443"></omgdi:waypoint>
        <omgdi:waypoint x="700.0002881553987" y="181.0940234142237"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-72B217BF-4F36-446E-B48F-741E3F38B66F" id="BPMNEdge_sid-72B217BF-4F36-446E-B48F-741E3F38B66F" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="15.5" flowable:targetDockerY="3.0">
        <omgdi:waypoint x="405.5" y="200.43965611353715"></omgdi:waypoint>
        <omgdi:waypoint x="405.5" y="270.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-BD25A451-66F1-4AF1-B954-5EE5BC5A5782" id="BPMNEdge_sid-BD25A451-66F1-4AF1-B954-5EE5BC5A5782" flowable:sourceDockerX="15.0" flowable:sourceDockerY="15.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
        <omgdi:waypoint x="119.94999946593475" y="181.0"></omgdi:waypoint>
        <omgdi:waypoint x="239.9999999999298" y="181.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-D9571C82-9071-41EA-9858-D10FF50B4396" id="BPMNEdge_sid-D9571C82-9071-41EA-9858-D10FF50B4396" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.5" flowable:targetDockerY="20.5">
        <omgdi:waypoint x="339.9499999999977" y="181.21623376623376"></omgdi:waypoint>
        <omgdi:waypoint x="385.4130434782609" y="181.41304347826087"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-7E40EF52-4ED7-4785-954B-3530C3400D81" id="BPMNEdge_sid-7E40EF52-4ED7-4785-954B-3530C3400D81" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
        <omgdi:waypoint x="424.52473707274277" y="181.41666666666666"></omgdi:waypoint>
        <omgdi:waypoint x="469.99999999999386" y="181.21812227074238"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-60B0EF34-8DB4-421C-A265-59E8A5B7C35F" id="BPMNEdge_sid-60B0EF34-8DB4-421C-A265-59E8A5B7C35F" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.5" flowable:targetDockerY="20.5">
        <omgdi:waypoint x="569.9499999999981" y="181.21623376623378"></omgdi:waypoint>
        <omgdi:waypoint x="615.4130434782609" y="181.41304347826087"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-50C31AEE-6B3A-48A2-92D3-7D640E5FF60E" id="BPMNEdge_sid-50C31AEE-6B3A-48A2-92D3-7D640E5FF60E" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="15.0" flowable:targetDockerY="15.0">
        <omgdi:waypoint x="635.4077669902913" y="200.53271096023283"></omgdi:waypoint>
        <omgdi:waypoint x="635.072221397189" y="270.00017140256364"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

以上初步实现怎么使用可视化工具来创建流程图定义文件,里面更为具体的使用方法还有待探索,上面的步骤执行完毕后,我们就可以运行我们的springboot工程了,在配置文件中配置好数据库链接相关的信息后,然后配置flowable相关信息:

flowable:
  aysnc-executor-activate: false
  database-schema-update: true
  process-definition-location-prefix: classpath*:/processes/
  process-definition-location-suffixes: "**.bpmn20.xml, **.bpmn"

上面的信息配置完毕后,就可以运行我们的工程了,在运行工程之前,在工程的resources文件夹下创建一个processes文件夹,我们的流程定义文档就放在这个文件夹下,创建一个process-test.bpmn20.xml放到processes文件夹下,具体内容定义如下:

<?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:xsd="http://www.w3.org/2001/XMLSchema"
        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="processTest" name="Request Resource Approval " isExecutable="true">
    <startEvent id="starter" name="Starter"></startEvent>
    <serviceTask id="sendJuniorRejectEmail" name="发送初级审批拒绝邮件"
                 activiti:class="com.chinaums.web.controller.flowable2.delegate.SendJuniorRejectionMailDelegate">
    </serviceTask>
    <endEvent id="juniorRejectEnd" name="Junior Reject End"></endEvent>
    <sequenceFlow id="flow5" sourceRef="sendJuniorRejectEmail" targetRef="juniorRejectEnd"></sequenceFlow>
    <userTask id="seniorApproval" name="高级审批" activiti:assignee="${seniorAdmin}"></userTask>
    <userTask id="juniorApproval" name="初级审批" activiti:assignee="${juniorAdmin}"></userTask>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway1"></exclusiveGateway>
    <sequenceFlow id="juniorSuccessFlow" name="同意" sourceRef="exclusivegateway1" targetRef="seniorApproval">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${approved=='Y'}]]>
      </conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="juniorRejectFlow" name="拒绝" sourceRef="exclusivegateway1" targetRef="sendJuniorRejectEmail">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${approved=='N'}]]>
      </conditionExpression>
    </sequenceFlow>
    <exclusiveGateway id="exclusivegateway2" name="Exclusive Gateway2"></exclusiveGateway>
    <sequenceFlow id="flow7" sourceRef="seniorApproval" targetRef="exclusivegateway2"></sequenceFlow>
    <endEvent id="approvalSuccessEnd" name="Approval Success End"></endEvent>
    <sequenceFlow id="seniorSuccessFlow" name="同意" sourceRef="exclusivegateway2" targetRef="sendApprovalSuccessEmail">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${approved=='Y'}]]>
      </conditionExpression>
    </sequenceFlow>
    <serviceTask id="sendSeniorRejectEmail" name="发送高级审批拒绝邮件"
                 activiti:class="com.chinaums.web.controller.flowable2.delegate.SendSeniorRejectionMailDelegate">
    </serviceTask>
    <endEvent id="seniorRejectEnd" name="Senior Reject End"></endEvent>
    <sequenceFlow id="seniorRejectFlow" name="拒绝" sourceRef="exclusivegateway2" targetRef="sendSeniorRejectEmail">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${approved=='N'}]]>
      </conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow9" sourceRef="sendSeniorRejectEmail" targetRef="seniorRejectEnd"></sequenceFlow>
    <sequenceFlow id="flow11" sourceRef="juniorApproval" targetRef="exclusivegateway1"></sequenceFlow>
    <sequenceFlow id="flow12" sourceRef="starter" targetRef="juniorApproval"></sequenceFlow>
    <serviceTask id="sendApprovalSuccessEmail" name="发送审批通过邮件"
                 activiti:class="com.chinaums.web.controller.flowable2.delegate.SendApprovalSuccessEmailDelegate"></serviceTask>
    <sequenceFlow id="flow13"
                  sourceRef="sendApprovalSuccessEmail"
                  targetRef="approvalSuccessEnd"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_requestResourceApprovalProcess">
    <bpmndi:BPMNPlane bpmnElement="requestResourceApprovalProcess" id="BPMNPlane_requestResourceApprovalProcess">
      <bpmndi:BPMNShape bpmnElement="starter" id="BPMNShape_starter">
        <omgdc:Bounds height="35.0" width="35.0" x="45.0" y="118.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sendJuniorRejectEmail" id="BPMNShape_sendJuniorRejectEmail">
        <omgdc:Bounds height="71.0" width="171.0" x="340.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="juniorRejectEnd" id="BPMNShape_juniorRejectEnd">
        <omgdc:Bounds height="35.0" width="35.0" x="408.0" y="385.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="seniorApproval" id="BPMNShape_seniorApproval">
        <omgdc:Bounds height="78.0" width="121.0" x="575.0" y="95.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="juniorApproval" id="BPMNShape_juniorApproval">
        <omgdc:Bounds height="81.0" width="115.0" x="170.0" y="95.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="405.0" y="113.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway2" id="BPMNShape_exclusivegateway2">
        <omgdc:Bounds height="40.0" width="40.0" x="765.0" y="115.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="approvalSuccessEnd" id="BPMNShape_approvalSuccessEnd">
        <omgdc:Bounds height="35.0" width="35.0" x="1140.0" y="117.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sendSeniorRejectEmail" id="BPMNShape_sendSeniorRejectEmail">
        <omgdc:Bounds height="71.0" width="192.0" x="690.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="seniorRejectEnd" id="BPMNShape_seniorRejectEnd">
        <omgdc:Bounds height="35.0" width="35.0" x="768.0" y="385.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sendApprovalSuccessEmail" id="BPMNShape_sendApprovalSuccessEmail">
        <omgdc:Bounds height="75.0" width="141.0" x="920.0" y="96.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
        <omgdi:waypoint x="425.0" y="301.0"></omgdi:waypoint>
        <omgdi:waypoint x="425.0" y="385.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="juniorSuccessFlow" id="BPMNEdge_juniorSuccessFlow">
        <omgdi:waypoint x="445.0" y="133.0"></omgdi:waypoint>
        <omgdi:waypoint x="575.0" y="134.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="16.0" width="32.0" x="445.0" y="133.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="juniorRejectFlow" id="BPMNEdge_juniorRejectFlow">
        <omgdi:waypoint x="425.0" y="153.0"></omgdi:waypoint>
        <omgdi:waypoint x="425.0" y="230.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="16.0" width="32.0" x="425.0" y="153.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
        <omgdi:waypoint x="696.0" y="134.0"></omgdi:waypoint>
        <omgdi:waypoint x="765.0" y="135.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="seniorSuccessFlow" id="BPMNEdge_seniorSuccessFlow">
        <omgdi:waypoint x="805.0" y="135.0"></omgdi:waypoint>
        <omgdi:waypoint x="920.0" y="133.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="16.0" width="32.0" x="805.0" y="135.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="seniorRejectFlow" id="BPMNEdge_seniorRejectFlow">
        <omgdi:waypoint x="785.0" y="155.0"></omgdi:waypoint>
        <omgdi:waypoint x="786.0" y="230.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="16.0" width="32.0" x="785.0" y="155.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
        <omgdi:waypoint x="786.0" y="301.0"></omgdi:waypoint>
        <omgdi:waypoint x="785.0" y="385.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11">
        <omgdi:waypoint x="285.0" y="135.0"></omgdi:waypoint>
        <omgdi:waypoint x="405.0" y="133.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12">
        <omgdi:waypoint x="80.0" y="135.0"></omgdi:waypoint>
        <omgdi:waypoint x="170.0" y="135.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow13" id="BPMNEdge_flow13">
        <omgdi:waypoint x="1061.0" y="133.0"></omgdi:waypoint>
        <omgdi:waypoint x="1140.0" y="134.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

上面文件中的process标签的id值是该流程定义的唯一标识,在创建流程实例时需要传入processId标识,上面的assignee变量后面定义了一个变量${seniorAdmin},这个是由接口调用时传入的,activiti:class后面的值是一个类,表示执行到这个步骤时会触发执行某个动作,比如id为sendJuniorRectEmail的serviceTask中的class定义如下:

@Slf4j
public class SendJuniorRejectionMailDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution execution) {
        String requestUser = (String) execution.getVariable("requestUser");
        String resourceId = (String) execution.getVariable("resourceId");
        System.out.println("SendJuniorRejectionMailDelegate");
        log.info("send approval success mail for user [" + requestUser + "] with apply resource [" + resourceId + "]");
    }
}

上面的类需要实现JavaDelegate这个接口,上面的内容定义完毕后,就可以定义我们的实现方法了,先创建一个接口,定义一些方法:

public interface IProcess {

    /**
     * 创建一个流程实例,创建实例时会登记一些信息,这些信息可以通过调用
     * queryProcessVariables方法获取到,调用时需要传递processInstanceId
     * @param paramObj
     * @return
     */
    ProcessInstanceEntity startProcess(ParamObj paramObj);

    /**
     * 获取指定工作人的代办任务
     * @param assignee
     * @return
     */
    List<TaskInstanceEntity> taskInstance(String assignee);

    /**
     * 处理工作
     * @param paramObj
     */
    void handleTask(ParamObj paramObj);

    /**
     * 获取某个流程实体的状态,各个审批环节所处的状态信息
     * @param processInstanceId
     * @return
     */
    List<ProcessStatusEntity> queryProcessStatus(String processInstanceId);

    /**
     * 查看创建流程实例时登记的变量信息
     * @param processInstanceId
     * @return
     */
    Map<String,Object> queryProcessVariables(String processInstanceId);

    /**
     * 获取某人的历史审批数据
     * @param assignee
     * @return
     */
    List<HistanceInstanceEntity> queryHistoryProcess(String assignee);

    /**
     * 生成流程的图谱
     * @param httpServletResponse
     * @param processInstanceId
     */
    void genProcessDiagram(HttpServletResponse httpServletResponse, String processInstanceId) throws Exception;

    /**
     * 查询是否存在历史数据的流程实例
     * @param processInstanceId
     * @return
     */
    boolean isExistHistoricProcessInstance(String processInstanceId);

    /**
     * 查询指定的流程是否是运行中的流程
     * @param processInstanceId
     * @return
     */
    boolean isExistRunningProcessInstance(String processInstanceId);

    /**
     * 将指定的流程挂起
     * @param processInstanceId
     */
    void suspendProcessInstance(String processInstanceId);

    /**
     * 终止项目流程
     * @param paramObj
     */
    void terminateProcessInstance(ParamObj paramObj);

    /**
     * 将指定的流程激活
     * @param processInstanceId
     */
    void activateProcessInstance(String processInstanceId);

    /**
     * 删除流程实例
     * @param paramObj
     */
    void deleteProcessInstance(ParamObj paramObj);

    /**
     * 将任务返回到某一步骤
     * @param taskId
     * @param targetTaskKey 返回到的目标任务ID
     */
    void rollbackTask(String taskId, String targetTaskKey);

    boolean isProcessFinished(String processInstanceId);
}

定义好接口后,再定义一个实现类:

@Service
public class IProcessImpl implements IProcess {
    @Autowired
    private RepositoryService repositoryService;
    private RuntimeService runtimeService;
    private TaskService taskService;
    private HistoryService historyService;
    private ProcessEngine processEngine;
    ManagementService managementService;
    @Override
    public ProcessInstanceEntity startProcess(ParamObj paramObj) {
        Map<String, Object> variables = new HashMap<>();
        // 请求的资源ID
        variables.put("resourceId", paramObj.getResourceId());
        // 请求发起用户
        variables.put("requestUser", paramObj.getRequestUser());
        // 初级审批用户
        variables.put("juniorAdmin", paramObj.getJuniorAdmin());
        // 高级审批用户
        variables.put("seniorAdmin", paramObj.getSeniorAdmin());
        ProcessInstance processInstance=runtimeService.
                startProcessInstanceByKey(ConstantValues.FLOWABLE_PROCESS_TEST, variables);
        ProcessInstanceEntity entity=new ProcessInstanceEntity();
        entity.setProcessDeploymentId(processInstance.getDeploymentId());
        entity.setProcessInstanceId(processInstance.getProcessInstanceId());
        entity.setActivityId(processInstance.getActivityId());
        return entity;
    }
    public List<TaskInstanceEntity> taskInstance(String assignee) {
        List<TaskInstanceEntity> entities=new ArrayList<>();
        List<Task> tasks= taskService.createTaskQuery().taskAssignee(assignee).orderByTaskCreateTime().desc().list();
        if(!CollectionUtils.isEmpty(tasks)){
            tasks.stream().forEach(task -> {
                TaskInstanceEntity entity=new TaskInstanceEntity();
                String id=task.getId();
                entity.setCreateTime(task.getCreateTime());
                entity.setTaskName(task.getName());
                entity.setProcessInstanceId(task.getProcessInstanceId());
                entity.setTaskId(id);
                Map<String, Object> processVariables = taskService.getVariables(id);
                entity.setRequestUser(processVariables.get("requestUser").toString());
                entity.setResourceId(processVariables.get("resourceId").toString());
                entities.add(entity);
            });
        }
        return entities;
    public void handleTask(ParamObj paramObj) {
        Map<String, Object> taskVariables = new HashMap<>();
        String approved=paramObj.isApproved()?"Y":"N";
        taskVariables.put("approved", approved);
        //审核结果和审核意见都封装为JSON然后放在评论里,后续需要进行逆操作。
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, String> map= new HashMap<>();
        map.put("approved", approved);
        map.put("comment", paramObj.getComment());
        try {
            String json = objectMapper.writeValueAsString(map);
            taskService.addComment(paramObj.getTaskId(), null, json);
            taskService.complete(paramObj.getTaskId(), taskVariables);
        } catch (Exception e) {
            throw new RuntimeException(e);
    public List<ProcessStatusEntity> queryProcessStatus(String processInstanceId) {
        List<ProcessStatusEntity> result = new ArrayList<>();
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId).list();
        if(CollectionUtils.isEmpty(historicTaskInstances)) {
            throw new RuntimeException("Process instance [" + processInstanceId + "] not exist");
        for (HistoricTaskInstance hti : historicTaskInstances) {
            String taskId = hti.getId();
            String taskName = hti.getName();
            String assignee = hti.getAssignee();
            Date createTime = hti.getCreateTime();
            String comment = null;
            String approved=null;
            List<Comment> comments = taskService.getTaskComments(taskId);
            if (!CollectionUtils.isEmpty(comments)) {
                comment = comments.get(0).getFullMessage();
                if(null!=comment) {
                    //这里进行评论的JSON数据的逆操作提取数据
                    ObjectMapper mapper = new ObjectMapper();
                    try {
                        Map<String,Object> data = mapper.readValue(comment, Map.class);
                        approved=data.get("approved").toString();
                        comment=data.get("comment").toString();
                    } catch (Exception e) {
                        System.out.println(e.toString());
                    }
                }
            }
            ProcessStatusEntity pd=new ProcessStatusEntity();
            pd.setTaskName(taskName);
            pd.setAssignee(assignee);
            pd.setCreateTime(createTime);
            pd.setApproved(approved);
            pd.setComment(comment);
            pd.setTaskId(hti.getId());
            pd.setProcessInstanceId(hti.getProcessInstanceId());
            result.add(pd);
        return result;
    public Map<String, Object> queryProcessVariables(String processInstanceId) {
        List<HistoricVariableInstance> historicVariableInstances =
                historyService.createHistoricVariableInstanceQuery()
        if (historicVariableInstances == null) {
        Map<String,Object> ret= new HashMap<>();
        for(HistoricVariableInstance var: historicVariableInstances) {
            ret.put(var.getVariableName(), var.getValue());
        return ret;
    public List<HistanceInstanceEntity> queryHistoryProcess(String assignee) {
        List<HistanceInstanceEntity> result=new ArrayList<>();
        List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
                .taskAssignee(assignee).finished().orderByHistoricActivityInstanceEndTime().desc().list();
        for(HistoricActivityInstance h : activities) {
            HistanceInstanceEntity d=new HistanceInstanceEntity();
            d.setProcessInstanceId(h.getProcessInstanceId());
            d.setTaskId(h.getTaskId());
            d.setStartTime(h.getStartTime());
            d.setEndTime(h.getEndTime());
            result.add(d);
    public void genProcessDiagram(HttpServletResponse httpServletResponse,
                                  String processInstanceId) throws Exception{
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().
                processInstanceId(processInstanceId).singleResult();
        //流程走完的不显示图
        if (pi == null) {
//            System.out.println("不存在该流程或则流程已经走完");
            throw new RuntimeException("不存在该流程或则流程已经走完");
//            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<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engineConf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engineConf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel,
                "png",
                activityIds,
                flows,
                engineConf.getActivityFontName(),
                engineConf.getLabelFontName(),
                engineConf.getAnnotationFontName(),
                engineConf.getClassLoader(),
                1.0,true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int length = 0;
            out = httpServletResponse.getOutputStream();
            while ((length = in.read(buf)) != -1) {
                out.write(buf, 0, length);
        } finally {
            if (in != null) {
                in.close();
            if (out != null) {
                out.close();
    public boolean isExistHistoricProcessInstance(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance =
                historyService.createHistoricProcessInstanceQuery().
                        processInstanceId(processInstanceId).singleResult();
        if (historicProcessInstance == null) {
            return false;
        return true;
    public boolean isExistRunningProcessInstance(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().
        if (processInstance == null) {
    public void suspendProcessInstance(String processInstanceId) {
        runtimeService.suspendProcessInstanceById(processInstanceId);
    public void terminateProcessInstance(ParamObj paramObj) {
        runtimeService.deleteProcessInstance(paramObj.getProcessInstanceId(),paramObj.getDeleteReason());
    public void activateProcessInstance(String processInstanceId) {
        runtimeService.activateProcessInstanceById(processInstanceId);
    public void deleteProcessInstance(ParamObj paramObj) {
        //查询是否操作
        long count = runtimeService.createExecutionQuery().processInstanceId(paramObj.getProcessInstanceId()).count();
        if(count>0){
            DeleteFlowableProcessInstanceCmd cmd=
                    new DeleteFlowableProcessInstanceCmd(paramObj.getProcessInstanceId(),
                            paramObj.getDeleteReason(),true);
            managementService.executeCommand(cmd);
            //runtimeService.deleteProcessInstance(processInstanceId,deleteReason);
        }else{
            //删除历史数据的流程实体
            historyService.deleteHistoricProcessInstance(paramObj.getProcessInstanceId());
    public void rollbackTask(String taskId, String targetTaskKey) {
        Task currentTask = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (currentTask == null) {
            return ;
        List<String> key = new ArrayList<>();
        key.add(currentTask.getTaskDefinitionKey());
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(currentTask.getProcessInstanceId())
                .moveActivityIdsToSingleActivityId(key, targetTaskKey)
                .changeState();
    public boolean isProcessFinished(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery().finished()
                .processInstanceId(processInstanceId).count()>0;
}

实现类中注入的变量都是flowable框架中的变量,实现类中的方法的作用在接口中都有向相关注释,其中deleteProcessInstance方法中会引用一个类来删除流程实例,DeleteFlowableProcessInstanceCmd类的定义如下:

@Data
public class DeleteProcessInstanceCmd implements Command<Void>, Serializable {
    String processInstanceId;
    String deleteReason;
    //是否删除历史
    boolean cascade=true;
    public DeleteProcessInstanceCmd(){
    }
    public DeleteProcessInstanceCmd(String processInstanceId,String deleteReason){
        this.deleteReason=deleteReason;
        this.processInstanceId=processInstanceId;
    }
    public DeleteProcessInstanceCmd(String processInstanceId,
                                    String deleteReason,
                                    boolean cascade){
        this.deleteReason=deleteReason;
        this.processInstanceId=processInstanceId;
        this.cascade=cascade;
    }
    @Override
    public Void execute(CommandContext commandContext) {
        ExecutionEntity entity= CommandContextUtil.getExecutionEntityManager(commandContext)
                .findById(processInstanceId);
        if(entity!=null){
            if(entity.isDeleted()){
                return null;
            }
            if(Flowable5Util.isFlowable5ProcessDefinitionId(commandContext,entity.getProcessDefinitionId())){
                Flowable5CompatibilityHandler handler=Flowable5Util.getFlowable5CompatibilityHandler();
                handler.deleteProcessInstance(processInstanceId,deleteReason);
            }else{
                CommandContextUtil.getExecutionEntityManager(commandContext).deleteProcessInstance(entity.getProcessInstanceId(),deleteReason,cascade);
            }
        }
        return null;
    }
}

上述功能了类定义完毕后,就可以创建我们的controller类了,我们的controller类的定义如下:

@RestController
@RequestMapping("/flowableTest")
public class FlowableController {
    @Autowired
    IProcess process;
    @PostMapping("/startProcess")
    public ProcessInstanceEntity startProcess(@RequestBody ParamObj paramObj){
        return process.startProcess(paramObj);
    }
    @GetMapping("/getTaskInstance/{assignee}")
    public List<TaskInstanceEntity> taskInstance(@PathVariable("assignee") String assignee){
        return process.taskInstance(assignee);
    }
    @PutMapping("/handleTask")
    public String handleTask(@RequestBody ParamObj paramObj){
        process.handleTask(paramObj);
        return "success";
    }
    @GetMapping("/queryProcessStatus")
    public List<ProcessStatusEntity> queryProcessStatus(String processInstanceId){
        return process.queryProcessStatus(processInstanceId);
    }
    @GetMapping("/queryProcessVariables")
    public Map<String, Object> queryProcessVariables(String processInstanceId){
        return process.queryProcessVariables(processInstanceId);
    }
    @GetMapping("/queryHistoryProcess")
    public List<HistanceInstanceEntity> queryHistoryProcess(String assignee){
        return process.queryHistoryProcess(assignee);
    }
    @GetMapping("/genProcessDiagram")
    public void genProcessDiagram(HttpServletResponse httpServletResponse,
                                  String processInstanceId) throws Exception {
        process.genProcessDiagram(httpServletResponse,processInstanceId);
    }
    @GetMapping("/isExistHistoricProcessInstance")
    public boolean isExistHistoricProcessInstance(String processInstanceId){
        return process.isExistHistoricProcessInstance(processInstanceId);
    }
    @GetMapping("/isProcessFinished")
    public boolean isProcessFinished(String processInstanceId){
        return process.isProcessFinished(processInstanceId);
    }
    @GetMapping("/isExistRunningProcessInstance")
    public boolean isExistRunningProcessInstance(String processInstanceId){
        return process.isExistRunningProcessInstance(processInstanceId);
    }
    @PutMapping("/suspendProcessInstance")
    public String suspendProcessInstance(String processInstanceId){
        process.suspendProcessInstance(processInstanceId);
        return "流程 "+processInstanceId+" 已经挂起";
    }
    @PutMapping("/terminateProcessInstance")
    public String terminateProcessInstance(ParamObj paramObj){
        process.terminateProcessInstance(paramObj);
        return "流程 "+paramObj.getProcessInstanceId()+" 已经终止";
    }
    @PutMapping("/activateProcessInstance")
    public String activateProcessInstance(String processInstanceId) {
        process.activateProcessInstance(processInstanceId);
        return "流程 "+processInstanceId+" 已经激活";
    }
    @PutMapping("/deleteProcessInstance")
    public String deleteProcessInstance(ParamObj paramObj){
        process.deleteProcessInstance(paramObj);
        return "流程 "+paramObj.getProcessInstanceId()+" 已经删除";
    }
    @PutMapping("/rollback")
    public String rollbackTask(String taskId, String targetTaskKey){
        process.rollbackTask(taskId,targetTaskKey);
        return "流程回退成功";
    }
}

试运行工程,运行工程后,系统会自动生成一些表单,是一些act_和flw_开头的表单,如下,利用postman创建一个流程实例:

查看流程示例图:

调用查看任务接口,可以查看某个人有哪些任务需要处理:

调用任务处理接口:

查看处理后的结果:

以上是flowable流程框架的简单应用,更为详细的使用等待后续的挖掘......

到此这篇关于springboot整合flowable-初步入门的文章就介绍到这了,更多相关springboot整合flowable内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Data JPA框架的Repository自定义实现详解

    目录 1. Spring Data Repository自定义实现 1.1 自定义特殊repository 1.2 配置类 1.3 解决歧义 1.4 手动装配 1.5 自定义Base Repository 1. Spring Data Repository自定义实现 Spring Data提供了各种选项来创建查询方法,只需少量编码.但是当这些选项不能满足你的需求时,你也可以为资源库方法提供你自己的自定义实现.本节主要介绍如何做到这一点. 1.1 自定义特殊repository 要用自定义的功能实

  • Spring Boot中使用Spring-Retry重试框架的实现

    目录 Maven依赖 注解使用 开启Retry功能 注解@Retryable 注解@Recover 注解@CircuitBreaker RetryTemplate RetryTemplate配置 使用RetryTemplate RetryPolicy BackOffPolicy RetryListener 参考 Spring Retry提供了自动重新调用失败的操作的功能.这在错误可能是暂时的(例如瞬时网络故障)的情况下很有用. 从2.2.0版本开始,重试功能已从Spring Batch中撤出,成

  • SpringBoot+Querydsl 框架实现复杂查询解析

    目录 概述 定义查询请求 google-like查询 特定字段的类sql查询 使用Spring Data Querydsl 利用Spring Query DSL实现动态查询 概述 查询功能是在各种应用程序里面都有应用,且非常重要的功能.用户直接使用的查询功能往往是在我们做好的UI界面上进行查询,UI会将查询请求发给查询实现的服务器,或者专门负责实现查询的一个组件.市场上有专门做查询的框架,其中比较出名,应用也比较广泛的是elasticsearch. 定义查询请求 对于服务端来说,前端UI发送过来

  • 深入介绍Spring框架及故障排除

    目录 Spring的缺点 不可理解性 按注释编程 故障排除 为什么是Spring IoC? 选择 其他人在说什么 结论 前言: 曾几何时,Spring框架提供了比J2EE更轻量级和更灵活的解决方案.即使在2013年左右,我也很高兴详细了解当时的新款Spring 4.如今,7年后,当我看到春天的时候,我感到一阵恐慌.注释和@ComponentScan已经用更好的东西取代了XML,这需要一个可视化工具来理解您的系统.Spring变成了一头不断生长(和变化)的水螅.我接手并试图理解他人编写的Sprin

  • Spring Data JPA框架快速入门之数据持久化存储到数据库

    目录 1 核心概念 CrudRepository接口 PagingAndSortingRepository接口 2 查询方法 3 后续内容介绍 1 核心概念 Spring Data存储库抽象的中心接口是Repository.它把要管理的实体类以及实体类的ID类型作为类型参数.这个接口主要是作为一个标记接口,用来捕捉工作中的类型,并帮助你发现扩展这个接口的接口.CrudRepository接口为被管理的实体类提供复杂的CRUD功能. 自己可以看看Repository的扩展接口以及实现类 IDEA中

  • springboot]logback日志框架配置教程

    目录 一.application配置文件实现日志配置 日志格式占位符 二.使用logback-spring.xml实现日志配置 2.1.需求 2.2.需求实现 2.3.测试一下 logback既可以通过application配置文件进行日志的配置,又可以通过logback-spring.xml进行日志的配置.通常情况下,使用全局配置文件application.yml或properties进行配置就足够了,如果您的日志输出需求特别复杂而且需求比较个性化,可以考虑使用logback-spring.x

  • Spring Boot Rest常用框架注解详情简介

    目录 开始Spring Boot Rest的先决条件 在Spring Initializer创建Spring Boot项目 Spring Boot注解 @RestController @RequestMapping @RequestParam @PathVariable @RequestBody REST方法的特定注释 @GetMapping @PostMapping和@PutMapping @DeleteMapping 前言: 让我们了解一下Spring Boot Rest框架注释.它是如此简

  • Spring Data JPA框架快速入门之自定义Repository接口

    目录 自定义Repository接口 repository接口定义 使用Repository接口 自定义Repository接口 要定义一个repository接口,你首先需要自定义一个实体类专用的Repository接口.该接口必须扩展 Repository,并将其类型指定为实体类和实体类的 ID 类型. 如果你想为该实体类资源类型开放CRUD方法,请直接继承CrudRepository而不是Repository. repository接口定义 通常,你的repository接口会扩展Repo

  • springboot整合flowable框架入门步骤

    最近工作中有用到工作流的开发,引入了flowable工作流框架,在此记录一下springboot整合flowable工作流框架的过程,以便后续再次使用到时可以做一些参考使用,如果项目中有涉及到流程审批的话,可以使用该框架帮我们实现流程图示化展示的功能,为了快速了解flowable工作流框架的一个使用过程,我们直接步入主题,springboot整合flowable工作流框架的步骤如下: 1.首先创建一个springboot工程,然后引入flowable pom依赖,代码如下: <dependenc

  • 使用sts工具、SpringBoot整合mybatis的详细步骤

    SpringBoot 集成 Mybatis 框架 一.1.SpringBoot 集成 Mybatis 的基本步骤 第一步:添加依赖: 第二步:配置数据源: 第三步:扫描接口包. 二.详细的集成步骤如下: 1.第一步:添加依赖: 添加依赖:除了常规依赖外,需要加入 Mybatis 代码如下(示例): <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XM

  • SpringBoot整合Ehcache3的实现步骤

    目录 前言 缓存配置 maven引用 个性化配置 代码注入配置 缓存操作 缓存预热 更新操作 查询操作 缓存与数据库数据一致性 前言 公司部门老项目要迁移升级java版本,需要进行缓存相关操作,原框架未支持这部分,经过调研java相关缓存方案大致分为ehcache和redis两种,redis的value最大值为500mb且超过1mb会对存取有性能影响,业务系统需要支持列表查询缓存就不可避免的涉及到大量的数据存取过滤,ehcache支持内存+磁盘缓存不用担心缓存容量问题,所以框架初步版本决定集成e

  • SpringBoot整合JPA框架实现过程讲解

    目录 一. Spring Boot数据访问概述 二. Spring Data JPA简介 2.1 编写ORM实体类 2.2 编写Repository接口 2.2.1 继承XXRepository<T, ID>接口 2.2.2 操作数据的多种方式 2.2.3 @Transactional事务管理 2.2.4 @Moditying注解 2.3.5 复杂条件查询 三. 使用Spring Boot整合JPA 3.1 添加Spring Data JPA依赖启动器 3.2 编写ORM实体类 3.3 编写R

  • SpringBoot整合Drools的实现步骤

    Drools有什么用 从我个人所待过的公司,其中做智能酒店这个项目时就用到规则引擎Drools,将它用于处理优惠劵规则. SpringBoot整合Drools初步实战 1.导入Maven依赖 <properties> <drools.version>7.14.0.Final</drools.version> </properties> <!-- drools --> <dependency> <groupId>org.dr

  • SpringBoot整合JWT框架,解决Token跨域验证问题

    一.传统Session认证 1.认证过程 1.用户向服务器发送用户名和密码. 2.服务器验证后在当前对话(session)保存相关数据. 3.服务器向返回sessionId,写入客户端 Cookie. 4.客户端每次请求,需要通过 Cookie,将 sessionId 回传服务器. 5.服务器收到 sessionId,验证客户端. 2.存在问题 1.session保存在服务端,客户端访问高并发时,服务端压力大. 2.扩展性差,服务器集群,就需要 session 数据共享. 二.JWT简介 JWT

  • SpringBoot整合Dubbo框架,实现RPC服务远程调用

    一.Dubbo框架简介 1.框架依赖 图例说明: 1)图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层或模块,蓝色的表示与业务有交互,绿色的表示只对 Dubbo 内部交互. 2)图中背景方块 Consumer, Provider, Registry, Monitor 代表部署逻辑拓扑节点. 3)图中蓝色虚线为初始化时调用,红色虚线为运行时异步调用,红色实线为运行时同步调用. 4)图中只包含 RPC

  • SpringBoot整合Shiro框架,实现用户权限管理

    一.Shiro简介 核心角色 1)Subject:认证主体 代表当前系统的使用者,就是用户,在Shiro的认证中,认证主体通常就是userName和passWord,或者其他用户相关的唯一标识. 2)SecurityManager:安全管理器 Shiro架构中最核心的组件,通过它可以协调其他组件完成用户认证和授权.实际上,SecurityManager就是Shiro框架的控制器. 3)Realm:域对象 定义了访问数据的方式,用来连接不同的数据源,如:关系数据库,配置文件等等. 核心理念 Shi

  • SpringBoot整合MongoDB的实现步骤

    目录 一.技术介绍 1.MongoDB是什么? 二.使用步骤 1.引入maven库 2.具体使用示例 3.配置文件 4.单元测试 总结 一.技术介绍 1.MongoDB是什么? MongoDB(来自于英文单词"Humongous",中文含义为"庞大")是可以应用于各种规模的企业.各个行业以及各类应用程序的开源数据库.作为一个适用于敏捷开发的数据库,MongoDB的数据模式可以随着应用程序的发展而灵活地更新.与此同时,它也为开发人员 提供了传统数据库的功能:二级索引,

  • SpringBoot整合之SpringBoot整合MongoDB的详细步骤

    目录 一.创建项目,选择依赖 二.引入相关依赖(非必要) 三.如果是第一次使用MongoDB,首先先创建用户 四.定义核心配置文件 六.创建dao层,这里的dao层有两种写法 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的.本文介绍SpringBoot整合之SpringBoot整合MongoDB的步骤. 一

随机推荐