SpringBoot 2.1.7.RELEASE + Activiti 5.18.0 喂饭级练习手册

环境准备

win10

eclipse 2023-03

eclipse Activiti插件

Mysql 5.x

Activiti的作用等不再赘叙,直接上代码和细节

POM

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.7.RELEASE</version><relativePath /> <!-- lookup parent from repository -->
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter-basic</artifactId><version>5.18.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId></dependency>
</dependencies>

启动类

import org.activiti.spring.boot.SecurityAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}

配置文件 application.yml

首次启动时,会自动创建activiti的表

spring:datasource:driveClassName: com.mysql.cj.jdbc.Driver#&nullCatalogMeansCurrent=trueurl: jdbc:mysql://127.0.0.1:3306/act?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTCusername: rootpassword: roothikari:mininum-idle: 5idle-timeout: 30000connection-timeout: 30000maxinum-pool-size: 10max-lifetime: 60000connect-test-query: select 1

BPMN

囊括了 系统任务、用户任务、执行监听器、任务监听器、排他网关,常用的都有了

<?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="testP" name="测试一把" isExecutable="true"><startEvent id="startevent1" name="Start"><extensionElements><activiti:executionListener event="start" delegateExpression="${startListener}"></activiti:executionListener></extensionElements></startEvent><endEvent id="endevent1" name="End"><extensionElements><activiti:executionListener event="end" delegateExpression="${endListener}"></activiti:executionListener></extensionElements></endEvent><serviceTask id="servicetask1" name="Service Task1" activiti:delegateExpression="${myServiceTask1}"></serviceTask><serviceTask id="servicetask2" name="Service Task2" activiti:delegateExpression="${myServiceTask2}"></serviceTask><sequenceFlow id="flow1" sourceRef="startevent1" targetRef="servicetask1"></sequenceFlow><sequenceFlow id="flow2" sourceRef="servicetask1" targetRef="servicetask2"></sequenceFlow><userTask id="usertask1" name="User Task"><extensionElements><activiti:taskListener event="create" delegateExpression="${userTaskListener}"></activiti:taskListener></extensionElements></userTask><sequenceFlow id="flow3" sourceRef="servicetask2" targetRef="usertask1"></sequenceFlow><exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway><serviceTask id="servicetask3" name="Service Task3" activiti:delegateExpression="${myServiceTask3}"></serviceTask><serviceTask id="servicetask4" name="Service Task4" activiti:delegateExpression="${myServiceTask4}"></serviceTask><sequenceFlow id="flow4" sourceRef="usertask1" targetRef="exclusivegateway1"></sequenceFlow><sequenceFlow id="flow5" sourceRef="exclusivegateway1" targetRef="servicetask3"><conditionExpression xsi:type="tFormalExpression"><![CDATA[${age > 18}]]></conditionExpression></sequenceFlow><sequenceFlow id="flow6" sourceRef="exclusivegateway1" targetRef="servicetask4"><conditionExpression xsi:type="tFormalExpression"><![CDATA[${age <= 18}]]></conditionExpression></sequenceFlow><sequenceFlow id="flow7" sourceRef="servicetask3" targetRef="endevent1"></sequenceFlow><sequenceFlow id="flow8" sourceRef="servicetask4" targetRef="endevent1"></sequenceFlow></process><bpmndi:... 这些不展示了/>
</definitions>

部署流程

import org.activiti.engine.RepositoryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** 部署流程* * @author wusc* @since 2023年8月8日16:16:40*/
@Component
public class ProcessDeployConfig {private final Logger logger = LoggerFactory.getLogger(ProcessDeployConfig.class);@Autowiredprivate RepositoryService repositoryService;@PostConstructpublic void deploy() {logger.info("部署流程");repositoryService.createDeployment().name("我今天来测试一把").addClasspathResource("testP.bpmn")// 我这个就放在src/main/resources目录下.deploy();}
}

启动流程

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ActivitiController {private final Logger logger = LoggerFactory.getLogger(ActivitiController.class);@Autowiredprivate RuntimeService runtimeService;// 直接引用@RequestMapping("/act/start")public String start(@RequestParam(value = "name") String name, @RequestParam(value = "phone") String phone) {// 全局变量,可以放订单信息、用户信息、流程状态、流程步骤等Map<String, Object> paramMap = new HashMap<>();paramMap.put("name", name);paramMap.put("phone", phone);// 任务唯一KEY,这里一般用orderId/orderNo 等唯一键来代替,后面处理任务时有用到String uuid = UUID.randomUUID().toString();logger.info("uuid:{}", uuid);// 流程KEY,BPMN XML的IDString processKey = "testP";runtimeService.startProcessInstanceByKey(processKey, uuid, paramMap);return "success";}
}

Start 节点

start/end 不设置监听器也可以 

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;/*** 执行监听器,流程启动时触发* * @author wusc* @since 2023年8月8日16:01:48*/
@Component("startListener")
public class StartListener implements ExecutionListener {private static final long serialVersionUID = 422573009417731884L;private final Logger logger = LoggerFactory.getLogger(StartListener.class);@Overridepublic void notify(DelegateExecution execution) throws Exception {logger.info("[{}]流程开始", execution.getEngineServices().getRepositoryService().getProcessDefinition(execution.getProcessDefinitionId()).getKey());}
}

 

 系统任务

系统任务是自动化处理的,需要指定哪个类来执行逻辑

Service Task1、Task2处理方式相同,execute()方法里面写自己的逻辑即可

import java.util.Map;import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;/*** 系统自动任务,需要实现JavaDelegate,execute()执行完毕,当前任务完成,自动进入下一任务* * myServiceTask1,实例名 = 上图Main config里面的变量* * @author wusc* @since 2023年8月8日16:28:55**/
@Component("myServiceTask1")
public class MyServiceTask1 implements JavaDelegate {private final Logger logger = LoggerFactory.getLogger(MyServiceTask1.class);@Overridepublic void execute(DelegateExecution execution) throws Exception {logger.info("activitiId:{}", execution.getCurrentActivityId());logger.info("activitiName:{}", execution.getCurrentActivityName());Map<String, Object> paramMap = execution.getVariables();logger.info("获取全局变量,name={}", paramMap.get("name"));logger.info("获取全局变量,phone={}", paramMap.get("phone"));// 一套增删改查}
}

用户任务 

与系统任务不同,用户任务不指定哪个类来执行逻辑;

1. 设置监听器,给任务绑定用户;

2. 通过controller接收http请求触发,经唯一键和用户标识查到当前任务,手动Complete;

 

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;/*** 用户任务就是具体某个人的任务,所以需要先分配给具体用户,然后该用户来处理* * @author wusc* @since 2023年8月8日16:13:58**/
@Component("userTaskListener")
public class UserTaskListener implements TaskListener {private static final long serialVersionUID = -3300154910592367754L;private final Logger logger = LoggerFactory.getLogger(UserTaskListener.class);@Overridepublic void notify(DelegateTask delegateTask) {logger.info("分配用户任务到具体用户身上");delegateTask.setOwner("Pony");// 这个任务属于Pony(这里可以用 用户ID来填充)delegateTask.setAssignee("wusc");// 这个任务Pony没空处理,wusc可以帮他处理,也就是二人都可以处理}
}

处理用户任务,taskService.complete


import java.util.HashMap;
import java.util.Map;
import java.util.UUID;import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ActivitiController {private final Logger logger = LoggerFactory.getLogger(ActivitiController.class);@Autowiredprivate TaskService taskService;@RequestMapping("/complete")public String complete(@RequestParam(value = "uuid") String uuid, @RequestParam(value = "age") int age) {logger.info("age={}", age);Task task = taskService.createTaskQuery().processInstanceBusinessKey(uuid)// 通过唯一键定位.taskAssignee("wusc")// 查自己的任务.list().get(0);logger.info("完成任务,taskId={}", task.getId());Map<String, Object> userMap = new HashMap<>();userMap.put("age", age);taskService.complete(task.getId(), userMap);return "success";}}

 排他网关

排他网关通过age变量确定走哪一条路

 

 系统任务

同Service Task1一样,在execute()方法内些自己的逻辑即可,方法执行完自动到下一个节点

import java.util.Map;import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;@Component("myServiceTask3")
public class MyServiceTask3 implements JavaDelegate {private final Logger logger = LoggerFactory.getLogger(MyServiceTask3.class);@Overridepublic void execute(DelegateExecution execution) throws Exception {logger.info("activitiId:{}", execution.getCurrentActivityId());logger.info("activitiName:{}", execution.getCurrentActivityName());Map<String, Object> paramMap = execution.getVariables();logger.info("获取全局变量,age={}", paramMap.get("age"));}}

 End 节点

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;@Component("endListener")
public class EndListener implements ExecutionListener {private static final long serialVersionUID = 422573009417731884L;private final Logger logger = LoggerFactory.getLogger(EndListener.class);@Overridepublic void notify(DelegateExecution execution) throws Exception {logger.info("[{}]流程结束", execution.getEngineServices().getRepositoryService().getProcessDefinition(execution.getProcessDefinitionId()).getKey());}
}

执行日志

通过日志可以看到,启动流程后,Service Task1、Service Task2自动执行了,执行到User Task时,触发了任务监听器,给用户任务分配了具体用户

业务KEY=78bc0087-79a9-4205-bdc5-7144d936ffa9,调用完成任务接口

因为age=18,经过排他网关判断,进入Service Task4节点,最后流程结束

 

 思考题

看日志,调用完成任务接口,Service Task4的线程ID与接口处理业务时的线程ID是相同的,这是为啥?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/81708.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring-2-透彻理解Spring 注解方式创建Bean--IOC

今日目标 学习使用XML配置第三方Bean 掌握纯注解开发定义Bean对象 掌握纯注解开发IOC模式 1. 第三方资源配置管理 说明&#xff1a;以管理DataSource连接池对象为例讲解第三方资源配置管理 1.1 XML管理Druid连接池(第三方Bean)对象【重点】 数据库准备 -- 创建数据库 create …

SQL力扣练习(十)

目录 1.体育馆的人流量(501) 示例 1 解法一&#xff08;row_number&#xff08;&#xff09;&#xff09; 解法二&#xff08;自定义变量&#xff09; 解法三 2.好友申请&#xff08;602&#xff09; 示例 解法一&#xff08;union all&#xff09; 解法二 3.销售员&…

【架构设计】如何设计一个高性能短链系统

一、前言 所谓系统设计&#xff0c;就是给一个场景&#xff0c;让你给出对应的架构设计&#xff0c;需要考虑哪些问题&#xff0c;采用什么方案解决。很多面试官喜欢出这么一道题来考验你的知识广度和逻辑思考能力。 虽然各个系统千差万别&#xff0c;但是设计思想基本一致&a…

如何识别手机是否有灵动岛(dynamic island)

如何识别手机是否有灵动岛&#xff08;dynamic island&#xff09; 灵动岛是苹果2022年9月推出的iPhone 14 Pro、iPhone 14 Pro Max首次出现&#xff0c;操作系统最低是iOS16.0。带灵动岛的手机在竖屏时顶部工具栏大于等于51像素。 #define isHaveDynamicIsland ({ BOOL isH…

UART实验

一、UART简介 UART Universal Asynchronous Receiver Transmitter 即通用异步收发器&#xff0c;是一种通用的串行、异步通信总线该总线有两条数据线&#xff0c;可以实现全双工的发送和接收在嵌入式系统中常用于主机与辅助设备之间的通信 二、通信基础 - 并行和串行 并行通信…

【JavaEE】Spring Boot - 项目的创建和使用

【JavaEE】Spring Boot 开发要点总结&#xff08;1&#xff09; 文章目录 【JavaEE】Spring Boot 开发要点总结&#xff08;1&#xff09;1. Spring Boot 的优点2. Spring Boot 项目创建2.1 下载安装插件2.2 创建项目过程2.3 加载项目2.4 启动项目2.5 删除一些没用的文件 3. Sp…

GCC编译过程:预处理->编译->汇编->链接

目录 引言 概括介绍 一、预处理 二、编译 三、汇编 四、链接 总结 引言 当使用集成开发环境&#xff08;IDE&#xff09;进行C语言编程时&#xff0c;点击"编译"按钮后&#xff0c;整个C程序从源代码到可执行文件的生成过程会自动完成。IDE会在后台为我们执行C…

Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用

目录 引出使用token的权限验证方法流程 用户、角色、权限表设计权限表角色表角色-权限关联表用户表查询用户的权限&#xff08;四表联查&#xff09;数据库的视图 项目中的应用自定义注解拦截器controller层DTO返回给前端枚举类型的json化日期json问题 实体类-DAO 总结 引出 1.…

Linux usb设备固定端口号

Linux usb设备固定端口号 一:/sys/bus/usb/devices/二:设备信息三:固定usb设备名方法 一:/sys/bus/usb/devices/ 信息显示如下 1-0:1.0 1&#xff1a;表示 1 号总线&#xff0c;或者说 1 号 Root Hub0&#xff1a;表示端口号1&#xff1a;表示配置号0&#xff1a;表示接口号命…

flink+kafka+doris+springboot集成例子

目录 一、例子说明 1.1、概述 1.1、所需环境 1.2、执行流程 二、部署环境 2.1、中间件部署 2.1.1部署kakfa 2.1.1.1 上传解压kafka安装包 2.1.1.2 修改zookeeper.properties 2.1.1.3 修改server.properties 2.1.1.3 启动kafka 2.1.2、部署flink 2.1.2.1 上传解压f…

SpringBoot项目-个人博客系统的实现【下】

10.实现强制要求登陆 当用户访问 博客列表页和 博客详情页时, 如果用户当前尚未登陆, 就自动跳转到登陆页面 1.添加拦截器 public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletRespon…

根文件系统制作

1.官网下载工具 制作工具&#xff1a;busybox https://busybox.net/downloads/ 2.制作根文件系统 2.1准备工作 a.把压缩包放在FSP1M目录下&#xff0c;并解压 2.2正式开始 2.2.1配置交叉编译工具链 1. 打开Makefile文件 2. 修改ARCH &#xff1f;$(SUBARCH) &#xf…

Yolov5缺陷检测/目标检测 Jetson nx部署Triton server

使用AI目标检测进行缺陷检测时&#xff0c;部署到Jetson上即小巧算力还高&#xff0c;将训练好的模型转为tensorRT再部署到Jetson 上供http或GRPC调用。1 Jetson nx 刷机 找个ubuntu 系统NVIDIA官网下载安装Jetson 的sdkmanager一步步刷机即可。 本文刷的是JetPack 5.1, 其中包…

day03

#ifndef __SEQLIST_H__ #define __SEQLIST_H__#include <stdio.h> #include <string.h> #include <stdlib.h>#define MAX 40 typedef int datatype; typedef struct {datatype data[MAX];int len; }seqlist, *seqlistPtr;//创建顺序表 seqlistPtr list_creat…

vscode连接远程Linux服务器

文章目录 一、环境安装1.1 下载vscode1.2 下载vscode-sever 二、ssh链接2.1 安装Remote-SSH2.2 设置vscode ssh2.3 设置免密登录2.3.1 本地生成公私钥2.3.2 服务器端添加公钥 三、安装插件3.1 vscode安装插件3.1.1 在线安装插件3.1.2.1 下载插件3.1.2.2 安装插件 3.2 vscode-se…

Openlayers实战:判断共享单车是否在电子围栏内

共享单车方便了我们的日常生活,解决了后一公里的行程问题。为了解决共享单车乱放的问题,运营部门规划出一些围栏,配合到电子地图上即为电子围栏,只有放在围栏内才能停车结算,在我们的Openlayers实战示例中,即模拟这一场景。 效果图 源代码 /* * @Author: 大剑师兰特(x…

【Git】Git切换地址

如何切换git代码地址&#xff1f; 1、查看当前远程 url git remote -v执行命令后&#xff0c;可以看见当前有2个URL。 远程 URL 在一般情况下有两个&#xff0c;分别是 fetch 和 push。 fetch URL 是用于从远程仓库获取最新版本的数据。当您运行 git fetch 命令时&#xf…

ThreadPoolExecutor线程池详解

ThreadPoolExecutor线程池详解 1. 背景 项目最近的迭代中使用到了ThreadPoolExecutor线程池&#xff0c;之前都只是知道怎么用&#xff0c;没有了解过线程池的底层原理&#xff0c;项目刚上线&#xff0c;有时间整理一下线程池的用法&#xff0c;学习一下线程池的底层实现与工…

运行 Jmeter 文件生成 HTML 测试报告,我选择 ANT 工具

概述 ant 是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具&#xff0c;大多用于 Java 环境中的软件开发。 在与 Jmeter 生成的 jmx 文件配合使用中&#xff0c;ant 会完成jmx计划的执行和生成jtl文件&#xff0c;并将jtl文件转化为html页面进行查看。 还可…

Node.js |(三)Node.js API:path模块及Node.js 模块化 | 尚硅谷2023版Node.js零基础视频教程

学习视频&#xff1a;尚硅谷2023版Node.js零基础视频教程&#xff0c;nodejs新手到高手 文章目录 &#x1f4da;path模块&#x1f4da;Node.js模块化&#x1f407;介绍&#x1f407;模块暴露数据⭐️模块初体验⭐️暴露数据 &#x1f407;导入文件模块&#x1f407;导入文件夹的…