Commit 290f45dd6edaa4460bf1fce072a9822245978dd8
Merge branch 'master-jdk21' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into develop
# Conflicts: # yudao-server/src/main/resources/application-local.yaml
Showing
32 changed files
with
138 additions
and
60 deletions
yudao-dependencies/pom.xml
| @@ -51,7 +51,7 @@ | @@ -51,7 +51,7 @@ | ||
| 51 | <mapstruct.version>1.5.5.Final</mapstruct.version> | 51 | <mapstruct.version>1.5.5.Final</mapstruct.version> |
| 52 | <hutool-5.version>5.8.23</hutool-5.version> | 52 | <hutool-5.version>5.8.23</hutool-5.version> |
| 53 | <hutool-6.version>6.0.0-M8</hutool-6.version> | 53 | <hutool-6.version>6.0.0-M8</hutool-6.version> |
| 54 | - <easyexcel.verion>3.3.2</easyexcel.verion> | 54 | + <easyexcel.verion>3.3.3</easyexcel.verion> |
| 55 | <velocity.version>2.3</velocity.version> | 55 | <velocity.version>2.3</velocity.version> |
| 56 | <screw.version>1.0.5</screw.version> | 56 | <screw.version>1.0.5</screw.version> |
| 57 | <fastjson.version>1.2.83</fastjson.version> | 57 | <fastjson.version>1.2.83</fastjson.version> |
| @@ -72,7 +72,7 @@ | @@ -72,7 +72,7 @@ | ||
| 72 | <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version> | 72 | <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version> |
| 73 | <tencentcloud-sdk-java.version>3.1.880</tencentcloud-sdk-java.version> | 73 | <tencentcloud-sdk-java.version>3.1.880</tencentcloud-sdk-java.version> |
| 74 | <justauth.version>2.0.5</justauth.version> | 74 | <justauth.version>2.0.5</justauth.version> |
| 75 | - <jimureport.version>1.6.1</jimureport.version> | 75 | + <jimureport.version>1.6.6-beta2</jimureport.version> |
| 76 | <xercesImpl.version>2.12.2</xercesImpl.version> | 76 | <xercesImpl.version>2.12.2</xercesImpl.version> |
| 77 | <weixin-java.version>4.5.7.B</weixin-java.version> | 77 | <weixin-java.version>4.5.7.B</weixin-java.version> |
| 78 | <ureport2.version>2.2.9</ureport2.version> | 78 | <ureport2.version>2.2.9</ureport2.version> |
| @@ -651,7 +651,7 @@ | @@ -651,7 +651,7 @@ | ||
| 651 | <!-- 积木报表--> | 651 | <!-- 积木报表--> |
| 652 | <dependency> | 652 | <dependency> |
| 653 | <groupId>org.jeecgframework.jimureport</groupId> | 653 | <groupId>org.jeecgframework.jimureport</groupId> |
| 654 | - <artifactId>jimureport-spring-boot-starter</artifactId> | 654 | + <artifactId>jimureport-spring-boot3-starter</artifactId> |
| 655 | <version>${jimureport.version}</version> | 655 | <version>${jimureport.version}</version> |
| 656 | <exclusions> | 656 | <exclusions> |
| 657 | <exclusion> | 657 | <exclusion> |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java
| 1 | package cn.iocoder.yudao.framework.common.util.cache; | 1 | package cn.iocoder.yudao.framework.common.util.cache; |
| 2 | 2 | ||
| 3 | +import com.alibaba.ttl.threadpool.TtlExecutors; | ||
| 3 | import com.google.common.cache.CacheBuilder; | 4 | import com.google.common.cache.CacheBuilder; |
| 4 | import com.google.common.cache.CacheLoader; | 5 | import com.google.common.cache.CacheLoader; |
| 5 | import com.google.common.cache.LoadingCache; | 6 | import com.google.common.cache.LoadingCache; |
| 6 | 7 | ||
| 7 | import java.time.Duration; | 8 | import java.time.Duration; |
| 9 | +import java.util.concurrent.Executor; | ||
| 8 | import java.util.concurrent.Executors; | 10 | import java.util.concurrent.Executors; |
| 9 | 11 | ||
| 10 | /** | 12 | /** |
| @@ -15,11 +17,13 @@ import java.util.concurrent.Executors; | @@ -15,11 +17,13 @@ import java.util.concurrent.Executors; | ||
| 15 | public class CacheUtils { | 17 | public class CacheUtils { |
| 16 | 18 | ||
| 17 | public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(Duration duration, CacheLoader<K, V> loader) { | 19 | public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(Duration duration, CacheLoader<K, V> loader) { |
| 20 | + Executor executor = Executors.newCachedThreadPool( // TODO 芋艿:可能要思考下,未来要不要做成可配置 | ||
| 21 | + TtlExecutors.getDefaultDisableInheritableThreadFactory()); // TTL 保证 ThreadLocal 可以透传 | ||
| 18 | return CacheBuilder.newBuilder() | 22 | return CacheBuilder.newBuilder() |
| 19 | // 只阻塞当前数据加载线程,其他线程返回旧值 | 23 | // 只阻塞当前数据加载线程,其他线程返回旧值 |
| 20 | .refreshAfterWrite(duration) | 24 | .refreshAfterWrite(duration) |
| 21 | // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程 | 25 | // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程 |
| 22 | - .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿:可能要思考下,未来要不要做成可配置 | 26 | + .build(CacheLoader.asyncReloading(loader, executor)); |
| 23 | } | 27 | } |
| 24 | 28 | ||
| 25 | } | 29 | } |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv
| @@ -490,6 +490,37 @@ id,name,type,parentId | @@ -490,6 +490,37 @@ id,name,type,parentId | ||
| 490 | 441700,阳江市,3,440000 | 490 | 441700,阳江市,3,440000 |
| 491 | 441800,清远市,3,440000 | 491 | 441800,清远市,3,440000 |
| 492 | 441900,东莞市,3,440000 | 492 | 441900,东莞市,3,440000 |
| 493 | +441901,莞城区,4,441900 | ||
| 494 | +441902,南城区,4,441900 | ||
| 495 | +441904,万江区,4,441900 | ||
| 496 | +441905,石碣镇,4,441900 | ||
| 497 | +441906,石龙镇,4,441900 | ||
| 498 | +441907,茶山镇,4,441900 | ||
| 499 | +441908,石排镇,4,441900 | ||
| 500 | +441909,企石镇,4,441900 | ||
| 501 | +441910,横沥镇,4,441900 | ||
| 502 | +441911,桥头镇,4,441900 | ||
| 503 | +441912,谢岗镇,4,441900 | ||
| 504 | +441913,东坑镇,4,441900 | ||
| 505 | +441914,常平镇,4,441900 | ||
| 506 | +441915,寮步镇,4,441900 | ||
| 507 | +441916,大朗镇,4,441900 | ||
| 508 | +441917,麻涌镇,4,441900 | ||
| 509 | +441918,中堂镇,4,441900 | ||
| 510 | +441919,高埗镇,4,441900 | ||
| 511 | +441920,樟木头镇,4,441900 | ||
| 512 | +441921,大岭山镇,4,441900 | ||
| 513 | +441922,望牛墩镇,4,441900 | ||
| 514 | +441923,黄江镇,4,441900 | ||
| 515 | +441924,洪梅镇,4,441900 | ||
| 516 | +441925,清溪镇,4,441900 | ||
| 517 | +441926,沙田镇,4,441900 | ||
| 518 | +441927,道滘镇,4,441900 | ||
| 519 | +441928,塘厦镇,4,441900 | ||
| 520 | +441929,虎门镇,4,441900 | ||
| 521 | +441930,厚街镇,4,441900 | ||
| 522 | +441931,凤岗镇,4,441900 | ||
| 523 | +441932,长安镇,4,441900 | ||
| 493 | 442000,中山市,3,440000 | 524 | 442000,中山市,3,440000 |
| 494 | 445100,潮州市,3,440000 | 525 | 445100,潮州市,3,440000 |
| 495 | 445200,揭阳市,3,440000 | 526 | 445200,揭阳市,3,440000 |
| @@ -3605,4 +3636,4 @@ id,name,type,parentId | @@ -3605,4 +3636,4 @@ id,name,type,parentId | ||
| 3605 | 659008,可克达拉市,4,659000 | 3636 | 659008,可克达拉市,4,659000 |
| 3606 | 659009,昆玉市,4,659000 | 3637 | 659009,昆玉市,4,659000 |
| 3607 | 659010,胡杨河市,4,659000 | 3638 | 659010,胡杨河市,4,659000 |
| 3608 | -659011,新星市,4,659000 | 3639 | -659011,新星市,4,659000 |
| 3640 | +659011,新星市,4,659000 | ||
| 3609 | \ No newline at end of file | 3641 | \ No newline at end of file |
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/AbstractSmsClient.java
| @@ -41,6 +41,7 @@ public abstract class AbstractSmsClient implements SmsClient { | @@ -41,6 +41,7 @@ public abstract class AbstractSmsClient implements SmsClient { | ||
| 41 | return; | 41 | return; |
| 42 | } | 42 | } |
| 43 | log.info("[refresh][配置({})发生变化,重新初始化]", properties); | 43 | log.info("[refresh][配置({})发生变化,重新初始化]", properties); |
| 44 | + this.properties = properties; | ||
| 44 | // 初始化 | 45 | // 初始化 |
| 45 | this.init(); | 46 | this.init(); |
| 46 | } | 47 | } |
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java
| 1 | package cn.iocoder.yudao.framework.tenant.core.context; | 1 | package cn.iocoder.yudao.framework.tenant.core.context; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.enums.DocumentEnum; | 4 | import cn.iocoder.yudao.framework.common.enums.DocumentEnum; |
| 4 | import com.alibaba.ttl.TransmittableThreadLocal; | 5 | import com.alibaba.ttl.TransmittableThreadLocal; |
| 5 | 6 | ||
| @@ -21,7 +22,7 @@ public class TenantContextHolder { | @@ -21,7 +22,7 @@ public class TenantContextHolder { | ||
| 21 | private static final ThreadLocal<Boolean> IGNORE = new TransmittableThreadLocal<>(); | 22 | private static final ThreadLocal<Boolean> IGNORE = new TransmittableThreadLocal<>(); |
| 22 | 23 | ||
| 23 | /** | 24 | /** |
| 24 | - * 获得租户编号。 | 25 | + * 获得租户编号 |
| 25 | * | 26 | * |
| 26 | * @return 租户编号 | 27 | * @return 租户编号 |
| 27 | */ | 28 | */ |
| @@ -30,6 +31,16 @@ public class TenantContextHolder { | @@ -30,6 +31,16 @@ public class TenantContextHolder { | ||
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | /** | 33 | /** |
| 34 | + * 获得租户编号 String | ||
| 35 | + * | ||
| 36 | + * @return 租户编号 | ||
| 37 | + */ | ||
| 38 | + public static String getTenantIdStr() { | ||
| 39 | + Long tenantId = getTenantId(); | ||
| 40 | + return StrUtil.toStringOrNull(tenantId); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 33 | * 获得租户编号。如果不存在,则抛出 NullPointerException 异常 | 44 | * 获得租户编号。如果不存在,则抛出 NullPointerException 异常 |
| 34 | * | 45 | * |
| 35 | * @return 租户编号 | 46 | * @return 租户编号 |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
| 1 | package cn.iocoder.yudao.framework.excel.core.util; | 1 | package cn.iocoder.yudao.framework.excel.core.util; |
| 2 | 2 | ||
| 3 | import com.alibaba.excel.EasyExcel; | 3 | import com.alibaba.excel.EasyExcel; |
| 4 | +import com.alibaba.excel.converters.longconverter.LongStringConverter; | ||
| 4 | import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; | 5 | import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; |
| 5 | import org.springframework.web.multipart.MultipartFile; | 6 | import org.springframework.web.multipart.MultipartFile; |
| 6 | 7 | ||
| 7 | import jakarta.servlet.http.HttpServletResponse; | 8 | import jakarta.servlet.http.HttpServletResponse; |
| 8 | import java.io.IOException; | 9 | import java.io.IOException; |
| 9 | import java.net.URLEncoder; | 10 | import java.net.URLEncoder; |
| 11 | +import java.nio.charset.StandardCharsets; | ||
| 10 | import java.util.List; | 12 | import java.util.List; |
| 11 | 13 | ||
| 12 | /** | 14 | /** |
| @@ -33,9 +35,10 @@ public class ExcelUtils { | @@ -33,9 +35,10 @@ public class ExcelUtils { | ||
| 33 | EasyExcel.write(response.getOutputStream(), head) | 35 | EasyExcel.write(response.getOutputStream(), head) |
| 34 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 | 36 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 |
| 35 | .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 | 37 | .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 |
| 38 | + .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 | ||
| 36 | .sheet(sheetName).doWrite(data); | 39 | .sheet(sheetName).doWrite(data); |
| 37 | // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 | 40 | // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 |
| 38 | - response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); | 41 | + response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8)); |
| 39 | response.setContentType("application/vnd.ms-excel;charset=UTF-8"); | 42 | response.setContentType("application/vnd.ms-excel;charset=UTF-8"); |
| 40 | } | 43 | } |
| 41 | 44 |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/s3/S3FileClient.java
| @@ -81,7 +81,7 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | @@ -81,7 +81,7 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | ||
| 81 | } | 81 | } |
| 82 | // 腾讯云必须有 region,否则会报错 | 82 | // 腾讯云必须有 region,否则会报错 |
| 83 | if (config.getEndpoint().contains(ENDPOINT_TENCENT)) { | 83 | if (config.getEndpoint().contains(ENDPOINT_TENCENT)) { |
| 84 | - return StrUtil.subAfter(config.getEndpoint(), ".cos.", false) | 84 | + return StrUtil.subAfter(config.getEndpoint(), "cos.", false) |
| 85 | .replaceAll("." + ENDPOINT_TENCENT, ""); // 去除 Endpoint | 85 | .replaceAll("." + ENDPOINT_TENCENT, ""); // 去除 Endpoint |
| 86 | } | 86 | } |
| 87 | return null; | 87 | return null; |
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.flowable.config; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.flowable.config; | ||
| 3 | import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; | 3 | import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; |
| 4 | import cn.iocoder.yudao.framework.flowable.core.web.FlowableWebFilter; | 4 | import cn.iocoder.yudao.framework.flowable.core.web.FlowableWebFilter; |
| 5 | import org.springframework.boot.autoconfigure.AutoConfiguration; | 5 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 6 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||
| 6 | import org.springframework.boot.web.servlet.FilterRegistrationBean; | 7 | import org.springframework.boot.web.servlet.FilterRegistrationBean; |
| 7 | import org.springframework.context.annotation.Bean; | 8 | import org.springframework.context.annotation.Bean; |
| 8 | import org.springframework.core.task.AsyncListenableTaskExecutor; | 9 | import org.springframework.core.task.AsyncListenableTaskExecutor; |
| @@ -17,6 +18,7 @@ public class YudaoFlowableConfiguration { | @@ -17,6 +18,7 @@ public class YudaoFlowableConfiguration { | ||
| 17 | * 如果不创建,会导致项目启动时,Flowable 报错的问题 | 18 | * 如果不创建,会导致项目启动时,Flowable 报错的问题 |
| 18 | */ | 19 | */ |
| 19 | @Bean | 20 | @Bean |
| 21 | + @ConditionalOnMissingBean | ||
| 20 | public AsyncListenableTaskExecutor taskExecutor() { | 22 | public AsyncListenableTaskExecutor taskExecutor() { |
| 21 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | 23 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
| 22 | executor.setCorePoolSize(8); | 24 | executor.setCorePoolSize(8); |
| @@ -40,4 +42,5 @@ public class YudaoFlowableConfiguration { | @@ -40,4 +42,5 @@ public class YudaoFlowableConfiguration { | ||
| 40 | registrationBean.setOrder(WebFilterOrderEnum.FLOWABLE_FILTER); | 42 | registrationBean.setOrder(WebFilterOrderEnum.FLOWABLE_FILTER); |
| 41 | return registrationBean; | 43 | return registrationBean; |
| 42 | } | 44 | } |
| 45 | + | ||
| 43 | } | 46 | } |
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
| @@ -65,6 +65,12 @@ | @@ -65,6 +65,12 @@ | ||
| 65 | <dependency> | 65 | <dependency> |
| 66 | <groupId>com.baomidou</groupId> | 66 | <groupId>com.baomidou</groupId> |
| 67 | <artifactId>dynamic-datasource-spring-boot3-starter</artifactId> <!-- 多数据源 --> | 67 | <artifactId>dynamic-datasource-spring-boot3-starter</artifactId> <!-- 多数据源 --> |
| 68 | + <exclusions> | ||
| 69 | + <exclusion> | ||
| 70 | + <groupId>org.springframework.boot</groupId> | ||
| 71 | + <artifactId>spring-boot-starter-undertow</artifactId> | ||
| 72 | + </exclusion> | ||
| 73 | + </exclusions> | ||
| 68 | </dependency> | 74 | </dependency> |
| 69 | 75 | ||
| 70 | <dependency> | 76 | <dependency> |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
| @@ -136,8 +136,8 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { | @@ -136,8 +136,8 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { | ||
| 136 | * | 136 | * |
| 137 | * @param entities 实体们 | 137 | * @param entities 实体们 |
| 138 | */ | 138 | */ |
| 139 | - default void insertBatch(Collection<T> entities) { | ||
| 140 | - Db.saveBatch(entities); | 139 | + default Boolean insertBatch(Collection<T> entities) { |
| 140 | + return Db.saveBatch(entities); | ||
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | /** | 143 | /** |
| @@ -146,28 +146,28 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { | @@ -146,28 +146,28 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { | ||
| 146 | * @param entities 实体们 | 146 | * @param entities 实体们 |
| 147 | * @param size 插入数量 Db.saveBatch 默认为 1000 | 147 | * @param size 插入数量 Db.saveBatch 默认为 1000 |
| 148 | */ | 148 | */ |
| 149 | - default void insertBatch(Collection<T> entities, int size) { | ||
| 150 | - Db.saveBatch(entities, size); | 149 | + default Boolean insertBatch(Collection<T> entities, int size) { |
| 150 | + return Db.saveBatch(entities, size); | ||
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | - default void updateBatch(T update) { | ||
| 154 | - update(update, new QueryWrapper<>()); | 153 | + default int updateBatch(T update) { |
| 154 | + return update(update, new QueryWrapper<>()); | ||
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | - default void updateBatch(Collection<T> entities) { | ||
| 158 | - Db.updateBatchById(entities); | 157 | + default Boolean updateBatch(Collection<T> entities) { |
| 158 | + return Db.updateBatchById(entities); | ||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | - default void updateBatch(Collection<T> entities, int size) { | ||
| 162 | - Db.updateBatchById(entities, size); | 161 | + default Boolean updateBatch(Collection<T> entities, int size) { |
| 162 | + return Db.updateBatchById(entities, size); | ||
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | - default void insertOrUpdate(T entity) { | ||
| 166 | - Db.saveOrUpdate(entity); | 165 | + default Boolean insertOrUpdate(T entity) { |
| 166 | + return Db.saveOrUpdate(entity); | ||
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | - default void insertOrUpdateBatch(Collection<T> collection) { | ||
| 170 | - Db.saveOrUpdateBatch(collection); | 169 | + default Boolean insertOrUpdateBatch(Collection<T> collection) { |
| 170 | + return Db.saveOrUpdateBatch(collection); | ||
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | default int delete(String field, String value) { | 173 | default int delete(String field, String value) { |
yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManagerImpl.java
| @@ -66,7 +66,7 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager { | @@ -66,7 +66,7 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager { | ||
| 66 | @Override | 66 | @Override |
| 67 | public void removeSession(WebSocketSession session) { | 67 | public void removeSession(WebSocketSession session) { |
| 68 | // 移除从 idSessions 中 | 68 | // 移除从 idSessions 中 |
| 69 | - idSessions.remove(session.getId(), session); | 69 | + idSessions.remove(session.getId()); |
| 70 | // 移除从 idSessions 中 | 70 | // 移除从 idSessions 中 |
| 71 | LoginUser user = WebSocketFrameworkUtils.getLoginUser(session); | 71 | LoginUser user = WebSocketFrameworkUtils.getLoginUser(session); |
| 72 | if (user == null) { | 72 | if (user == null) { |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
| @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 7 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 7 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 8 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; | 8 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; |
| 9 | import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; | 9 | import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; |
| 10 | +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | ||
| 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; | 11 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; |
| 11 | import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; | 12 | import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; |
| 12 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | 13 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; |
| @@ -71,7 +72,8 @@ public class BpmModelServiceImpl implements BpmModelService { | @@ -71,7 +72,8 @@ public class BpmModelServiceImpl implements BpmModelService { | ||
| 71 | modelQuery.modelCategory(pageVO.getCategory()); | 72 | modelQuery.modelCategory(pageVO.getCategory()); |
| 72 | } | 73 | } |
| 73 | // 执行查询 | 74 | // 执行查询 |
| 74 | - List<Model> models = modelQuery.orderByCreateTime().desc() | 75 | + List<Model> models = modelQuery.modelTenantId(TenantContextHolder.getTenantIdStr()) |
| 76 | + .orderByCreateTime().desc() | ||
| 75 | .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); | 77 | .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); |
| 76 | 78 | ||
| 77 | // 获得 Form Map | 79 | // 获得 Form Map |
| @@ -107,6 +109,7 @@ public class BpmModelServiceImpl implements BpmModelService { | @@ -107,6 +109,7 @@ public class BpmModelServiceImpl implements BpmModelService { | ||
| 107 | // 创建流程定义 | 109 | // 创建流程定义 |
| 108 | Model model = repositoryService.newModel(); | 110 | Model model = repositoryService.newModel(); |
| 109 | BpmModelConvert.INSTANCE.copy(model, createReqVO); | 111 | BpmModelConvert.INSTANCE.copy(model, createReqVO); |
| 112 | + model.setTenantId(TenantContextHolder.getTenantIdStr()); | ||
| 110 | // 保存流程定义 | 113 | // 保存流程定义 |
| 111 | repositoryService.saveModel(model); | 114 | repositoryService.saveModel(model); |
| 112 | // 保存 BPMN XML | 115 | // 保存 BPMN XML |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
| @@ -6,6 +6,8 @@ import cn.hutool.core.util.StrUtil; | @@ -6,6 +6,8 @@ import cn.hutool.core.util.StrUtil; | ||
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; |
| 8 | import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; | 8 | import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; |
| 9 | +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; | ||
| 10 | +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | ||
| 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; | 11 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; |
| 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; | 12 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; |
| 11 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; | 13 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; |
| @@ -124,6 +126,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | @@ -124,6 +126,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | ||
| 124 | Deployment deploy = repositoryService.createDeployment() | 126 | Deployment deploy = repositoryService.createDeployment() |
| 125 | .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory()) | 127 | .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory()) |
| 126 | .addBytes(createReqDTO.getKey() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes()) | 128 | .addBytes(createReqDTO.getKey() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes()) |
| 129 | + .tenantId(TenantContextHolder.getTenantIdStr()) | ||
| 127 | .deploy(); | 130 | .deploy(); |
| 128 | 131 | ||
| 129 | // 设置 ProcessDefinition 的 category 分类 | 132 | // 设置 ProcessDefinition 的 category 分类 |
| @@ -234,6 +237,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | @@ -234,6 +237,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | ||
| 234 | definitionQuery.active(); | 237 | definitionQuery.active(); |
| 235 | } | 238 | } |
| 236 | // 执行查询 | 239 | // 执行查询 |
| 240 | + definitionQuery.processDefinitionTenantId(TenantContextHolder.getTenantIdStr()); | ||
| 237 | List<ProcessDefinition> processDefinitions = definitionQuery.list(); | 241 | List<ProcessDefinition> processDefinitions = definitionQuery.list(); |
| 238 | if (CollUtil.isEmpty(processDefinitions)) { | 242 | if (CollUtil.isEmpty(processDefinitions)) { |
| 239 | return Collections.emptyList(); | 243 | return Collections.emptyList(); |
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.framework.flowable.core.context.FlowableContextHolder; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import java.time.LocalDateTime; 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 实现类 * <p> * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * <p> * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * <p> * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @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, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } @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(LocalDateTime.now()) // 由于 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(LocalDateTime.now()) // 由于 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())); } @Override @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, Map<String, List<Long>> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables).setAssignee(assignee)); return instance.getId(); } @Override public List<Long> getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List<Long> result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } if (CollUtil.isNotEmpty(instance.getAssignee())) { return instance.getAssignee().get(taskDefinitionKey); } return Collections.emptyList(); } } | ||
| 2 | \ No newline at end of file | 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.framework.flowable.core.context.FlowableContextHolder; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import java.time.LocalDateTime; 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 实现类 * <p> * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * <p> * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * <p> * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @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() .includeProcessVariables() .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, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } @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(LocalDateTime.now()) // 由于 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(LocalDateTime.now()) // 由于 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())); } @Override @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, Map<String, List<Long>> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables).setAssignee(assignee)); return instance.getId(); } @Override public List<Long> getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List<Long> result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } if (CollUtil.isNotEmpty(instance.getAssignee())) { return instance.getAssignee().get(taskDefinitionKey); } return Collections.emptyList(); } } | ||
| 3 | \ No newline at end of file | 3 | \ No newline at end of file |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/package-info.java deleted
| 1 | -package cn.iocoder.yudao.module.bpm.service.task; |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.infra.controller.admin.file; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.infra.controller.admin.file; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.io.IoUtil; | 3 | import cn.hutool.core.io.IoUtil; |
| 4 | import cn.hutool.core.util.StrUtil; | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | +import cn.hutool.core.util.URLUtil; | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| @@ -70,6 +71,8 @@ public class FileController { | @@ -70,6 +71,8 @@ public class FileController { | ||
| 70 | if (StrUtil.isEmpty(path)) { | 71 | if (StrUtil.isEmpty(path)) { |
| 71 | throw new IllegalArgumentException("结尾的 path 路径必须传递"); | 72 | throw new IllegalArgumentException("结尾的 path 路径必须传递"); |
| 72 | } | 73 | } |
| 74 | + // 解码,解决中文路径的问题 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/ | ||
| 75 | + path = URLUtil.decode(path); | ||
| 73 | 76 | ||
| 74 | // 读取内容 | 77 | // 读取内容 |
| 75 | byte[] content = fileService.getFileContent(configId, path); | 78 | byte[] content = fileService.getFileContent(configId, path); |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/controller.vm
| 1 | package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}; | 1 | package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}; |
| 2 | 2 | ||
| 3 | import org.springframework.web.bind.annotation.*; | 3 | import org.springframework.web.bind.annotation.*; |
| 4 | -import javax.annotation.Resource; | 4 | +import jakarta.annotation.Resource; |
| 5 | import org.springframework.validation.annotation.Validated; | 5 | import org.springframework.validation.annotation.Validated; |
| 6 | #if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end | 6 | #if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end |
| 7 | 7 | ||
| @@ -9,9 +9,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; | @@ -9,9 +9,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 9 | import io.swagger.v3.oas.annotations.Parameter; | 9 | import io.swagger.v3.oas.annotations.Parameter; |
| 10 | import io.swagger.v3.oas.annotations.Operation; | 10 | import io.swagger.v3.oas.annotations.Operation; |
| 11 | 11 | ||
| 12 | -import javax.validation.constraints.*; | ||
| 13 | -import javax.validation.*; | ||
| 14 | -import javax.servlet.http.*; | 12 | +import jakarta.validation.constraints.*; |
| 13 | +import jakarta.validation.*; | ||
| 14 | +import jakarta.servlet.http.*; | ||
| 15 | import java.util.*; | 15 | import java.util.*; |
| 16 | import java.io.IOException; | 16 | import java.io.IOException; |
| 17 | 17 |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/saveReqVO.vm
| @@ -3,7 +3,7 @@ package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePac | @@ -3,7 +3,7 @@ package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePac | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.*; | 4 | import lombok.*; |
| 5 | import java.util.*; | 5 | import java.util.*; |
| 6 | -import javax.validation.constraints.*; | 6 | +import jakarta.validation.constraints.*; |
| 7 | ## 处理 BigDecimal 字段的引入 | 7 | ## 处理 BigDecimal 字段的引入 |
| 8 | import java.util.*; | 8 | import java.util.*; |
| 9 | #foreach ($column in $columns) | 9 | #foreach ($column in $columns) |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/service.vm
| 1 | package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; | 1 | package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import java.util.*; |
| 4 | -import javax.validation.*; | 4 | +import jakarta.validation.*; |
| 5 | import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; | 5 | import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; |
| 6 | import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; | 6 | import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; |
| 7 | ## 特殊:主子表专属逻辑 | 7 | ## 特殊:主子表专属逻辑 |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm
| 1 | package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; | 1 | package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; |
| 2 | 2 | ||
| 3 | import org.springframework.stereotype.Service; | 3 | import org.springframework.stereotype.Service; |
| 4 | -import javax.annotation.Resource; | 4 | +import jakarta.annotation.Resource; |
| 5 | import org.springframework.validation.annotation.Validated; | 5 | import org.springframework.validation.annotation.Validated; |
| 6 | import org.springframework.transaction.annotation.Transactional; | 6 | import org.springframework.transaction.annotation.Transactional; |
| 7 | 7 |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm
| @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Disabled; | @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Disabled; | ||
| 4 | import org.junit.jupiter.api.Test; | 4 | import org.junit.jupiter.api.Test; |
| 5 | import org.springframework.boot.test.mock.mockito.MockBean; | 5 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 6 | 6 | ||
| 7 | -import javax.annotation.Resource; | 7 | +import jakarta.annotation.Resource; |
| 8 | 8 | ||
| 9 | import ${baseFrameworkPackage}.test.core.ut.BaseDbUnitTest; | 9 | import ${baseFrameworkPackage}.test.core.ut.BaseDbUnitTest; |
| 10 | 10 | ||
| @@ -13,7 +13,7 @@ import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.business | @@ -13,7 +13,7 @@ import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.business | ||
| 13 | import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper; | 13 | import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper; |
| 14 | import ${PageResultClassName}; | 14 | import ${PageResultClassName}; |
| 15 | 15 | ||
| 16 | -import javax.annotation.Resource; | 16 | +import jakarta.annotation.Resource; |
| 17 | import org.springframework.context.annotation.Import; | 17 | import org.springframework.context.annotation.Import; |
| 18 | import java.util.*; | 18 | import java.util.*; |
| 19 | import java.time.LocalDateTime; | 19 | import java.time.LocalDateTime; |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderExtensionMapper.java
| @@ -24,10 +24,10 @@ public interface PayOrderExtensionMapper extends BaseMapperX<PayOrderExtensionDO | @@ -24,10 +24,10 @@ public interface PayOrderExtensionMapper extends BaseMapperX<PayOrderExtensionDO | ||
| 24 | return selectList(PayOrderExtensionDO::getOrderId, orderId); | 24 | return selectList(PayOrderExtensionDO::getOrderId, orderId); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | - default List<PayOrderExtensionDO> selectListByStatusAndCreateTimeGe(Integer status, LocalDateTime minCreateTime) { | 27 | + default List<PayOrderExtensionDO> selectListByStatusAndCreateTimeLe(Integer status, LocalDateTime minCreateTime) { |
| 28 | return selectList(new LambdaQueryWrapper<PayOrderExtensionDO>() | 28 | return selectList(new LambdaQueryWrapper<PayOrderExtensionDO>() |
| 29 | .eq(PayOrderExtensionDO::getStatus, status) | 29 | .eq(PayOrderExtensionDO::getStatus, status) |
| 30 | - .ge(PayOrderExtensionDO::getCreateTime, minCreateTime)); | 30 | + .le(PayOrderExtensionDO::getCreateTime, minCreateTime)); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | } | 33 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
| @@ -232,7 +232,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { | @@ -232,7 +232,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { | ||
| 232 | throw exception(DEMO_ORDER_NOT_FOUND); | 232 | throw exception(DEMO_ORDER_NOT_FOUND); |
| 233 | } | 233 | } |
| 234 | // 1.2 校验退款订单匹配 | 234 | // 1.2 校验退款订单匹配 |
| 235 | - if (Objects.equals(order.getPayOrderId(), payRefundId)) { | 235 | + if (Objects.equals(order.getPayRefundId(), payRefundId)) { |
| 236 | log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]", | 236 | log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]", |
| 237 | id, payRefundId, toJsonString(order)); | 237 | id, payRefundId, toJsonString(order)); |
| 238 | throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR); | 238 | throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR); |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
| @@ -448,8 +448,8 @@ public class PayOrderServiceImpl implements PayOrderService { | @@ -448,8 +448,8 @@ public class PayOrderServiceImpl implements PayOrderService { | ||
| 448 | 448 | ||
| 449 | @Override | 449 | @Override |
| 450 | public int syncOrder(LocalDateTime minCreateTime) { | 450 | public int syncOrder(LocalDateTime minCreateTime) { |
| 451 | - // 1. 查询指定创建时间内的待支付订单 | ||
| 452 | - List<PayOrderExtensionDO> orderExtensions = orderExtensionMapper.selectListByStatusAndCreateTimeGe( | 451 | + // 1. 查询指定创建时间前的待支付订单 |
| 452 | + List<PayOrderExtensionDO> orderExtensions = orderExtensionMapper.selectListByStatusAndCreateTimeLe( | ||
| 453 | PayOrderStatusEnum.WAITING.getStatus(), minCreateTime); | 453 | PayOrderStatusEnum.WAITING.getStatus(), minCreateTime); |
| 454 | if (CollUtil.isEmpty(orderExtensions)) { | 454 | if (CollUtil.isEmpty(orderExtensions)) { |
| 455 | return 0; | 455 | return 0; |
yudao-module-report/yudao-module-report-biz/pom.xml
| @@ -66,7 +66,7 @@ | @@ -66,7 +66,7 @@ | ||
| 66 | <!-- 积木报表--> | 66 | <!-- 积木报表--> |
| 67 | <dependency> | 67 | <dependency> |
| 68 | <groupId>org.jeecgframework.jimureport</groupId> | 68 | <groupId>org.jeecgframework.jimureport</groupId> |
| 69 | - <artifactId>jimureport-spring-boot-starter</artifactId> | 69 | + <artifactId>jimureport-spring-boot3-starter</artifactId> |
| 70 | </dependency> | 70 | </dependency> |
| 71 | <!-- 单独依赖升级版本,解决低版本validator失败问题 --> | 71 | <!-- 单独依赖升级版本,解决低版本validator失败问题 --> |
| 72 | <dependency> | 72 | <dependency> |
yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java
| @@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | @@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | ||
| 11 | import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; | 11 | import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; |
| 12 | import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; | 12 | import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; |
| 13 | import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; | 13 | import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; |
| 14 | +import cn.iocoder.yudao.module.system.api.permission.RoleApi; | ||
| 14 | import lombok.RequiredArgsConstructor; | 15 | import lombok.RequiredArgsConstructor; |
| 15 | import org.jeecg.modules.jmreport.api.JmReportTokenServiceI; | 16 | import org.jeecg.modules.jmreport.api.JmReportTokenServiceI; |
| 16 | import org.springframework.http.HttpHeaders; | 17 | import org.springframework.http.HttpHeaders; |
| @@ -128,4 +129,20 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI { | @@ -128,4 +129,20 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI { | ||
| 128 | return user; | 129 | return user; |
| 129 | } | 130 | } |
| 130 | 131 | ||
| 132 | + @Override | ||
| 133 | + public String[] getRoles(String s) { | ||
| 134 | + // 暂时不用实现,因为不用 JmReport 的角色 | ||
| 135 | + return null; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + @Override | ||
| 139 | + public String getTenantId() { | ||
| 140 | + // 补充说明:不能直接通过 TenantContext 获取,因为 jimu 报表前端请求时,没有带上 tenant-id Header | ||
| 141 | + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); | ||
| 142 | + if (loginUser == null) { | ||
| 143 | + return null; | ||
| 144 | + } | ||
| 145 | + return StrUtil.toStringOrNull(loginUser.getTenantId()); | ||
| 146 | + } | ||
| 147 | + | ||
| 131 | } | 148 | } |
yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/ureport/config/UReportConfiguration.java
| 1 | package cn.iocoder.yudao.module.report.framework.ureport.config; | 1 | package cn.iocoder.yudao.module.report.framework.ureport.config; |
| 2 | 2 | ||
| 3 | -import com.bstek.ureport.console.UReportServlet; | ||
| 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties; | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| 5 | -import org.springframework.boot.web.servlet.ServletRegistrationBean; | ||
| 6 | -import org.springframework.context.annotation.Bean; | ||
| 7 | import org.springframework.context.annotation.Configuration; | 4 | import org.springframework.context.annotation.Configuration; |
| 8 | import org.springframework.context.annotation.ImportResource; | 5 | import org.springframework.context.annotation.ImportResource; |
| 9 | import org.springframework.context.annotation.PropertySource; | 6 | import org.springframework.context.annotation.PropertySource; |
| 10 | 7 | ||
| 11 | -import jakarta.servlet.Servlet; | ||
| 12 | - | ||
| 13 | /** | 8 | /** |
| 14 | * UReport2 配置类 | 9 | * UReport2 配置类 |
| 15 | * | 10 | * |
| 16 | * @author 赤焰 | 11 | * @author 赤焰 |
| 17 | */ | 12 | */ |
| 18 | -@Configuration | 13 | +// @Configuration TODO 芋艿:JDK21 暂时不支持 UReport2,原因是 Spring Boot 3 的 javax 替换成 jakarta 了 |
| 19 | @ImportResource({"classpath:ureport-console-context.xml"}) | 14 | @ImportResource({"classpath:ureport-console-context.xml"}) |
| 20 | @PropertySource(value = {"classpath:ureport.properties"}) // TODO @赤焰:这个可以搞到 application.yaml 里么? | 15 | @PropertySource(value = {"classpath:ureport.properties"}) // TODO @赤焰:这个可以搞到 application.yaml 里么? |
| 21 | @EnableConfigurationProperties({UReportProperties.class}) | 16 | @EnableConfigurationProperties({UReportProperties.class}) |
| 22 | public class UReportConfiguration { | 17 | public class UReportConfiguration { |
| 23 | 18 | ||
| 24 | - @Bean | ||
| 25 | - public ServletRegistrationBean<Servlet> uReportRegistrationBean() { | ||
| 26 | - return new ServletRegistrationBean<>(new UReportServlet(), "/ureport/*"); | ||
| 27 | - } | 19 | +// TODO 芋艿:JDK21 暂时不支持 UReport2,原因是 Spring Boot 3 的 javax 替换成 jakarta 了 |
| 20 | +// @Bean | ||
| 21 | +// public ServletRegistrationBean<Servlet> uReportRegistrationBean() { | ||
| 22 | +// return new ServletRegistrationBean<>(new UReportServlet(), "/ureport/*"); | ||
| 23 | +// } | ||
| 28 | 24 | ||
| 29 | } | 25 | } |
yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/ureport/core/UReportDataSource.java
| @@ -18,7 +18,7 @@ import static cn.iocoder.yudao.module.report.enums.ErrorCodeConstants.UREPORT_DA | @@ -18,7 +18,7 @@ import static cn.iocoder.yudao.module.report.enums.ErrorCodeConstants.UREPORT_DA | ||
| 18 | * @author 赤焰 | 18 | * @author 赤焰 |
| 19 | */ | 19 | */ |
| 20 | @Slf4j | 20 | @Slf4j |
| 21 | -@Component | 21 | +//@Component |
| 22 | public class UReportDataSource implements BuildinDatasource { | 22 | public class UReportDataSource implements BuildinDatasource { |
| 23 | 23 | ||
| 24 | private static final String NAME = "UReportDataSource"; | 24 | private static final String NAME = "UReportDataSource"; |
yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/ureport/core/UReportDatabaseProvider.java
| @@ -29,7 +29,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. | @@ -29,7 +29,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. | ||
| 29 | * @author 赤焰 | 29 | * @author 赤焰 |
| 30 | */ | 30 | */ |
| 31 | // TODO @赤焰:这个 bean 的注解,交给 UReportConfiguration 搞 | 31 | // TODO @赤焰:这个 bean 的注解,交给 UReportConfiguration 搞 |
| 32 | -@Component | 32 | +//@Component |
| 33 | @Slf4j | 33 | @Slf4j |
| 34 | @Setter | 34 | @Setter |
| 35 | public class UReportDatabaseProvider implements ReportProvider { | 35 | public class UReportDatabaseProvider implements ReportProvider { |
yudao-server/src/main/resources/application-dev.yaml
| @@ -5,9 +5,6 @@ server: | @@ -5,9 +5,6 @@ server: | ||
| 5 | 5 | ||
| 6 | spring: | 6 | spring: |
| 7 | # 数据源配置项 | 7 | # 数据源配置项 |
| 8 | - autoconfigure: | ||
| 9 | - exclude: | ||
| 10 | - - org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration # 排除积木报表带来的 MongoDB 的自动配置 | ||
| 11 | datasource: | 8 | datasource: |
| 12 | druid: # Druid 【监控】相关的全局配置 | 9 | druid: # Druid 【监控】相关的全局配置 |
| 13 | web-stat-filter: | 10 | web-stat-filter: |
yudao-server/src/main/resources/application-local.yaml
| @@ -7,7 +7,6 @@ spring: | @@ -7,7 +7,6 @@ spring: | ||
| 7 | # 数据源配置项 | 7 | # 数据源配置项 |
| 8 | autoconfigure: | 8 | autoconfigure: |
| 9 | exclude: | 9 | exclude: |
| 10 | - - org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration # 排除积木报表带来的 MongoDB 的自动配置 | ||
| 11 | - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置 | 10 | - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置 |
| 12 | - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 | 11 | - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 |
| 13 | - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 | 12 | - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 |
| @@ -189,6 +188,7 @@ logging: | @@ -189,6 +188,7 @@ logging: | ||
| 189 | cn.iocoder.yudao.module.promotion.dal.mysql: debug | 188 | cn.iocoder.yudao.module.promotion.dal.mysql: debug |
| 190 | cn.iocoder.yudao.module.statistics.dal.mysql: debug | 189 | cn.iocoder.yudao.module.statistics.dal.mysql: debug |
| 191 | cn.iocoder.yudao.module.crm.dal.mysql: debug | 190 | cn.iocoder.yudao.module.crm.dal.mysql: debug |
| 191 | + org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 | ||
| 192 | 192 | ||
| 193 | debug: false | 193 | debug: false |
| 194 | 194 |
yudao-server/src/main/resources/application.yaml
| @@ -264,9 +264,9 @@ yudao: | @@ -264,9 +264,9 @@ yudao: | ||
| 264 | debug: false | 264 | debug: false |
| 265 | 265 | ||
| 266 | # 积木报表配置 | 266 | # 积木报表配置 |
| 267 | -minidao : | ||
| 268 | - base-package: org.jeecg.modules.jmreport.desreport.dao* | ||
| 269 | - db-type: mysql | 267 | +jeecg: |
| 268 | + jmreport: | ||
| 269 | + saas-mode: tenant | ||
| 270 | 270 | ||
| 271 | # UReport 配置 | 271 | # UReport 配置 |
| 272 | ureport: | 272 | ureport: |