Commit 26ff75370115bf7edcbde1a497e9a050a213b22f

Authored by YunaiV
1 parent b37a535d

暂时去除回退功能,边界处理不够正确

Showing 38 changed files with 15 additions and 1306 deletions
README.md
... ... @@ -23,7 +23,7 @@
23 23 * 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统。
24 24 * 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能。
25 25 * 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装。
26   -* 工作流使用 Activiti + Flowable,支持动态表单、在线设计流程、多种任务分配方式。
  26 +* 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式。
27 27 * 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验。
28 28 * 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款。
29 29 * 集成阿里云、腾讯云、云片等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务。
... ... @@ -167,7 +167,7 @@ ps:核心功能已经实现,正在对接微信小程序中...
167 167 | [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.16 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
168 168 | [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.5.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
169 169 | [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.2 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
170   -| [Activiti](https://github.com/Activiti/Activiti) | 工作流引擎 | 7.1.0.M6 | [文档](TODO) |
  170 +| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.0 | [文档](https://doc.iocoder.cn/bpm/) |
171 171 | [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
172 172 | [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
173 173 | [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
... ...
yudao-framework/pom.xml
... ... @@ -25,7 +25,6 @@
25 25  
26 26 <module>yudao-spring-boot-starter-excel</module>
27 27 <module>yudao-spring-boot-starter-test</module>
28   - <module>yudao-spring-boot-starter-extension</module>
29 28  
30 29 <module>yudao-spring-boot-starter-biz-operatelog</module>
31 30 <module>yudao-spring-boot-starter-biz-dict</module>
... ...
yudao-framework/yudao-spring-boot-starter-extension/pom.xml deleted
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project xmlns="http://maven.apache.org/POM/4.0.0"
3   - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4   - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5   - <parent>
6   - <artifactId>yudao-framework</artifactId>
7   - <groupId>cn.iocoder.boot</groupId>
8   - <version>${revision}</version>
9   - </parent>
10   - <modelVersion>4.0.0</modelVersion>
11   -
12   - <artifactId>yudao-spring-boot-starter-extension</artifactId>
13   - <packaging>jar</packaging>
14   -
15   - <name>${project.artifactId}</name>
16   - <description>扩展点组件</description>
17   - <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
18   -
19   - <properties>
20   -
21   - </properties>
22   -
23   - <dependencies>
24   - <dependency>
25   - <groupId>cn.iocoder.boot</groupId>
26   - <artifactId>yudao-common</artifactId>
27   - </dependency>
28   -
29   - <!-- Spring 核心 -->
30   - <dependency>
31   - <groupId>org.springframework</groupId>
32   - <artifactId>spring-context</artifactId>
33   - <scope>provided</scope>
34   - </dependency>
35   -
36   - <dependency>
37   - <groupId>org.springframework</groupId>
38   - <artifactId>spring-beans</artifactId>
39   - <scope>provided</scope>
40   - </dependency>
41   -
42   - <!-- Spring 核心 -->
43   - <dependency>
44   - <groupId>org.springframework.boot</groupId>
45   - <artifactId>spring-boot-starter-aop</artifactId>
46   - </dependency>
47   -
48   - <!-- 测试包 -->
49   - <dependency>
50   - <groupId>org.springframework.boot</groupId>
51   - <artifactId>spring-boot-starter-test</artifactId>
52   - <scope>test</scope>
53   - </dependency>
54   -
55   - <!-- 测试包 -->
56   - <dependency>
57   - <groupId>junit</groupId>
58   - <artifactId>junit</artifactId>
59   - <scope>test</scope>
60   - </dependency>
61   -
62   - <!-- 工具类相关 -->
63   - <dependency>
64   - <groupId>jakarta.validation</groupId>
65   - <artifactId>jakarta.validation-api</artifactId>
66   - </dependency>
67   - </dependencies>
68   -</project>
69 0 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/config/YudaoExtensionAutoConfiguration.java deleted
1   -package cn.iocoder.yudao.framework.extension.config;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.ExtensionBootstrap;
4   -import cn.iocoder.yudao.framework.extension.core.context.ExtensionContext;
5   -import cn.iocoder.yudao.framework.extension.core.context.ExtensionContextHolder;
6   -import cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor;
7   -import cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory;
8   -import cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory;
9   -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
10   -import org.springframework.context.annotation.Bean;
11   -import org.springframework.context.annotation.Configuration;
12   -
13   -/**
14   - * @description 扩展点组件自动装配
15   - * @author Qingchen
16   - * @version 1.0.0
17   - * @date 2021-08-28 21:50
18   - * @class cn.iocoder.yudao.framework.extension.config.YudaoExtensionAutoConfiguration.java
19   - */
20   -@Configuration
21   -public class YudaoExtensionAutoConfiguration {
22   -
23   - /**
24   - * 组件初始化
25   - * @return
26   - */
27   - @Bean(initMethod = "init")
28   - @ConditionalOnMissingBean(ExtensionBootstrap.class)
29   - public ExtensionBootstrap bootstrap() {
30   - return new ExtensionBootstrap();
31   - }
32   -
33   - /**
34   - * 扩展点工厂
35   - * @return
36   - */
37   - @Bean
38   - @ConditionalOnMissingBean({ExtensionRegisterFactory.class, ExtensionFactory.class})
39   - public ExtensionRegisterFactory registerFactory() {
40   - return new ExtensionRegisterFactory();
41   - }
42   -
43   - /**
44   - * 扩展组件上下文对象
45   - * @return
46   - */
47   - @Bean
48   - @ConditionalOnMissingBean({ExtensionContextHolder.class, ExtensionContext.class})
49   - public ExtensionContextHolder context() {
50   - return new ExtensionContextHolder();
51   - }
52   -
53   - /**
54   - * 扩展组件执行器
55   - * @return
56   - */
57   - @Bean
58   - @ConditionalOnMissingBean(ExtensionExecutor.class)
59   - public ExtensionExecutor executor() {
60   - return new ExtensionExecutor();
61   - }
62   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/BusinessScenario.java deleted
1   -package cn.iocoder.yudao.framework.extension.core;
2   -
3   -import javax.validation.constraints.NotNull;
4   -import java.io.Serializable;
5   -import java.util.StringJoiner;
6   -
7   -/**
8   - * @description 业务场景 = businessId + useCase + scenario, 用来标识系统中唯一的一个场景<br/>
9   - * @author Qingchen
10   - * @version 1.0.0
11   - * @date 2021-08-28 22:19
12   - * @class cn.iocoder.yudao.framework.extension.core.BusinessScenario.java
13   - */
14   -public class BusinessScenario implements Serializable {
15   -
16   - /**
17   - * 默认业务id
18   - */
19   - public final static String DEFAULT_BUSINESS_ID = "#defaultBusinessId#";
20   -
21   - /**
22   - * 默认用例
23   - */
24   - public final static String DEFAULT_USECASE = "#defaultUseCase#";
25   -
26   - /**
27   - * 默认场景
28   - */
29   - public final static String DEFAULT_SCENARIO = "#defaultScenario#";
30   -
31   - /**
32   - * 分隔符
33   - */
34   - private final static String DOT_SEPARATOR = ".";
35   -
36   - /**
37   - * 业务Id
38   - */
39   - private String businessId;
40   -
41   - /**
42   - * 用例
43   - */
44   - private String useCase;
45   -
46   - /**
47   - * 场景
48   - */
49   - private String scenario;
50   -
51   - public BusinessScenario() {
52   - this.businessId = DEFAULT_BUSINESS_ID;
53   - this.useCase = DEFAULT_USECASE;
54   - this.scenario = DEFAULT_SCENARIO;
55   - }
56   -
57   - public BusinessScenario(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario) {
58   - this.businessId = businessId;
59   - this.useCase = useCase;
60   - this.scenario = scenario;
61   - }
62   -
63   - public BusinessScenario(@NotNull String scenario) {
64   - this();
65   - this.scenario = scenario;
66   - }
67   -
68   - public BusinessScenario(@NotNull String useCase, @NotNull String scenario) {
69   - this(DEFAULT_BUSINESS_ID, useCase, scenario);
70   - }
71   -
72   - public String getBusinessId() {
73   - return businessId;
74   - }
75   -
76   - public void setBusinessId(String businessId) {
77   - this.businessId = businessId;
78   - }
79   -
80   - public String getUseCase() {
81   - return useCase;
82   - }
83   -
84   - public void setUseCase(String useCase) {
85   - this.useCase = useCase;
86   - }
87   -
88   - public String getScenario() {
89   - return scenario;
90   - }
91   -
92   - public void setScenario(String scenario) {
93   - this.scenario = scenario;
94   - }
95   -
96   - /**
97   - * 构建业务场景
98   - * @param businessId
99   - * @param useCase
100   - * @param scenario
101   - * @return
102   - */
103   - public static BusinessScenario valueOf(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario) {
104   - return new BusinessScenario(businessId, useCase, scenario);
105   - }
106   -
107   - /**
108   - * 构建业务场景
109   - * @param useCase
110   - * @param scenario
111   - * @return
112   - */
113   - public static BusinessScenario valueOf(@NotNull String useCase, @NotNull String scenario) {
114   - return new BusinessScenario(useCase, scenario);
115   - }
116   -
117   - /**
118   - * 构建业务场景
119   - * @param scenario
120   - * @return
121   - */
122   - public static BusinessScenario valueOf(@NotNull String scenario) {
123   - return new BusinessScenario(scenario);
124   - }
125   -
126   - /**
127   - * 业务场景唯一标识
128   - * @return
129   - */
130   - public String getUniqueIdentity(){
131   - return new StringJoiner(DOT_SEPARATOR).add(businessId).add(useCase).add(scenario).toString();
132   - }
133   -
134   - @Override
135   - public String toString() {
136   - return "BusinessScenario{" +
137   - "businessId='" + businessId + '\'' +
138   - ", useCase='" + useCase + '\'' +
139   - ", scenario='" + scenario + '\'' +
140   - '}';
141   - }
142   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/ExtensionBootstrap.java deleted
1   -package cn.iocoder.yudao.framework.extension.core;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory;
4   -import org.springframework.beans.BeansException;
5   -import org.springframework.beans.factory.annotation.Autowired;
6   -import org.springframework.context.ApplicationContext;
7   -import org.springframework.context.ApplicationContextAware;
8   -
9   -import javax.annotation.PostConstruct;
10   -
11   -/**
12   - * @description
13   - * @author Qingchen
14   - * @version 1.0.0
15   - * @date 2021-08-29 00:18
16   - * @class cn.iocoder.yudao.framework.extension.core.ExtensionBootstrap.java
17   - */
18   -public class ExtensionBootstrap implements ApplicationContextAware {
19   -
20   - /**
21   - * spring 容器
22   - */
23   - private ApplicationContext applicationContext;
24   -
25   - @Autowired
26   - private ExtensionRegisterFactory registerFactory;
27   -
28   - /**
29   - * 初始化
30   - */
31   - @PostConstruct
32   - public void init() {
33   - registerFactory.setApplicationContext(applicationContext);
34   - registerFactory.register(null);
35   - }
36   -
37   - @Override
38   - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
39   - this.applicationContext = applicationContext;
40   - }
41   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/context/AbstractComponentExecutor.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.context;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
4   -import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
5   -
6   -import java.util.function.Consumer;
7   -import java.util.function.Function;
8   -
9   -/**
10   - * @description 执行器通用方法
11   - * @author Qingchen
12   - * @version 1.0.0
13   - * @date 2021-08-29 00:38
14   - * @class cn.iocoder.yudao.framework.extension.core.context.AbstractComponentExecutor.java
15   - */
16   -public abstract class AbstractComponentExecutor {
17   -
18   - /**
19   - * ("业务" + "用例" + "场景")执行扩展组件,并返回执行结果
20   - * @param targetClazz
21   - * @param businessId
22   - * @param useCase
23   - * @param scenario
24   - * @param function
25   - * @param <R>
26   - * @param <T>
27   - * @return
28   - */
29   - public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String businessId, String useCase, String scenario, Function<T, R> function) {
30   - return execute(targetClazz, BusinessScenario.valueOf(businessId, useCase, scenario), function);
31   - }
32   -
33   -
34   - /**
35   - * ("用例" + "场景")执行扩展组件,并返回执行结果
36   - * @param targetClazz
37   - * @param useCase
38   - * @param scenario
39   - * @param function
40   - * @param <R>
41   - * @param <T>
42   - * @return
43   - */
44   - public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String useCase, String scenario, Function<T, R> function) {
45   - return execute(targetClazz, BusinessScenario.valueOf(useCase, scenario), function);
46   - }
47   -
48   - /**
49   - * ("场景")执行扩展组件,并返回执行结果
50   - * @param targetClazz
51   - * @param scenario
52   - * @param function
53   - * @param <R>
54   - * @param <T>
55   - * @return
56   - */
57   - public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String scenario, Function<T, R> function) {
58   - return execute(targetClazz, BusinessScenario.valueOf(scenario), function);
59   - }
60   -
61   - /**
62   - * 执行扩展组件,并返回执行结果
63   - * @param targetClazz
64   - * @param businessScenario
65   - * @param function
66   - * @param <R> Response Type
67   - * @param <T> Parameter Type
68   - * @return
69   - */
70   - public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, BusinessScenario businessScenario, Function<T, R> function) {
71   - T component = locateComponent(targetClazz, businessScenario);
72   - return function.apply(component);
73   - }
74   -
75   - /**
76   - * ("业务" + "用例" + "场景")执行扩展组件,适用于无返回值的业务
77   - * @param targetClazz
78   - * @param businessId
79   - * @param useCase
80   - * @param scenario
81   - * @param consumer
82   - * @param <T>
83   - */
84   - public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String businessId, String useCase, String scenario, Consumer<T> consumer) {
85   - accept(targetClazz, BusinessScenario.valueOf(businessId, useCase, scenario), consumer);
86   - }
87   -
88   - /**
89   - * ("场景")执行扩展组件,适用于无返回值的业务
90   - * @param targetClazz
91   - * @param useCase
92   - * @param scenario
93   - * @param consumer
94   - * @param <T>
95   - */
96   - public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String useCase, String scenario, Consumer<T> consumer) {
97   - accept(targetClazz, BusinessScenario.valueOf(useCase, scenario), consumer);
98   - }
99   -
100   - /**
101   - * ("场景")执行扩展组件,适用于无返回值的业务
102   - * @param targetClazz
103   - * @param scenario
104   - * @param consumer
105   - * @param <T>
106   - */
107   - public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String scenario, Consumer<T> consumer) {
108   - accept(targetClazz, BusinessScenario.valueOf(scenario), consumer);
109   - }
110   -
111   - /**
112   - * 执行扩展组件,适用于无返回值的业务
113   - * @param targetClazz
114   - * @param businessScenario
115   - * @param consumer
116   - * @param <T> Parameter Type
117   - */
118   - public <T extends ExtensionPoint> void accept(Class<T> targetClazz, BusinessScenario businessScenario, Consumer<T> consumer) {
119   - T component = locateComponent(targetClazz, businessScenario);
120   - consumer.accept(component);
121   - }
122   -
123   - /**
124   - * 获取/定位扩展点组件
125   - * @param targetClazz
126   - * @param businessScenario
127   - * @param <C>
128   - * @return
129   - */
130   - protected abstract <C extends ExtensionPoint> C locateComponent(Class<C> targetClazz, BusinessScenario businessScenario);
131   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/context/ExtensionContext.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.context;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
4   -import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
5   -
6   -/**
7   - * @description 上下文,包含各个扩展点的相关操作
8   - * @author Qingchen
9   - * @version 1.0.0
10   - * @date 2021-08-28 22:15
11   - * @class cn.iocoder.yudao.framework.extension.core.context.ExtensionContext.java
12   - */
13   -public interface ExtensionContext {
14   -
15   - /**
16   - * 根据业务场景唯一标识获取扩展点组件实现类
17   - * @param businessId
18   - * @param useCase
19   - * @param scenario
20   - * @param clazz
21   - * @param <T>
22   - * @return
23   - */
24   - <T extends ExtensionPoint> T getPoint(String businessId, String useCase, String scenario, Class<T> clazz);
25   -
26   - /**
27   - * 根据("实例" + "场景")获取扩展点组件实现类,其中:业务id(businessId)= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_BUSINESS_ID}
28   - * @param useCase
29   - * @param scenario
30   - * @param clazz
31   - * @param <T>
32   - * @return
33   - */
34   - <T extends ExtensionPoint> T getPoint(String useCase, String scenario, Class<T> clazz);
35   -
36   - /**
37   - * 根据("场景")获取扩展点组件实现类 <br/>
38   - * 其中:
39   - * 业务id(businessId)= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_BUSINESS_ID}
40   - * 实例(useCase)= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_USECASE}
41   - * @param scenario
42   - * @param clazz
43   - * @param <T>
44   - * @return
45   - */
46   - <T extends ExtensionPoint> T getPoint(String scenario, Class<T> clazz);
47   -
48   - /**
49   - * 根据业务场景唯一标识获取扩展点组件实现类
50   - * @param businessScenario
51   - * @param clazz
52   - * @param <T>
53   - * @return
54   - */
55   - <T extends ExtensionPoint> T getPoint(BusinessScenario businessScenario, Class<T> clazz);
56   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/context/ExtensionContextHolder.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.context;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
4   -import cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory;
5   -import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
6   -import lombok.extern.slf4j.Slf4j;
7   -import org.springframework.beans.factory.annotation.Autowired;
8   -import org.springframework.stereotype.Component;
9   -
10   -import javax.validation.constraints.NotNull;
11   -
12   -/**
13   - * @description 上下文及扩展点组件工厂的持有类
14   - * @author Qingchen
15   - * @version 1.0.0
16   - * @date 2021-08-29 00:29
17   - * @class cn.iocoder.yudao.framework.extension.core.context.ExtensionContextHolder.java
18   - */
19   -@Component
20   -@Slf4j
21   -public class ExtensionContextHolder implements ExtensionContext{
22   -
23   - @Autowired
24   - private ExtensionFactory factory;
25   -
26   - @Override
27   - public <T extends ExtensionPoint> T getPoint(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario, Class<T> clazz) {
28   - return getPoint(BusinessScenario.valueOf(businessId, useCase, scenario), clazz);
29   - }
30   -
31   - @Override
32   - public <T extends ExtensionPoint> T getPoint(@NotNull String useCase, String scenario, Class<T> clazz) {
33   - return getPoint(BusinessScenario.valueOf(useCase, scenario), clazz);
34   - }
35   -
36   - @Override
37   - public <T extends ExtensionPoint> T getPoint(@NotNull String scenario, Class<T> clazz) {
38   - return getPoint(BusinessScenario.valueOf(scenario), clazz);
39   - }
40   -
41   - @Override
42   - public <T extends ExtensionPoint> T getPoint(@NotNull BusinessScenario businessScenario, Class<T> clazz) {
43   - return factory.get(businessScenario, clazz);
44   - }
45   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/context/ExtensionExecutor.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.context;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
4   -import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
5   -import lombok.extern.slf4j.Slf4j;
6   -import org.springframework.beans.factory.annotation.Autowired;
7   -import org.springframework.stereotype.Component;
8   -
9   -/**
10   - * @description 扩展组件执行器
11   - * @author Qingchen
12   - * @version 1.0.0
13   - * @date 2021-08-29 00:32
14   - * @class cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor.java
15   - */
16   -@Component
17   -@Slf4j
18   -public class ExtensionExecutor extends AbstractComponentExecutor{
19   -
20   - @Autowired
21   - private ExtensionContextHolder contextHolder;
22   -
23   -
24   - @Override
25   - protected <C extends ExtensionPoint> C locateComponent(Class<C> targetClazz, BusinessScenario businessScenario) {
26   - return contextHolder.getPoint(businessScenario, targetClazz);
27   - }
28   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/factory/ExtensionDefinition.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.factory;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
4   -import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
5   -import lombok.Getter;
6   -import lombok.Setter;
7   -
8   -import javax.validation.constraints.NotNull;
9   -import java.io.Serializable;
10   -import java.util.Objects;
11   -
12   -/**
13   - * @description 扩展定义(扩展坐标),标识唯一一个业务场景实现
14   - * @author Qingchen
15   - * @version 1.0.0
16   - * @date 2021-08-28 23:14
17   - * @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionDefinition.java
18   - */
19   -@Setter
20   -@Getter
21   -public class ExtensionDefinition implements Serializable {
22   -
23   - /**
24   - * 业务场景唯一标识(id)
25   - */
26   - private String uniqueIdentify;
27   -
28   - /**
29   - * 扩展点实现类名称
30   - */
31   - private String extensionPointName;
32   -
33   - /**
34   - * 业务场景
35   - */
36   - private BusinessScenario businessScenario;
37   -
38   - /**
39   - * 扩展点实现类
40   - */
41   - private ExtensionPoint extensionPoint;
42   -
43   - /**
44   - * class
45   - */
46   - private Class extensionPointClass;
47   -
48   - public ExtensionDefinition() {
49   - }
50   -
51   - public ExtensionDefinition(@NotNull BusinessScenario businessScenario, @NotNull ExtensionPoint extensionPoint) {
52   - this.businessScenario = businessScenario;
53   - this.extensionPoint = extensionPoint;
54   - this.uniqueIdentify = this.businessScenario.getUniqueIdentity();
55   - this.extensionPointClass = this.extensionPoint.getClass();
56   - }
57   -
58   - /**
59   - * 构建definition
60   - * @param businessScenario
61   - * @param point
62   - * @return
63   - */
64   - public static ExtensionDefinition valueOf(@NotNull BusinessScenario businessScenario, @NotNull ExtensionPoint point) {
65   - return new ExtensionDefinition(businessScenario, point);
66   - }
67   -
68   - @Override
69   - public boolean equals(Object o) {
70   - if (this == o) {
71   - return true;
72   - }
73   - if (o == null || getClass() != o.getClass()) {
74   - return false;
75   - }
76   - ExtensionDefinition that = (ExtensionDefinition) o;
77   - return Objects.equals(uniqueIdentify, that.uniqueIdentify) && Objects.equals(extensionPointName, that.extensionPointName);
78   - }
79   -
80   - @Override
81   - public int hashCode() {
82   - final int prime = 31;
83   - int result = 1;
84   - result = prime * result + ((uniqueIdentify == null) ? 0 : uniqueIdentify.hashCode());
85   - result = prime * result + ((extensionPointName == null) ? 0 : extensionPointName.hashCode());
86   - return result;
87   - }
88   -
89   - @Override
90   - public String toString() {
91   - return "ExtensionDefinition{" +
92   - "uniqueIdentify='" + uniqueIdentify + '\'' +
93   - ", extensionPointName='" + extensionPointName + '\'' +
94   - '}';
95   - }
96   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/factory/ExtensionFactory.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.factory;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
4   -import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
5   -
6   -/**
7   - * @description 扩展点工厂
8   - * @author Qingchen
9   - * @version 1.0.0
10   - * @date 2021-08-28 23:04
11   - * @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory.java
12   - */
13   -public interface ExtensionFactory {
14   -
15   - /**
16   - * 注册所有扩展点实现类
17   - * @param basePackage
18   - */
19   - void register(String basePackage);
20   -
21   - /**
22   - * 根据业务场景获取指定类型的扩展点
23   - * @param businessScenario
24   - * @param clazz
25   - * @param <T>
26   - * @return
27   - */
28   - <T extends ExtensionPoint> T get(BusinessScenario businessScenario, Class<T> clazz);
29   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/factory/ExtensionRegisterFactory.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.factory;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
4   -import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
5   -import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
6   -import lombok.extern.slf4j.Slf4j;
7   -import org.springframework.aop.support.AopUtils;
8   -import org.springframework.context.ApplicationContext;
9   -import org.springframework.core.annotation.AnnotationUtils;
10   -import org.springframework.stereotype.Component;
11   -import org.springframework.util.ClassUtils;
12   -
13   -import javax.validation.constraints.NotNull;
14   -import java.util.Map;
15   -import java.util.concurrent.ConcurrentHashMap;
16   -
17   -/**
18   - * @description 注册工厂
19   - * @author Qingchen
20   - * @version 1.0.0
21   - * @date 2021-08-28 23:07
22   - * @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory.java
23   - */
24   -@Component
25   -@Slf4j
26   -public class ExtensionRegisterFactory implements ExtensionFactory {
27   -
28   - /**
29   - * spring ApplicationContext
30   - */
31   - private ApplicationContext applicationContext;
32   -
33   - /**
34   - * 扩展点实现类集合
35   - */
36   - private Map<String, ExtensionDefinition> registerExtensionBeans = new ConcurrentHashMap<>();
37   -
38   - @Override
39   - public void register(String basePackage) {
40   - final Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Extension.class);
41   - if(beans == null || beans.isEmpty()) {
42   - return;
43   - }
44   -
45   - beans.values().forEach(point -> doRegister((ExtensionPoint) point));
46   - log.info("业务场景相关扩展点注册完成,注册数量: {}", registerExtensionBeans.size());
47   - }
48   -
49   - @Override
50   - public <T extends ExtensionPoint> T get(BusinessScenario businessScenario, Class<T> clazz) {
51   -
52   - final ExtensionDefinition definition = registerExtensionBeans.get(businessScenario.getUniqueIdentity());
53   - if(definition == null) {
54   - log.error("获取业务场景扩展点实现失败,失败原因:尚未定义该业务场景相关扩展点。{}", businessScenario);
55   - throw new RuntimeException("尚未定义该业务场景相关扩展点 [" + businessScenario + "]");
56   - }
57   -
58   - return (T) definition.getExtensionPoint();
59   - }
60   -
61   - /**
62   - * 注册扩展点
63   - * @param point
64   - */
65   - private void doRegister(@NotNull ExtensionPoint point) {
66   - Class<?> extensionClazz = point.getClass();
67   -
68   - if (AopUtils.isAopProxy(point)) {
69   - extensionClazz = ClassUtils.getUserClass(point);
70   - }
71   -
72   - Extension extension = AnnotationUtils.findAnnotation(extensionClazz, Extension.class);
73   - final BusinessScenario businessScenario = BusinessScenario.valueOf(extension.businessId(), extension.useCase(), extension.scenario());
74   - final ExtensionDefinition definition = ExtensionDefinition.valueOf(businessScenario, point);
75   - final ExtensionDefinition exist = registerExtensionBeans.get(businessScenario.getUniqueIdentity());
76   - if(exist != null && !exist.equals(definition)) {
77   - throw new RuntimeException("相同的业务场景重复注册了不同类型的扩展点实现 :【" + definition + "】【" + exist + "】");
78   - }
79   -
80   - registerExtensionBeans.put(businessScenario.getUniqueIdentity(), definition);
81   - }
82   -
83   - public void setApplicationContext(ApplicationContext applicationContext) {
84   - this.applicationContext = applicationContext;
85   - }
86   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/package-info.java deleted
1   -/**
2   - * @description core 核心
3   - * @author Qingchen
4   - * @version 1.0.0
5   - * @date 2021-08-28 21:54
6   - * @class cn.iocoder.yudao.framework.extension.core.package-info.java
7   - */
8   -package cn.iocoder.yudao.framework.extension.core;
9 0 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/point/ExtensionPoint.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.point;
2   -/**
3   - * @description 扩展点 <br/>
4   - * 表示一块逻辑在不同的业务有不同的实现,使用扩展点做接口申明,然后用{@linkplain cn.iocoder.yudao.framework.extension.core.stereotype.Extension}(扩展)去实现扩展点。
5   - * @author Qingchen
6   - * @version 1.0.0
7   - * @date 2021-08-28 22:06
8   - * @class cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint.java
9   - */
10   -public interface ExtensionPoint {
11   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/core/stereotype/Extension.java deleted
1   -package cn.iocoder.yudao.framework.extension.core.stereotype;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
4   -import org.springframework.stereotype.Component;
5   -
6   -import java.lang.annotation.*;
7   -
8   -/**
9   - * @description 表示带注释的类是“扩展组件”
10   - * @author Qingchen
11   - * @version 1.0.0
12   - * @date 2021-08-28 21:59
13   - * @class cn.iocoder.yudao.framework.extension.core.stereotype.Extension.java
14   - */
15   -@Inherited
16   -@Retention(RetentionPolicy.RUNTIME)
17   -@Target({ElementType.TYPE})
18   -@Component
19   -public @interface Extension {
20   -
21   - /**
22   - * 业务 <br/>
23   - * 一个自负盈亏的财务主体,比如tmall、淘宝和零售通就是三个不同的业务
24   - * @return
25   - */
26   - String businessId() default BusinessScenario.DEFAULT_BUSINESS_ID;
27   -
28   - /**
29   - * 用例 <br/>
30   - * 描述了用户和系统之间的互动,每个用例提供了一个或多个场景。比如,支付订单就是一个典型的用例。
31   - * @return
32   - */
33   - String useCase() default BusinessScenario.DEFAULT_USECASE;
34   -
35   - /**
36   - * 场景 <br/>
37   - * 场景也被称为用例的实例(Instance),包括用例所有的可能情况(正常的和异常的)。比如对于"订单支付"这个用例,就有“支付宝支付”、“银行卡支付”、"微信支付"等多个场景
38   - * @return
39   - */
40   - String scenario() default BusinessScenario.DEFAULT_SCENARIO;
41   -}
yudao-framework/yudao-spring-boot-starter-extension/src/main/java/cn/iocoder/yudao/framework/extension/package-info.java deleted
1   -/**
2   - * @description 扩展点组件
3   - * @author Qingchen
4   - * @version 1.0.0
5   - * @date 2021-08-28 14:35
6   - * @class cn.iocoder.yudao.framework.extension.package-info.java
7   - */
8   -package cn.iocoder.yudao.framework.extension;
9 0 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-extension/src/main/resources/META-INF/spring.factories deleted
1   -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2   - cn.iocoder.yudao.framework.extension.config.YudaoExtensionAutoConfiguration
yudao-framework/yudao-spring-boot-starter-extension/src/test/java/cn/iocoder/yudao/framework/extension/Application.java deleted
1   -package cn.iocoder.yudao.framework.extension;
2   -
3   -import org.springframework.boot.SpringApplication;
4   -import org.springframework.boot.autoconfigure.SpringBootApplication;
5   -
6   -/**
7   - * @description Application
8   - * @author Qingchen
9   - * @version 1.0.0
10   - * @date 2021-08-30 10:32
11   - * @class cn.iocoder.yudao.framework.extension.Application.java
12   - */
13   -@SpringBootApplication
14   -public class Application {
15   -
16   - public static void main(String[] args) {
17   - SpringApplication.run(Application.class, args);
18   - }
19   -}
yudao-framework/yudao-spring-boot-starter-extension/src/test/java/cn/iocoder/yudao/framework/extension/ExtensionTest.java deleted
1   -package cn.iocoder.yudao.framework.extension;
2   -
3   -import cn.hutool.core.util.IdUtil;
4   -import cn.hutool.json.JSONUtil;
5   -import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
6   -import cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor;
7   -import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
8   -import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
9   -import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
10   -import lombok.extern.slf4j.Slf4j;
11   -import org.junit.Assert;
12   -import org.junit.Test;
13   -import org.junit.runner.RunWith;
14   -import org.springframework.beans.factory.annotation.Autowired;
15   -import org.springframework.boot.test.context.SpringBootTest;
16   -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
17   -
18   -import java.math.BigDecimal;
19   -
20   -/**
21   - * @description
22   - * @author Qingchen
23   - * @version 1.0.0
24   - * @date 2021-08-30 10:30
25   - * @class cn.iocoder.yudao.framework.extension.ExtensionTest.java
26   - */
27   -@RunWith(SpringJUnit4ClassRunner.class)
28   -@SpringBootTest(classes = Application.class)
29   -@Slf4j
30   -public class ExtensionTest {
31   -
32   - @Autowired
33   - private ExtensionExecutor extensionExecutor;
34   -
35   - @Test
36   - public void unifiedOrder() {
37   - final BusinessScenario scenario = BusinessScenario.valueOf("pay", "jsapi", "wechat");
38   - final TransactionsCommand command = new TransactionsCommand(IdUtil.objectId(), new BigDecimal(105), "Image形象店-深圳腾大-QQ公仔", "https://www.weixin.qq.com/wxpay/pay.php");
39   - final TransactionsResult result = extensionExecutor.execute(PayExtensionPoint.class, scenario, extension -> extension.unifiedOrder(command));
40   - log.info("result is: {}", JSONUtil.toJsonStr(result));
41   - Assert.assertSame("wechat", result.getChannel());
42   - }
43   -}
yudao-framework/yudao-spring-boot-starter-extension/src/test/java/cn/iocoder/yudao/framework/extension/package-info.java deleted
1   -/**
2   - * @description
3   - * @author Qingchen
4   - * @version 1.0.0
5   - * @date 2021-08-30 10:25
6   - * @class cn.iocoder.yudao.framework.extension.package-info.java
7   - */
8   -package cn.iocoder.yudao.framework.extension;
9 0 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-extension/src/test/java/cn/iocoder/yudao/framework/extension/pay/PayExtensionPoint.java deleted
1   -package cn.iocoder.yudao.framework.extension.pay;
2   -
3   -import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
4   -import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
5   -import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
6   -
7   -/**
8   - * @description 支付操作接口
9   - * @author Qingchen
10   - * @version 1.0.0
11   - * @date 2021-08-30 10:35
12   - * @class cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint.java
13   - */
14   -public interface PayExtensionPoint extends ExtensionPoint {
15   -
16   - /**
17   - * 统一下单:获取"预支付交易会话标识"
18   - * @param command
19   - * @return
20   - */
21   - TransactionsResult unifiedOrder(TransactionsCommand command);
22   -}
yudao-framework/yudao-spring-boot-starter-extension/src/test/java/cn/iocoder/yudao/framework/extension/pay/command/TransactionsCommand.java deleted
1   -package cn.iocoder.yudao.framework.extension.pay.command;
2   -
3   -import lombok.AllArgsConstructor;
4   -import lombok.Data;
5   -import lombok.NoArgsConstructor;
6   -
7   -import java.io.Serializable;
8   -import java.math.BigDecimal;
9   -
10   -/**
11   - * @description 下单请求
12   - * @author Qingchen
13   - * @version 1.0.0
14   - * @date 2021-08-30 10:48
15   - * @class cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand.java
16   - */
17   -@Data
18   -@NoArgsConstructor
19   -@AllArgsConstructor
20   -public class TransactionsCommand implements Serializable {
21   - /**
22   - * 订单编号
23   - */
24   - private String orderNo;
25   -
26   - /**
27   - * 支付金额
28   - */
29   - private BigDecimal amount;
30   -
31   - /**
32   - * 商品描述
33   - */
34   - private String productDescription;
35   -
36   - /**
37   - * 通知地址
38   - */
39   - private String notifyUrl;
40   -}
yudao-framework/yudao-spring-boot-starter-extension/src/test/java/cn/iocoder/yudao/framework/extension/pay/domain/TransactionsResult.java deleted
1   -package cn.iocoder.yudao.framework.extension.pay.domain;
2   -
3   -import lombok.*;
4   -
5   -import java.io.Serializable;
6   -
7   -/**
8   - * @description 下单: 预支付交易单返回结果
9   - * @author Qingchen
10   - * @version 1.0.0
11   - * @date 2021-08-30 10:43
12   - * @class cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult.java
13   - */
14   -@Data
15   -@AllArgsConstructor
16   -public class TransactionsResult implements Serializable {
17   -
18   - /**
19   - * 预支付交易会话标识
20   - */
21   - private String prepayId;
22   -
23   - /**
24   - * 订单编号
25   - */
26   - private String orderNo;
27   -
28   - /**
29   - * 系统内部支付单号
30   - */
31   - private String paymentNo;
32   -
33   - /**
34   - * 支付渠道:微信 or 支付宝
35   - */
36   - private String channel;
37   -
38   -
39   -}
yudao-framework/yudao-spring-boot-starter-extension/src/test/java/cn/iocoder/yudao/framework/extension/pay/impl/AlipayService.java deleted
1   -package cn.iocoder.yudao.framework.extension.pay.impl;
2   -
3   -import cn.hutool.core.util.IdUtil;
4   -import cn.hutool.json.JSONUtil;
5   -import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
6   -import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
7   -import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
8   -import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
9   -import lombok.extern.slf4j.Slf4j;
10   -
11   -/**
12   - * @description 微信 JSAPI 支付
13   - * @author Qingchen
14   - * @version 1.0.0
15   - * @date 2021-08-30 10:38
16   - * @class cn.iocoder.yudao.framework.extension.pay.impl.AlipayService.java
17   - */
18   -@Extension(businessId = "pay", useCase = "jsapi", scenario = "alipay")
19   -@Slf4j
20   -public class AlipayService implements PayExtensionPoint {
21   - @Override
22   - public TransactionsResult unifiedOrder(TransactionsCommand command) {
23   - log.info("微信 JSAPI 支付:{}", JSONUtil.toJsonStr(command));
24   - return new TransactionsResult("alipay26112221580621e9b071c00d9e093b0000", command.getOrderNo(), IdUtil.objectId(), "alipay");
25   - }
26   -}
yudao-framework/yudao-spring-boot-starter-extension/src/test/java/cn/iocoder/yudao/framework/extension/pay/impl/WechatPayService.java deleted
1   -package cn.iocoder.yudao.framework.extension.pay.impl;
2   -
3   -import cn.hutool.core.util.IdUtil;
4   -import cn.hutool.json.JSONUtil;
5   -import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
6   -import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
7   -import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
8   -import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
9   -import lombok.extern.slf4j.Slf4j;
10   -
11   -/**
12   - * @description 微信 JSAPI 支付
13   - * @author Qingchen
14   - * @version 1.0.0
15   - * @date 2021-08-30 10:37
16   - * @class cn.iocoder.yudao.framework.extension.pay.impl.WechatPayService.java
17   - */
18   -@Extension(businessId = "pay", useCase = "jsapi", scenario = "wechat")
19   -@Slf4j
20   -public class WechatPayService implements PayExtensionPoint {
21   - @Override
22   - public TransactionsResult unifiedOrder(TransactionsCommand command) {
23   - log.info("微信 JSAPI 支付:{}", JSONUtil.toJsonStr(command));
24   - return new TransactionsResult("wx26112221580621e9b071c00d9e093b0000", command.getOrderNo(), IdUtil.objectId(), "wechat");
25   - }
26   -}
yudao-framework/yudao-spring-boot-starter-extension/《芋道 Spring Boot 扩展点组件》.md deleted
1   -### 作用
2   -
3   -​ 为了解决同一个流程不同业务有不同处理逻辑而产生,减少代码中 if else 逻辑,降低代码的耦合性,通过统一的扩展形式来支撑业务的变化。
4   -
5   -### 原理
6   -
7   -​ https://blog.csdn.net/significantfrank/article/details/100074716
8   -
9   -
10   -
11   -### 使用介绍
12   -
13   -参考测试代码 `cn.iocoder.yudao.framework.extension.ExtensionTest`
14   -
15   -
16   -
17   -
18   -
19   -
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
... ... @@ -75,13 +75,4 @@ public class BpmTaskController {
75 75 return success(true);
76 76 }
77 77  
78   - @PutMapping("/back")
79   - @ApiOperation(value = "回退")
80   - // @PreAuthorize("@ss.hasPermission('bpm:task:back')")
81   - public CommonResult<Boolean> backTask(@Valid @RequestBody BpmTaskBackReqVO reqVO) {
82   - //先硬编码到 回退到第一个审批节点
83   - // String destinationTaskDefKey = "task01";
84   - return taskService.backTask(reqVO);
85   -
86   - }
87 78 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskBackReqVO.java deleted
1   -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
2   -
3   -import io.swagger.annotations.ApiModelProperty;
4   -import lombok.AllArgsConstructor;
5   -import lombok.Data;
6   -import lombok.NoArgsConstructor;
7   -
8   -import javax.validation.constraints.NotEmpty;
9   -import javax.validation.constraints.NotNull;
10   -
11   -/**
12   - * @author kemengkai
13   - * @create 2022-05-07 08:05 TODO ke:vo 类,使用 swagger 注解即可
14   - */
15   -@Data
16   -@AllArgsConstructor
17   -@NoArgsConstructor
18   -public class BpmTaskBackReqVO {
19   -
20   - // TODO ke:userId 应该使用后端的,不能前端传递,不然就越权了
21   - @ApiModelProperty(value = "用户id", required = true, example = "1")
22   - @NotEmpty(message = "用户id不能为空")
23   - private String userId;
24   -
25   - // TODO ke:procInstId、taskId、oldTaskDefKey 三个,是不是只要传递一个 taskId?字段不要存在推导关系
26   - @ApiModelProperty(value = "流程编号id", required = true, example = "730da750-cc4f-11ec-b58e-1e429355e4a0")
27   - @NotEmpty(message = "流程编号id不能为空")
28   - private String procInstId;
29   -
30   - @ApiModelProperty(value = "当前任务id", required = true, example = "730da750-cc4f-11ec-b58e-1e429355e4a0")
31   - @NotEmpty(message = "当前任务id不能为空")
32   - private String taskId;
33   -
34   - @ApiModelProperty(value = "当前流程任务id", required = true, example = "Activity_1jlembv")
35   - @NotNull(message = "当前流程任务id不能为空")
36   - private String oldTaskDefKey;
37   -
38   - @ApiModelProperty(value = "准备回退的流程任务id", required = true, example = "task01")
39   - @NotNull(message = "准备回退流程任务id不能为空")
40   - private String newTaskDefKey;
41   -
42   - @ApiModelProperty(value = "审批结果", required = true, example = "任务驳回")
43   - @NotNull(message = "审批结果")
44   - private String reason;
45   -}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java
... ... @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 4 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
5 5 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6 6 import org.apache.ibatis.annotations.Mapper;
7   -import org.apache.ibatis.annotations.Param;
8 7  
9 8 import java.util.Collection;
10 9 import java.util.List;
... ... @@ -24,28 +23,4 @@ public interface BpmTaskExtMapper extends BaseMapperX&lt;BpmTaskExtDO&gt; {
24 23 return selectOne(BpmTaskExtDO::getTaskId, taskId);
25 24 }
26 25  
27   - default List<BpmTaskExtDO> selectListByProcessInstanceId(String processInstanceId) {
28   - return selectList(BpmTaskExtDO::getProcessInstanceId, processInstanceId);
29   - }
30   -
31   - // TODO @ke:可以使用类上上面的 default 方法实现。然后,方法的命名上,要保持和 db 一样。因为 mapper 是数据层,不关注业务。例如说,这里,其实复用 updateByTaskId 方法即可
32   - /**
33   - * 任务驳回
34   - *
35   - * @param taskId 任务列表
36   - * @param reason 驳回理由
37   - *
38   - * @return 返回驳回结果,是否成功
39   - */
40   - Boolean backByTaskId(@Param("taskId") String taskId, @Param("reason") String reason);
41   -
42   - // TODO @ke:tong上哈
43   - /**
44   - * 逻辑删除任务
45   - *
46   - * @param taskIdList 任务id列表
47   - *
48   - * @return 返回是否成功
49   - */
50   - Boolean delByTaskIds(@Param("taskIdList") List<String> taskIdList);
51 26 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java
... ... @@ -5,7 +5,6 @@ import org.flowable.engine.delegate.DelegateExecution;
5 5  
6 6 import java.util.Set;
7 7  
8   -// TODO @芋艿:迁移到 bpm 的 core 下
9 8 /**
10 9 * Bpm 任务分配的自定义 Script 脚本
11 10 * 使用场景:
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
1   -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 //TODO startProcessInstance流程里面修改了 BpmProcessInstanceExt,没有提交,和下面的更新 锁持有冲突了,异步更新这个表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()).setFormVariables(variables)); BpmProcessInstanceExtDO bpmProcessInstanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()).setFormVariables(variables); asyncUpdateProcesInstance(bpmProcessInstanceExtDO); return instance.getId(); } @Async public void asyncUpdateProcesInstance(BpmProcessInstanceExtDO bpmProcessInstanceExtDO){ log.info("asyncUpdateProcesInstance ,cause MySQL Dead Lock"); processInstanceExtMapper.updateByProcessInstanceId(bpmProcessInstanceExtDO); } }
2 1 \ No newline at end of file
  2 +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); return instance.getId(); } }
3 3 \ No newline at end of file
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
... ... @@ -85,13 +85,6 @@ public interface BpmTaskService {
85 85 void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
86 86  
87 87 /**
88   - * 回退任务
89   - *
90   - * @param reqVO 回退任务信息
91   - */
92   - CommonResult<Boolean> backTask(BpmTaskBackReqVO reqVO);
93   -
94   - /**
95 88 * 将流程任务分配给指定用户
96 89 *
97 90 * @param userId 用户编号
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -2,15 +2,12 @@ package cn.iocoder.yudao.module.bpm.service.task;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.StrUtil;
5   -import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 6 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
8 7 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
9   -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
10 8 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
11 9 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
12 10 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
13   -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO;
14 11 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
15 12 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
16 13 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper;
... ... @@ -24,7 +21,6 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
24 21 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
25 22 import lombok.extern.slf4j.Slf4j;
26 23 import org.flowable.engine.HistoryService;
27   -import org.flowable.engine.RuntimeService;
28 24 import org.flowable.engine.TaskService;
29 25 import org.flowable.engine.history.HistoricProcessInstance;
30 26 import org.flowable.engine.runtime.ProcessInstance;
... ... @@ -40,7 +36,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
40 36 import javax.annotation.Resource;
41 37 import javax.validation.Valid;
42 38 import java.util.*;
43   -import java.util.stream.Collectors;
44 39  
45 40 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
46 41 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
... ... @@ -60,8 +55,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
60 55 @Resource
61 56 private TaskService taskService;
62 57 @Resource
63   - private RuntimeService runtimeService;
64   - @Resource
65 58 private HistoryService historyService;
66 59  
67 60 @Resource
... ... @@ -227,44 +220,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
227 220 }
228 221  
229 222 @Override
230   - @Transactional(rollbackFor = Exception.class)
231   - @TenantIgnore
232   - public CommonResult<Boolean> backTask(BpmTaskBackReqVO reqVO) {
233   - Long userId = Long.valueOf(reqVO.getUserId());
234   - // 校验任务存在
235   - Task task = checkTask(userId, reqVO.getTaskId());
236   - ArrayList<String> oldTaskDefKeyList = CollUtil.newArrayList(reqVO.getOldTaskDefKey());
237   -
238   - // List<HistoricActivityInstance> hisActInstList =
239   - // historyService.createHistoricActivityInstanceQuery().processInstanceId(reqVO.getProcInstId()).list();
240   - // TODO @ke:使用 historyService.createHistoricActivityInstanceQuery().processInstanceId(reqVO.getProcInstId()).list() 读取,会存在啥问题呀?
241   - List<BpmActivityDO> bpmActivityDOList = bpmActivityMapper.listAllByProcInstIdAndDelete(reqVO.getProcInstId());
242   - // List<BpmActivityDO> bpmActivityDOList = BpmTaskConvert.INSTANCE.copyList(hisActInstList, BpmActivityDO.class);
243   - // bpmActivityDOList.forEach(bpmActivityDO -> log.info("bpmActivityDO = " + bpmActivityDO));
244   - // TODO @ke:如果 开始->a->b->c->d->结束,从 d 驳回到 b 的话,这样会不会导致 a 也被删除呀?http://blog.wya1.com/article/636697030/details/7296 可以看看这篇文章哈。
245   - List<String> taskIdList = bpmActivityDOList.stream().filter(
246   - bpmActivityDO -> bpmActivityDO.getActivityId().equals(reqVO.getOldTaskDefKey())
247   - && !bpmActivityDO.getTaskId().equals(reqVO.getTaskId())).map(BpmActivityDO::getTaskId)
248   - .collect(Collectors.toList());
249   -
250   - // 使用flowable更改任务节点
251   - runtimeService.createChangeActivityStateBuilder().processInstanceId(reqVO.getProcInstId())
252   - .moveActivityIdsToSingleActivityId(oldTaskDefKeyList, reqVO.getNewTaskDefKey()).changeState();
253   -
254   - // 逻辑删除hiActInst表任务
255   - Boolean delHiActInstResult = bpmActivityMapper.delHiActInstByTaskId(taskIdList);
256   - // 逻辑删除hiTaskInst表任务
257   - Boolean delHiTaskInstResult = bpmActivityMapper.delHiTaskInstByTaskId(taskIdList);
258   - // 更新任务拓展表
259   - Boolean backResult = taskExtMapper.backByTaskId(reqVO.getTaskId(), reqVO.getReason());
260   - Boolean delTaskResult = taskExtMapper.delByTaskIds(taskIdList);
261   - if (!delHiActInstResult && !delHiTaskInstResult && !backResult && !delTaskResult) {
262   - throw new RuntimeException("任务驳回失败!!!");
263   - }
264   - return CommonResult.success(true);
265   - }
266   -
267   - @Override
268 223 public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) {
269 224 // 校验任务存在
270 225 Task task = checkTask(userId, reqVO.getId());
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/BpmActivityMapper.xml deleted
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3   -<mapper namespace="cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper">
4   -
5   - <update id="delHiActInstByTaskId">
6   - UPDATE act_hi_actinst
7   - SET delete_reason_ = 'delete task' WHERE task_id_ IN
8   - <foreach collection="taskIdList" item="item" open="(" separator="," close=")">
9   - #{item}
10   - </foreach>
11   - </update>
12   - <delete id="delHiTaskInstByTaskId">
13   - UPDATE act_hi_taskinst
14   - SET delete_reason_ = 'delete task' WHERE id_ IN
15   - <foreach collection="taskIdList" item="item" open="(" separator="," close=")">
16   - #{item}
17   - </foreach>
18   - </delete>
19   -
20   - <select id="listAllByProcInstIdAndDelete"
21   - resultType="cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO">
22   - SELECT id_ AS `id`,
23   - rev_ AS `rev`,
24   - proc_def_id_ AS `proc_def_id`,
25   - proc_inst_id_ AS `process_instance_id`,
26   - execution_id_ AS `execution_id`,
27   - act_id_ AS `activity_id`,
28   - task_id_ AS `task_id`,
29   - call_proc_inst_id_ AS `call_proc_inst_id`,
30   - act_name_ AS `activity_name`,
31   - act_type_ AS `activity_type`,
32   - assignee_ AS `assignee`,
33   - start_time_ AS `start_time`,
34   - end_time_ AS `end_time`,
35   - transaction_order_ AS `transaction_order`,
36   - duration_ AS `duration`,
37   - delete_reason_ AS `delete_reason`,
38   - tenant_id_ AS `tenant_id`
39   - FROM act_hi_actinst aha
40   - WHERE aha.proc_inst_id_ = #{procInstId}
41   - AND aha.act_type_ != 'sequenceFlow'
42   - LIMIT 500;
43   - </select>
44   -</mapper>
yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/BpmTaskExtMapper.xml deleted
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3   -<mapper namespace="cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper">
4   -
5   - <update id="backByTaskId">
6   - UPDATE bpm_task_ext
7   - SET result=2,
8   - `reason`=#{reason}
9   - WHERE task_id = #{taskId}
10   - </update>
11   - <update id="delByTaskIds">
12   - UPDATE bpm_task_ext
13   - SET result=1,
14   - `deleted`= true
15   - WHERE `task_id` IN
16   - <foreach collection="taskIdList" item="item" open="(" separator="," close=")">
17   - #{item}
18   - </foreach>
19   - </update>
20   -
21   -</mapper>
yudao-ui-admin/src/components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue
... ... @@ -2,6 +2,8 @@
2 2 <div class="panel-tab__content">
3 3 <el-form size="mini" label-width="90px" :model="model" :rules="rules" @submit.native.prevent>
4 4 <div v-if="elementBaseInfo.$type === 'bpmn:Process'"> <!-- 如果是 Process 信息的时候,使用自定义表单 -->
  5 + <el-link href="https://doc.iocoder.cn/bpm/#_3-%E4%BC%9A%E7%AD%BE-%E6%88%96%E7%AD%BE"
  6 + type="danger" target="_blank">如何实现实现会签、或签?</el-link>
5 7 <el-form-item label="流程标识" prop="key">
6 8 <el-input v-model="model.key" placeholder="请输入流标标识"
7 9 :disabled="model.id !== undefined && model.id.length > 0" @change="handleKeyUpdate" />
... ...
yudao-ui-admin/src/views/bpm/processInstance/detail.vue
... ... @@ -412,15 +412,16 @@ export default {
412 412 },
413 413 /** 处理审批退回的操作 */
414 414 handleBack(task) {
415   - const data = {
416   - id: task.id,
417   - assigneeUserId: 1
418   - }
419   - // this.$modal.msgError("暂不支持【--退回】功能!");
420   - backTask(data).then(response => {
421   - this.$modal.msgSuccess("回退成功!");
422   - this.getDetail(); // 获得最新详情
423   - });
  415 + this.$modal.msgError("暂不支持【退回】功能!");
  416 + // 可参考 http://blog.wya1.com/article/636697030/details/7296
  417 + // const data = {
  418 + // id: task.id,
  419 + // assigneeUserId: 1
  420 + // }
  421 + // backTask(data).then(response => {
  422 + // this.$modal.msgSuccess("回退成功!");
  423 + // this.getDetail(); // 获得最新详情
  424 + // });
424 425 }
425 426 }
426 427 };
... ...