Commit 787de1be94f21d945d55c2de28ad4c0db6692fdb

Authored by YunaiV
2 parents f9e64a9f 497d826a

Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/mall_product

# Conflicts:
#	sql/mysql/mall.sql
#	sql/mysql/ruoyi-vue-pro.sql
#	yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateReqVO.java
#	yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
Showing 189 changed files with 1533 additions and 2012 deletions
README.md
... ... @@ -256,7 +256,7 @@ _鍓嶇鍩轰簬 crmeb uniapp 缁忚繃鎺堟潈閲嶆瀯锛屼紭鍖栦唬鐮佸疄鐜帮紝鎺ュ叆鑺嬮
256 256  
257 257 | 妗嗘灦 | 璇存槑 | 鐗堟湰 | 瀛︿範鎸囧崡 |
258 258 |---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|
259   -| [Spring Boot](https://spring.io/projects/spring-boot) | 搴旂敤寮鍙戞鏋 | 2.7.16 | [鏂囨。](https://github.com/YunaiV/SpringBoot-Labs) |
  259 +| [Spring Boot](https://spring.io/projects/spring-boot) | 搴旂敤寮鍙戞鏋 | 2.7.17 | [鏂囨。](https://github.com/YunaiV/SpringBoot-Labs) |
260 260 | [MySQL](https://www.mysql.com/cn/) | 鏁版嵁搴撴湇鍔″櫒 | 5.7 / 8.0+ | |
261 261 | [Druid](https://github.com/alibaba/druid) | JDBC 杩炴帴姹犮佺洃鎺х粍浠 | 1.2.19 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
262 262 | [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 澧炲己宸ュ叿鍖 | 3.5.3.2 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
... ...
... ... @@ -13,16 +13,16 @@
13 13 <!-- Server 主项目 -->
14 14 <module>yudao-server</module>
15 15 <!-- 各种 module 拓展 -->
16   - <module>yudao-module-member</module>
17 16 <module>yudao-module-system</module>
18 17 <module>yudao-module-infra</module>
19   - <!-- <module>yudao-module-bpm</module>-->
  18 +<!-- <module>yudao-module-member</module>-->
  19 +<!-- <module>yudao-module-bpm</module>-->
20 20 <!-- <module>yudao-module-report</module>-->
21 21 <!-- <module>yudao-module-mp</module>-->
22   - <module>yudao-module-pay</module>
23   - <module>yudao-module-mall</module>
  22 +<!-- <module>yudao-module-pay</module>-->
  23 +<!-- <module>yudao-module-mall</module>-->
24 24 <!-- 示例项目 -->
25   - <module>yudao-example</module>
  25 +<!-- <module>yudao-example</module>-->
26 26 </modules>
27 27  
28 28 <name>${project.artifactId}</name>
... ... @@ -30,7 +30,7 @@
30 30 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
31 31  
32 32 <properties>
33   - <revision>1.8.2-snapshot</revision>
  33 + <revision>1.8.3-snapshot</revision>
34 34 <!-- Maven 相关 -->
35 35 <java.version>1.8</java.version>
36 36 <maven.compiler.source>${java.version}</maven.compiler.source>
... ... @@ -40,7 +40,7 @@
40 40 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
41 41 <!-- 看看咋放到 bom 里 -->
42 42 <lombok.version>1.18.30</lombok.version>
43   - <spring.boot.version>2.7.16</spring.boot.version>
  43 + <spring.boot.version>2.7.17</spring.boot.version>
44 44 <mapstruct.version>1.5.5.Final</mapstruct.version>
45 45 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
46 46 </properties>
... ...
yudao-dependencies/pom.xml
... ... @@ -14,28 +14,30 @@
14 14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
15 15  
16 16 <properties>
17   - <revision>1.8.2-snapshot</revision>
  17 + <revision>1.8.3-snapshot</revision>
18 18 <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
19 19 <!-- 统一依赖管理 -->
20   - <spring.boot.version>2.7.16</spring.boot.version>
  20 + <spring.boot.version>2.7.17</spring.boot.version>
21 21 <!-- Web 相关 -->
22 22 <springdoc.version>1.6.15</springdoc.version>
23 23 <knife4j.version>4.3.0</knife4j.version>
24 24 <servlet.versoin>2.5</servlet.versoin>
25 25 <!-- DB 相关 -->
26   - <druid.version>1.2.19</druid.version>
27   - <mybatis-plus.version>3.5.3.2</mybatis-plus.version>
28   - <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version>
  26 + <druid.version>1.2.20</druid.version>
  27 + <mybatis-plus.version>3.5.4</mybatis-plus.version>
  28 + <mybatis-plus-generator.version>3.5.4</mybatis-plus-generator.version>
29 29 <dynamic-datasource.version>3.6.1</dynamic-datasource.version>
30   - <mybatis-plus-join.version>1.4.6</mybatis-plus-join.version>
  30 + <mybatis-plus-join.version>1.4.7</mybatis-plus-join.version>
31 31 <redisson.version>3.18.0</redisson.version>
32   - <dm8.jdbc.version>8.1.2.141</dm8.jdbc.version>
  32 + <dm8.jdbc.version>8.1.3.62</dm8.jdbc.version>
  33 + <!-- 消息队列 -->
  34 + <rocketmq-spring.version>2.2.3</rocketmq-spring.version>
33 35 <!-- 服务保障相关 -->
34   - <lock4j.version>2.2.3</lock4j.version>
  36 + <lock4j.version>2.2.5</lock4j.version>
35 37 <resilience4j.version>1.7.1</resilience4j.version>
36 38 <!-- 监控相关 -->
37 39 <skywalking.version>8.12.0</skywalking.version>
38   - <spring-boot-admin.version>2.7.10</spring-boot-admin.version>
  40 + <spring-boot-admin.version>2.7.11</spring-boot-admin.version>
39 41 <opentracing.version>0.33.0</opentracing.version>
40 42 <!-- Test 测试相关 -->
41 43 <podam.version>7.2.11.RELEASE</podam.version>
... ... @@ -44,8 +46,8 @@
44 46 <!-- Bpm 工作流相关 -->
45 47 <flowable.version>6.8.0</flowable.version>
46 48 <!-- 工具类相关 -->
47   - <captcha-plus.version>1.0.8</captcha-plus.version>
48   - <jsoup.version>1.16.1</jsoup.version>
  49 + <captcha-plus.version>1.0.10</captcha-plus.version>
  50 + <jsoup.version>1.16.2</jsoup.version>
49 51 <lombok.version>1.18.30</lombok.version>
50 52 <mapstruct.version>1.5.5.Final</mapstruct.version>
51 53 <hutool.version>5.8.22</hutool.version>
... ... @@ -53,10 +55,10 @@
53 55 <velocity.version>2.3</velocity.version>
54 56 <screw.version>1.0.5</screw.version>
55 57 <fastjson.version>1.2.83</fastjson.version>
56   - <guava.version>32.1.2-jre</guava.version>
  58 + <guava.version>32.1.3-jre</guava.version>
57 59 <guice.version>5.1.0</guice.version>
58 60 <transmittable-thread-local.version>2.14.2</transmittable-thread-local.version>
59   - <commons-net.version>3.9.0</commons-net.version>
  61 + <commons-net.version>3.10.0</commons-net.version>
60 62 <jsch.version>0.1.55</jsch.version>
61 63 <tika-core.version>2.7.0</tika-core.version>
62 64 <ip2region.version>2.7.0</ip2region.version>
... ... @@ -67,8 +69,8 @@
67 69 <minio.version>8.5.6</minio.version>
68 70 <aliyun-java-sdk-core.version>4.6.4</aliyun-java-sdk-core.version>
69 71 <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
70   - <tencentcloud-sdk-java.version>3.1.853</tencentcloud-sdk-java.version>
71   - <justauth.version>1.0.5</justauth.version>
  72 + <tencentcloud-sdk-java.version>3.1.880</tencentcloud-sdk-java.version>
  73 + <justauth.version>1.0.7</justauth.version>
72 74 <jimureport.version>1.6.1</jimureport.version>
73 75 <xercesImpl.version>2.12.2</xercesImpl.version>
74 76 <weixin-java.version>4.5.0</weixin-java.version>
... ... @@ -98,11 +100,6 @@
98 100 </dependency>
99 101 <dependency>
100 102 <groupId>cn.iocoder.boot</groupId>
101   - <artifactId>yudao-spring-boot-starter-biz-trade</artifactId>
102   - <version>${revision}</version>
103   - </dependency>
104   - <dependency>
105   - <groupId>cn.iocoder.boot</groupId>
106 103 <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
107 104 <version>${revision}</version>
108 105 </dependency>
... ... @@ -260,6 +257,12 @@
260 257 <version>${revision}</version>
261 258 </dependency>
262 259  
  260 + <dependency>
  261 + <groupId>org.apache.rocketmq</groupId>
  262 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  263 + <version>${rocketmq-spring.version}</version>
  264 + </dependency>
  265 +
263 266 <!-- 服务保障相关 -->
264 267 <dependency>
265 268 <groupId>cn.iocoder.boot</groupId>
... ...
yudao-example/yudao-sso-demo-by-code/pom.xml
... ... @@ -21,7 +21,7 @@
21 21 <maven.compiler.target>8</maven.compiler.target>
22 22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 23 <!-- 统一依赖管理 -->
24   - <spring.boot.version>2.7.16</spring.boot.version>
  24 + <spring.boot.version>2.7.17</spring.boot.version>
25 25 </properties>
26 26  
27 27 <dependencyManagement>
... ...
yudao-example/yudao-sso-demo-by-password/pom.xml
... ... @@ -21,7 +21,7 @@
21 21 <maven.compiler.target>8</maven.compiler.target>
22 22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 23 <!-- 统一依赖管理 -->
24   - <spring.boot.version>2.7.16</spring.boot.version>
  24 + <spring.boot.version>2.7.17</spring.boot.version>
25 25 </properties>
26 26  
27 27 <dependencyManagement>
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/core/KeyValue.java
... ... @@ -4,6 +4,8 @@ import lombok.AllArgsConstructor;
4 4 import lombok.Data;
5 5 import lombok.NoArgsConstructor;
6 6  
  7 +import java.io.Serializable;
  8 +
7 9 /**
8 10 * Key Value 的键值对
9 11 *
... ... @@ -12,7 +14,7 @@ import lombok.NoArgsConstructor;
12 14 @Data
13 15 @NoArgsConstructor
14 16 @AllArgsConstructor
15   -public class KeyValue<K, V> {
  17 +public class KeyValue<K, V> implements Serializable {
16 18  
17 19 private K key;
18 20 private V value;
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
... ... @@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableMap;
8 8 import java.util.*;
9 9 import java.util.function.*;
10 10 import java.util.stream.Collectors;
  11 +import java.util.stream.Stream;
11 12  
12 13 import static java.util.Arrays.asList;
13 14  
... ... @@ -271,4 +272,20 @@ public class CollectionUtils {
271 272 return deptId == null ? Collections.emptyList() : Collections.singleton(deptId);
272 273 }
273 274  
  275 + public static <T, U> List<U> convertListByFlatMap(Collection<T> from,
  276 + Function<T, ? extends Stream<? extends U>> func) {
  277 + if (CollUtil.isEmpty(from)) {
  278 + return new ArrayList<>();
  279 + }
  280 + return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
  281 + }
  282 +
  283 + public static <T, U> Set<U> convertSetByFlatMap(Collection<T> from,
  284 + Function<T, ? extends Stream<? extends U>> func) {
  285 + if (CollUtil.isEmpty(from)) {
  286 + return new HashSet<>();
  287 + }
  288 + return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
  289 + }
  290 +
274 291 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-error-code/src/main/java/cn/iocoder/yudao/framework/errorcode/config/YudaoErrorCodeConfiguration.java renamed to yudao-framework/yudao-spring-boot-starter-biz-error-code/src/main/java/cn/iocoder/yudao/framework/errorcode/config/YudaoErrorCodeAutoConfiguration.java
... ... @@ -21,7 +21,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
21 21 @ConditionalOnProperty(prefix = "yudao.error-code", value = "enable", matchIfMissing = true) // 允许使用 yudao.error-code.enable=false 禁用访问日志
22 22 @EnableConfigurationProperties(ErrorCodeProperties.class)
23 23 @EnableScheduling // 开启调度任务的功能,因为 ErrorCodeRemoteLoader 通过定时刷新错误码
24   -public class YudaoErrorCodeConfiguration {
  24 +public class YudaoErrorCodeAutoConfiguration {
25 25  
26 26 @Bean
27 27 public ErrorCodeAutoGenerator errorCodeAutoGenerator(@Value("${spring.application.name}") String applicationName,
... ...
yudao-framework/yudao-spring-boot-starter-biz-error-code/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
1   -cn.iocoder.yudao.framework.errorcode.config.YudaoErrorCodeConfiguration
2 1 \ No newline at end of file
  2 +cn.iocoder.yudao.framework.errorcode.config.YudaoErrorCodeAutoConfiguration
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/pom.xml
... ... @@ -48,6 +48,22 @@
48 48 <dependency>
49 49 <groupId>cn.iocoder.boot</groupId>
50 50 <artifactId>yudao-spring-boot-starter-mq</artifactId>
  51 + <optional>true</optional>
  52 + </dependency>
  53 + <dependency>
  54 + <groupId>org.springframework.kafka</groupId>
  55 + <artifactId>spring-kafka</artifactId>
  56 + <optional>true</optional>
  57 + </dependency>
  58 + <dependency>
  59 + <groupId>org.springframework.amqp</groupId>
  60 + <artifactId>spring-rabbit</artifactId>
  61 + <optional>true</optional>
  62 + </dependency>
  63 + <dependency>
  64 + <groupId>org.apache.rocketmq</groupId>
  65 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  66 + <optional>true</optional>
51 67 </dependency>
52 68  
53 69 <!-- Test 测试相关 -->
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
... ... @@ -6,7 +6,9 @@ import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties;
6 6 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect;
7 7 import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
8 8 import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect;
9   -import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor;
  9 +import cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq.TenantRabbitMQInitializer;
  10 +import cn.iocoder.yudao.framework.tenant.core.mq.redis.TenantRedisMessageInterceptor;
  11 +import cn.iocoder.yudao.framework.tenant.core.mq.rocketmq.TenantRocketMQInitializer;
10 12 import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager;
11 13 import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
12 14 import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
... ... @@ -18,6 +20,7 @@ import cn.iocoder.yudao.module.system.api.tenant.TenantApi;
18 20 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
19 21 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
20 22 import org.springframework.boot.autoconfigure.AutoConfiguration;
  23 +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
21 24 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
22 25 import org.springframework.boot.context.properties.EnableConfigurationProperties;
23 26 import org.springframework.boot.web.servlet.FilterRegistrationBean;
... ... @@ -92,6 +95,18 @@ public class YudaoTenantAutoConfiguration {
92 95 return new TenantRedisMessageInterceptor();
93 96 }
94 97  
  98 + @Bean
  99 + @ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate")
  100 + public TenantRabbitMQInitializer tenantRabbitMQInitializer() {
  101 + return new TenantRabbitMQInitializer();
  102 + }
  103 +
  104 + @Bean
  105 + @ConditionalOnClass(name = "org.apache.rocketmq.spring.core.RocketMQTemplate")
  106 + public TenantRocketMQInitializer tenantRocketMQInitializer() {
  107 + return new TenantRocketMQInitializer();
  108 + }
  109 +
95 110 // ========== Job ==========
96 111  
97 112 @Bean
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.kafka;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.boot.SpringApplication;
  6 +import org.springframework.boot.env.EnvironmentPostProcessor;
  7 +import org.springframework.core.env.ConfigurableEnvironment;
  8 +
  9 +/**
  10 + * 多租户的 Kafka 的 {@link EnvironmentPostProcessor} 实现类
  11 + *
  12 + * Kafka Producer 发送消息时,增加 {@link TenantKafkaProducerInterceptor} 拦截器
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Slf4j
  17 +public class TenantKafkaEnvironmentPostProcessor implements EnvironmentPostProcessor {
  18 +
  19 + private static final String PROPERTY_KEY_INTERCEPTOR_CLASSES = "spring.kafka.producer.properties.interceptor.classes";
  20 +
  21 + @Override
  22 + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
  23 + // 添加 TenantKafkaProducerInterceptor 拦截器
  24 + try {
  25 + String value = environment.getProperty(PROPERTY_KEY_INTERCEPTOR_CLASSES);
  26 + if (StrUtil.isEmpty(value)) {
  27 + value = TenantKafkaProducerInterceptor.class.getName();
  28 + } else {
  29 + value += "," + TenantKafkaProducerInterceptor.class.getName();
  30 + }
  31 + environment.getSystemProperties().put(PROPERTY_KEY_INTERCEPTOR_CLASSES, value);
  32 + } catch (NoClassDefFoundError ignore) {
  33 + // 如果触发 NoClassDefFoundError 异常,说明 TenantKafkaProducerInterceptor 类不存在,即没引入 kafka-spring 依赖
  34 + }
  35 + }
  36 +
  37 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.kafka;
  2 +
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  5 +import org.apache.kafka.clients.producer.ProducerInterceptor;
  6 +import org.apache.kafka.clients.producer.ProducerRecord;
  7 +import org.apache.kafka.clients.producer.RecordMetadata;
  8 +import org.apache.kafka.common.header.Headers;
  9 +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
  10 +
  11 +import java.util.Map;
  12 +
  13 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  14 +
  15 +/**
  16 + * Kafka 消息队列的多租户 {@link ProducerInterceptor} 实现类
  17 + *
  18 + * 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
  19 + * 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +public class TenantKafkaProducerInterceptor implements ProducerInterceptor<Object, Object> {
  24 +
  25 + @Override
  26 + public ProducerRecord<Object, Object> onSend(ProducerRecord<Object, Object> record) {
  27 + Long tenantId = TenantContextHolder.getTenantId();
  28 + if (tenantId != null) {
  29 + Headers headers = (Headers) ReflectUtil.getFieldValue(record, "headers"); // private 属性,没有 get 方法,智能反射
  30 + headers.add(HEADER_TENANT_ID, tenantId.toString().getBytes());
  31 + }
  32 + return record;
  33 + }
  34 +
  35 + @Override
  36 + public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
  37 + }
  38 +
  39 + @Override
  40 + public void close() {
  41 + }
  42 +
  43 + @Override
  44 + public void configure(Map<String, ?> configs) {
  45 + }
  46 +
  47 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq;
  2 +
  3 +import org.springframework.amqp.rabbit.core.RabbitTemplate;
  4 +import org.springframework.beans.BeansException;
  5 +import org.springframework.beans.factory.config.BeanPostProcessor;
  6 +
  7 +/**
  8 + * 多租户的 RabbitMQ 初始化器
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +public class TenantRabbitMQInitializer implements BeanPostProcessor {
  13 +
  14 + @Override
  15 + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  16 + if (bean instanceof RabbitTemplate) {
  17 + RabbitTemplate rabbitTemplate = (RabbitTemplate) bean;
  18 + rabbitTemplate.addBeforePublishPostProcessors(new TenantRabbitMQMessagePostProcessor());
  19 + }
  20 + return bean;
  21 + }
  22 +
  23 +}
0 24 \ No newline at end of file
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq;
  2 +
  3 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  4 +import org.apache.kafka.clients.producer.ProducerInterceptor;
  5 +import org.springframework.amqp.AmqpException;
  6 +import org.springframework.amqp.core.Message;
  7 +import org.springframework.amqp.core.MessagePostProcessor;
  8 +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
  9 +
  10 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  11 +
  12 +/**
  13 + * RabbitMQ 消息队列的多租户 {@link ProducerInterceptor} 实现类
  14 + *
  15 + * 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
  16 + * 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +public class TenantRabbitMQMessagePostProcessor implements MessagePostProcessor {
  21 +
  22 + @Override
  23 + public Message postProcessMessage(Message message) throws AmqpException {
  24 + Long tenantId = TenantContextHolder.getTenantId();
  25 + if (tenantId != null) {
  26 + message.getMessageProperties().getHeaders().put(HEADER_TENANT_ID, tenantId);
  27 + }
  28 + return message;
  29 + }
  30 +
  31 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/TenantRedisMessageInterceptor.java renamed to yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/redis/TenantRedisMessageInterceptor.java
1   -package cn.iocoder.yudao.framework.tenant.core.mq;
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.redis;
2 2  
3 3 import cn.hutool.core.util.StrUtil;
4   -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;
5   -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
  4 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
6 6 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
7 7  
8 8 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  6 +import org.apache.rocketmq.client.hook.ConsumeMessageContext;
  7 +import org.apache.rocketmq.client.hook.ConsumeMessageHook;
  8 +import org.apache.rocketmq.common.message.MessageExt;
  9 +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
  10 +
  11 +import java.util.List;
  12 +
  13 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  14 +
  15 +/**
  16 + * RocketMQ 消息队列的多租户 {@link ConsumeMessageHook} 实现类
  17 + *
  18 + * Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +public class TenantRocketMQConsumeMessageHook implements ConsumeMessageHook {
  23 +
  24 + @Override
  25 + public String hookName() {
  26 + return getClass().getSimpleName();
  27 + }
  28 +
  29 + @Override
  30 + public void consumeMessageBefore(ConsumeMessageContext context) {
  31 + // 校验,消息必须是单条,不然设置租户可能不正确
  32 + List<MessageExt> messages = context.getMsgList();
  33 + Assert.isTrue(messages.size() == 1, "消息条数({})不正确", messages.size());
  34 + // 设置租户编号
  35 + String tenantId = messages.get(0).getUserProperty(HEADER_TENANT_ID);
  36 + if (StrUtil.isNotEmpty(tenantId)) {
  37 + TenantContextHolder.setTenantId(Long.parseLong(tenantId));
  38 + }
  39 + }
  40 +
  41 + @Override
  42 + public void consumeMessageAfter(ConsumeMessageContext context) {
  43 + TenantContextHolder.clear();
  44 + }
  45 +
  46 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq;
  2 +
  3 +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
  4 +import org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl;
  5 +import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl;
  6 +import org.apache.rocketmq.client.producer.DefaultMQProducer;
  7 +import org.apache.rocketmq.spring.core.RocketMQTemplate;
  8 +import org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer;
  9 +import org.springframework.beans.BeansException;
  10 +import org.springframework.beans.factory.config.BeanPostProcessor;
  11 +
  12 +/**
  13 + * 多租户的 RocketMQ 初始化器
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public class TenantRocketMQInitializer implements BeanPostProcessor {
  18 +
  19 + @Override
  20 + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  21 + if (bean instanceof DefaultRocketMQListenerContainer) {
  22 + DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer) bean;
  23 + initTenantConsumer(container.getConsumer());
  24 + } else if (bean instanceof RocketMQTemplate) {
  25 + RocketMQTemplate template = (RocketMQTemplate) bean;
  26 + initTenantProducer(template.getProducer());
  27 + }
  28 + return bean;
  29 + }
  30 +
  31 + private void initTenantProducer(DefaultMQProducer producer) {
  32 + if (producer == null) {
  33 + return;
  34 + }
  35 + DefaultMQProducerImpl producerImpl = producer.getDefaultMQProducerImpl();
  36 + if (producerImpl == null) {
  37 + return;
  38 + }
  39 + producerImpl.registerSendMessageHook(new TenantRocketMQSendMessageHook());
  40 + }
  41 +
  42 + private void initTenantConsumer(DefaultMQPushConsumer consumer) {
  43 + if (consumer == null) {
  44 + return;
  45 + }
  46 + DefaultMQPushConsumerImpl consumerImpl = consumer.getDefaultMQPushConsumerImpl();
  47 + if (consumerImpl == null) {
  48 + return;
  49 + }
  50 + consumerImpl.registerConsumeMessageHook(new TenantRocketMQConsumeMessageHook());
  51 + }
  52 +
  53 +}
0 54 \ No newline at end of file
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq;
  2 +
  3 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  4 +import org.apache.rocketmq.client.hook.SendMessageContext;
  5 +import org.apache.rocketmq.client.hook.SendMessageHook;
  6 +
  7 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  8 +
  9 +/**
  10 + * RocketMQ 消息队列的多租户 {@link SendMessageHook} 实现类
  11 + *
  12 + * Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public class TenantRocketMQSendMessageHook implements SendMessageHook {
  17 +
  18 + @Override
  19 + public String hookName() {
  20 + return getClass().getSimpleName();
  21 + }
  22 +
  23 + @Override
  24 + public void sendMessageBefore(SendMessageContext sendMessageContext) {
  25 + Long tenantId = TenantContextHolder.getTenantId();
  26 + if (tenantId == null) {
  27 + return;
  28 + }
  29 + sendMessageContext.getMessage().putUserProperty(HEADER_TENANT_ID, tenantId.toString());
  30 + }
  31 +
  32 + @Override
  33 + public void sendMessageAfter(SendMessageContext sendMessageContext) {
  34 + }
  35 +
  36 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java 0 → 100644
  1 +/*
  2 + * Copyright 2002-2021 the original author or authors.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * https://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.springframework.messaging.handler.invocation;
  18 +
  19 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  20 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
  21 +import org.springframework.core.DefaultParameterNameDiscoverer;
  22 +import org.springframework.core.MethodParameter;
  23 +import org.springframework.core.ParameterNameDiscoverer;
  24 +import org.springframework.core.ResolvableType;
  25 +import org.springframework.lang.Nullable;
  26 +import org.springframework.messaging.Message;
  27 +import org.springframework.messaging.handler.HandlerMethod;
  28 +import org.springframework.util.ObjectUtils;
  29 +
  30 +import java.lang.reflect.InvocationTargetException;
  31 +import java.lang.reflect.Method;
  32 +import java.lang.reflect.Type;
  33 +import java.util.Arrays;
  34 +
  35 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  36 +
  37 +/**
  38 + * Extension of {@link HandlerMethod} that invokes the underlying method with
  39 + * argument values resolved from the current HTTP request through a list of
  40 + * {@link HandlerMethodArgumentResolver}.
  41 + *
  42 + * 针对 rabbitmq-spring 和 kafka-spring,不存在合适的拓展点,可以实现 Consumer 消费前,读取 Header 中的 tenant-id 设置到 {@link TenantContextHolder} 中
  43 + * TODO 芋艿:持续跟进,看看有没新的拓展点
  44 + *
  45 + * @author Rossen Stoyanchev
  46 + * @author Juergen Hoeller
  47 + * @since 4.0
  48 + */
  49 +public class InvocableHandlerMethod extends HandlerMethod {
  50 +
  51 + private static final Object[] EMPTY_ARGS = new Object[0];
  52 +
  53 + private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
  54 +
  55 + private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
  56 +
  57 + /**
  58 + * Create an instance from a {@code HandlerMethod}.
  59 + */
  60 + public InvocableHandlerMethod(HandlerMethod handlerMethod) {
  61 + super(handlerMethod);
  62 + }
  63 +
  64 + /**
  65 + * Create an instance from a bean instance and a method.
  66 + */
  67 + public InvocableHandlerMethod(Object bean, Method method) {
  68 + super(bean, method);
  69 + }
  70 +
  71 + /**
  72 + * Construct a new handler method with the given bean instance, method name and parameters.
  73 + * @param bean the object bean
  74 + * @param methodName the method name
  75 + * @param parameterTypes the method parameter types
  76 + * @throws NoSuchMethodException when the method cannot be found
  77 + */
  78 + public InvocableHandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
  79 + throws NoSuchMethodException {
  80 +
  81 + super(bean, methodName, parameterTypes);
  82 + }
  83 +
  84 + /**
  85 + * Set {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} to use for resolving method argument values.
  86 + */
  87 + public void setMessageMethodArgumentResolvers(HandlerMethodArgumentResolverComposite argumentResolvers) {
  88 + this.resolvers = argumentResolvers;
  89 + }
  90 +
  91 + /**
  92 + * Set the ParameterNameDiscoverer for resolving parameter names when needed
  93 + * (e.g. default request attribute name).
  94 + * <p>Default is a {@link DefaultParameterNameDiscoverer}.
  95 + */
  96 + public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
  97 + this.parameterNameDiscoverer = parameterNameDiscoverer;
  98 + }
  99 +
  100 + /**
  101 + * Invoke the method after resolving its argument values in the context of the given message.
  102 + * <p>Argument values are commonly resolved through
  103 + * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
  104 + * The {@code providedArgs} parameter however may supply argument values to be used directly,
  105 + * i.e. without argument resolution.
  106 + * <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the
  107 + * resolved arguments.
  108 + * @param message the current message being processed
  109 + * @param providedArgs "given" arguments matched by type, not resolved
  110 + * @return the raw value returned by the invoked method
  111 + * @throws Exception raised if no suitable argument resolver can be found,
  112 + * or if the method raised an exception
  113 + * @see #getMethodArgumentValues
  114 + * @see #doInvoke
  115 + */
  116 + @Nullable
  117 + public Object invoke(Message<?> message, Object... providedArgs) throws Exception {
  118 + Object[] args = getMethodArgumentValues(message, providedArgs);
  119 + if (logger.isTraceEnabled()) {
  120 + logger.trace("Arguments: " + Arrays.toString(args));
  121 + }
  122 + // 注意:如下是本类的改动点!!!
  123 + // 情况一:无租户编号的情况
  124 + Long tenantId= parseTenantId(message);
  125 + if (tenantId == null) {
  126 + return doInvoke(args);
  127 + }
  128 + // 情况二:有租户的情况下
  129 + return TenantUtils.execute(tenantId, () -> doInvoke(args));
  130 + }
  131 +
  132 + private Long parseTenantId(Message<?> message) {
  133 + Object tenantId = message.getHeaders().get(HEADER_TENANT_ID);
  134 + if (tenantId == null) {
  135 + return null;
  136 + }
  137 + if (tenantId instanceof Long) {
  138 + return (Long) tenantId;
  139 + }
  140 + if (tenantId instanceof Number) {
  141 + return ((Number) tenantId).longValue();
  142 + }
  143 + if (tenantId instanceof String) {
  144 + return Long.parseLong((String) tenantId);
  145 + }
  146 + if (tenantId instanceof byte[]) {
  147 + return Long.parseLong(new String((byte[]) tenantId));
  148 + }
  149 + throw new IllegalArgumentException("未知的数据类型:" + tenantId);
  150 + }
  151 +
  152 + /**
  153 + * Get the method argument values for the current message, checking the provided
  154 + * argument values and falling back to the configured argument resolvers.
  155 + * <p>The resulting array will be passed into {@link #doInvoke}.
  156 + * @since 5.1.2
  157 + */
  158 + protected Object[] getMethodArgumentValues(Message<?> message, Object... providedArgs) throws Exception {
  159 + MethodParameter[] parameters = getMethodParameters();
  160 + if (ObjectUtils.isEmpty(parameters)) {
  161 + return EMPTY_ARGS;
  162 + }
  163 +
  164 + Object[] args = new Object[parameters.length];
  165 + for (int i = 0; i < parameters.length; i++) {
  166 + MethodParameter parameter = parameters[i];
  167 + parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
  168 + args[i] = findProvidedArgument(parameter, providedArgs);
  169 + if (args[i] != null) {
  170 + continue;
  171 + }
  172 + if (!this.resolvers.supportsParameter(parameter)) {
  173 + throw new MethodArgumentResolutionException(
  174 + message, parameter, formatArgumentError(parameter, "No suitable resolver"));
  175 + }
  176 + try {
  177 + args[i] = this.resolvers.resolveArgument(parameter, message);
  178 + }
  179 + catch (Exception ex) {
  180 + // Leave stack trace for later, exception may actually be resolved and handled...
  181 + if (logger.isDebugEnabled()) {
  182 + String exMsg = ex.getMessage();
  183 + if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
  184 + logger.debug(formatArgumentError(parameter, exMsg));
  185 + }
  186 + }
  187 + throw ex;
  188 + }
  189 + }
  190 + return args;
  191 + }
  192 +
  193 + /**
  194 + * Invoke the handler method with the given argument values.
  195 + */
  196 + @Nullable
  197 + protected Object doInvoke(Object... args) throws Exception {
  198 + try {
  199 + return getBridgedMethod().invoke(getBean(), args);
  200 + }
  201 + catch (IllegalArgumentException ex) {
  202 + assertTargetBean(getBridgedMethod(), getBean(), args);
  203 + String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
  204 + throw new IllegalStateException(formatInvokeError(text, args), ex);
  205 + }
  206 + catch (InvocationTargetException ex) {
  207 + // Unwrap for HandlerExceptionResolvers ...
  208 + Throwable targetException = ex.getTargetException();
  209 + if (targetException instanceof RuntimeException) {
  210 + throw (RuntimeException) targetException;
  211 + }
  212 + else if (targetException instanceof Error) {
  213 + throw (Error) targetException;
  214 + }
  215 + else if (targetException instanceof Exception) {
  216 + throw (Exception) targetException;
  217 + }
  218 + else {
  219 + throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
  220 + }
  221 + }
  222 + }
  223 +
  224 + MethodParameter getAsyncReturnValueType(@Nullable Object returnValue) {
  225 + return new AsyncResultMethodParameter(returnValue);
  226 + }
  227 +
  228 + private class AsyncResultMethodParameter extends HandlerMethodParameter {
  229 +
  230 + @Nullable
  231 + private final Object returnValue;
  232 +
  233 + private final ResolvableType returnType;
  234 +
  235 + public AsyncResultMethodParameter(@Nullable Object returnValue) {
  236 + super(-1);
  237 + this.returnValue = returnValue;
  238 + this.returnType = ResolvableType.forType(super.getGenericParameterType()).getGeneric();
  239 + }
  240 +
  241 + protected AsyncResultMethodParameter(AsyncResultMethodParameter original) {
  242 + super(original);
  243 + this.returnValue = original.returnValue;
  244 + this.returnType = original.returnType;
  245 + }
  246 +
  247 + @Override
  248 + public Class<?> getParameterType() {
  249 + if (this.returnValue != null) {
  250 + return this.returnValue.getClass();
  251 + }
  252 + if (!ResolvableType.NONE.equals(this.returnType)) {
  253 + return this.returnType.toClass();
  254 + }
  255 + return super.getParameterType();
  256 + }
  257 +
  258 + @Override
  259 + public Type getGenericParameterType() {
  260 + return this.returnType.getType();
  261 + }
  262 +
  263 + @Override
  264 + public AsyncResultMethodParameter clone() {
  265 + return new AsyncResultMethodParameter(this);
  266 + }
  267 + }
  268 +
  269 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories 0 → 100644
  1 +org.springframework.boot.env.EnvironmentPostProcessor=\
  2 + cn.iocoder.yudao.framework.tenant.core.mq.kafka.TenantKafkaEnvironmentPostProcessor
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/job/TestJob.java deleted
1   -package cn.iocoder.yudao.framework.tenant.core.job;
2   -
3   -import cn.hutool.core.collection.CollUtil;
4   -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
5   -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
6   -import org.springframework.stereotype.Component;
7   -
8   -import java.util.List;
9   -import java.util.concurrent.CopyOnWriteArrayList;
10   -
11   -@Component
12   -public class TestJob implements JobHandler {
13   -
14   - private final List<Long> tenantIds = new CopyOnWriteArrayList<>();
15   -
16   - @Override
17   - @TenantJob // 标记多租户
18   - public String execute(String param) throws Exception {
19   - tenantIds.add(TenantContextHolder.getTenantId());
20   - return "success";
21   - }
22   -
23   - public List<Long> getTenantIds() {
24   - CollUtil.sort(tenantIds, Long::compareTo);
25   - return tenantIds;
26   - }
27   -
28   -}
yudao-framework/yudao-spring-boot-starter-mq/pom.xml
... ... @@ -12,7 +12,7 @@
12 12 <packaging>jar</packaging>
13 13  
14 14 <name>${project.artifactId}</name>
15   - <description>消息队列,基于 Redis Pub/Sub 实现广播消费,基于 Stream 实现集群消费</description>
  15 + <description>消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种</description>
16 16 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
17 17  
18 18 <dependencies>
... ... @@ -21,6 +21,23 @@
21 21 <groupId>cn.iocoder.boot</groupId>
22 22 <artifactId>yudao-spring-boot-starter-redis</artifactId>
23 23 </dependency>
  24 +
  25 + <!-- 消息队列相关 -->
  26 + <dependency>
  27 + <groupId>org.springframework.kafka</groupId>
  28 + <artifactId>spring-kafka</artifactId>
  29 + <optional>true</optional>
  30 + </dependency>
  31 + <dependency>
  32 + <groupId>org.springframework.amqp</groupId>
  33 + <artifactId>spring-rabbit</artifactId>
  34 + <optional>true</optional>
  35 + </dependency>
  36 + <dependency>
  37 + <groupId>org.apache.rocketmq</groupId>
  38 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  39 + <optional>true</optional>
  40 + </dependency>
24 41 </dependencies>
25 42  
26 43 -</project>
  44 +</project>
27 45 \ No newline at end of file
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java
1 1 /**
2   - * 消息队列,基于 Redis 提供:
3   - * 1. 基于 Pub/Sub 实现广播消费
4   - * 2. 基于 Stream 实现集群消费
  2 + * 消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种
5 3 */
6 4 package cn.iocoder.yudao.framework.mq;
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mq.rabbitmq.config;
  2 +
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.amqp.utils.SerializationUtils;
  6 +import org.springframework.boot.autoconfigure.AutoConfiguration;
  7 +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  8 +
  9 +import java.lang.reflect.Field;
  10 +
  11 +/**
  12 + * RabbitMQ 消息队列配置类
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@AutoConfiguration
  17 +@Slf4j
  18 +@ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate")
  19 +public class YudaoRabbitMQAutoConfiguration {
  20 +
  21 + static {
  22 + // 强制设置 SerializationUtils 的 TRUST_ALL 为 true,避免 RabbitMQ Consumer 反序列化消息报错
  23 + // 为什么不通过设置 spring.amqp.deserialization.trust.all 呢?因为可能在 SerializationUtils static 初始化后
  24 + Field trustAllField = ReflectUtil.getField(SerializationUtils.class, "TRUST_ALL");
  25 + ReflectUtil.removeFinalModify(trustAllField);
  26 + ReflectUtil.setFieldValue(SerializationUtils.class, trustAllField, true);
  27 + }
  28 +
  29 +}
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java 0 → 100644
  1 +/**
  2 + * 占位符,无特殊逻辑
  3 + */
  4 +package cn.iocoder.yudao.framework.mq.rabbitmq.core;
0 5 \ No newline at end of file
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列,基于 RabbitMQ 提供
  3 + */
  4 +package cn.iocoder.yudao.framework.mq.rabbitmq;
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQAutoConfiguration.java
1   -package cn.iocoder.yudao.framework.mq.config;
  1 +package cn.iocoder.yudao.framework.mq.redis.config;
2 2  
3 3 import cn.hutool.core.map.MapUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.hutool.system.SystemUtil;
6 6 import cn.iocoder.yudao.framework.common.enums.DocumentEnum;
7   -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
8   -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;
9   -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
10   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
11   -import cn.iocoder.yudao.framework.mq.job.RedisPendingMessageResendJob;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  8 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  9 +import cn.iocoder.yudao.framework.mq.redis.core.job.RedisPendingMessageResendJob;
  10 +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessageListener;
  11 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
12 12 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
13 13 import lombok.extern.slf4j.Slf4j;
14 14 import org.redisson.api.RedissonClient;
15 15 import org.springframework.beans.factory.annotation.Value;
16 16 import org.springframework.boot.autoconfigure.AutoConfiguration;
17 17 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
18   -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
19 18 import org.springframework.context.annotation.Bean;
20 19 import org.springframework.data.redis.connection.RedisServerCommands;
21 20 import org.springframework.data.redis.connection.stream.Consumer;
... ... @@ -27,7 +26,6 @@ import org.springframework.data.redis.core.RedisTemplate;
27 26 import org.springframework.data.redis.core.StringRedisTemplate;
28 27 import org.springframework.data.redis.listener.ChannelTopic;
29 28 import org.springframework.data.redis.listener.RedisMessageListenerContainer;
30   -import org.springframework.data.redis.stream.DefaultStreamMessageListenerContainerX;
31 29 import org.springframework.data.redis.stream.StreamMessageListenerContainer;
32 30 import org.springframework.scheduling.annotation.EnableScheduling;
33 31  
... ... @@ -42,7 +40,7 @@ import java.util.Properties;
42 40 @Slf4j
43 41 @EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息
44 42 @AutoConfiguration(after = YudaoRedisAutoConfiguration.class)
45   -public class YudaoMQAutoConfiguration {
  43 +public class YudaoRedisMQAutoConfiguration {
46 44  
47 45 @Bean
48 46 public RedisMQTemplate redisMQTemplate(StringRedisTemplate redisTemplate,
... ... @@ -59,10 +57,9 @@ public class YudaoMQAutoConfiguration {
59 57 * 创建 Redis Pub/Sub 广播消费的容器
60 58 */
61 59 @Bean(initMethod = "start", destroyMethod = "stop")
62   - @ConditionalOnBean(AbstractChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听
63   - @ConditionalOnProperty(prefix = "yudao.mq.redis.pubsub", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.pubsub.enable=false 禁用多租户
  60 + @ConditionalOnBean(AbstractRedisChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听
64 61 public RedisMessageListenerContainer redisMessageListenerContainer(
65   - RedisMQTemplate redisMQTemplate, List<AbstractChannelMessageListener<?>> listeners) {
  62 + RedisMQTemplate redisMQTemplate, List<AbstractRedisChannelMessageListener<?>> listeners) {
66 63 // 创建 RedisMessageListenerContainer 对象
67 64 RedisMessageListenerContainer container = new RedisMessageListenerContainer();
68 65 // 设置 RedisConnection 工厂。
... ... @@ -81,9 +78,8 @@ public class YudaoMQAutoConfiguration {
81 78 * 创建 Redis Stream 重新消费的任务
82 79 */
83 80 @Bean
84   - @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
85   - @ConditionalOnProperty(prefix = "yudao.mq.redis.stream", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.stream.enable=false 禁用多租户
86   - public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractStreamMessageListener<?>> listeners,
  81 + @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
  82 + public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractRedisStreamMessageListener<?>> listeners,
87 83 RedisMQTemplate redisTemplate,
88 84 @Value("${spring.application.name}") String groupName,
89 85 RedissonClient redissonClient) {
... ... @@ -92,14 +88,13 @@ public class YudaoMQAutoConfiguration {
92 88  
93 89 /**
94 90 * 创建 Redis Stream 集群消费的容器
95   - * <p>
96   - * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html
  91 + *
  92 + * 基础知识:<a href="https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html">Redis Stream 的 xreadgroup 命令</a>
97 93 */
98 94 @Bean(initMethod = "start", destroyMethod = "stop")
99   - @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
100   - @ConditionalOnProperty(prefix = "yudao.mq.redis.stream", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.stream.enable=false 禁用多租户
  95 + @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
101 96 public StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer(
102   - RedisMQTemplate redisMQTemplate, List<AbstractStreamMessageListener<?>> listeners) {
  97 + RedisMQTemplate redisMQTemplate, List<AbstractRedisStreamMessageListener<?>> listeners) {
103 98 RedisTemplate<String, ?> redisTemplate = redisMQTemplate.getRedisTemplate();
104 99 checkRedisVersion(redisTemplate);
105 100 // 第一步,创建 StreamMessageListenerContainer 容器
... ... @@ -111,8 +106,7 @@ public class YudaoMQAutoConfiguration {
111 106 .build();
112 107 // 创建 container 对象
113 108 StreamMessageListenerContainer<String, ObjectRecord<String, String>> container =
114   -// StreamMessageListenerContainer.create(redisTemplate.getRequiredConnectionFactory(), containerOptions);
115   - DefaultStreamMessageListenerContainerX.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions);
  109 + StreamMessageListenerContainer.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions);
116 110  
117 111 // 第二步,注册监听器,消费对应的 Stream 主题
118 112 String consumerName = buildConsumerName();
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/RedisMQTemplate.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java
1   -package cn.iocoder.yudao.framework.mq.core;
  1 +package cn.iocoder.yudao.framework.mq.redis.core;
2 2  
3 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4   -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;
5   -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
6   -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
7   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
  4 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessage;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessage;
8 8 import lombok.AllArgsConstructor;
9 9 import lombok.Getter;
10 10 import org.springframework.data.redis.connection.stream.RecordId;
... ... @@ -35,7 +35,7 @@ public class RedisMQTemplate {
35 35 *
36 36 * @param message 消息
37 37 */
38   - public <T extends AbstractChannelMessage> void send(T message) {
  38 + public <T extends AbstractRedisChannelMessage> void send(T message) {
39 39 try {
40 40 sendMessageBefore(message);
41 41 // 发送消息
... ... @@ -51,7 +51,7 @@ public class RedisMQTemplate {
51 51 * @param message 消息
52 52 * @return 消息记录的编号对象
53 53 */
54   - public <T extends AbstractStreamMessage> RecordId send(T message) {
  54 + public <T extends AbstractRedisStreamMessage> RecordId send(T message) {
55 55 try {
56 56 sendMessageBefore(message);
57 57 // 发送消息
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/interceptor/RedisMessageInterceptor.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java
1   -package cn.iocoder.yudao.framework.mq.core.interceptor;
  1 +package cn.iocoder.yudao.framework.mq.redis.core.interceptor;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
  3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 4  
5 5 /**
6 6 * {@link AbstractRedisMessage} 消息拦截器
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/job/RedisPendingMessageResendJob.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
1   -package cn.iocoder.yudao.framework.mq.job;
  1 +package cn.iocoder.yudao.framework.mq.redis.core.job;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
5   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
  4 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
6 6 import lombok.AllArgsConstructor;
7 7 import lombok.extern.slf4j.Slf4j;
8 8 import org.redisson.api.RLock;
... ... @@ -33,7 +33,7 @@ public class RedisPendingMessageResendJob {
33 33 */
34 34 private static final int EXPIRE_TIME = 5 * 60;
35 35  
36   - private final List<AbstractStreamMessageListener<?>> listeners;
  36 + private final List<AbstractRedisStreamMessageListener<?>> listeners;
37 37 private final RedisMQTemplate redisTemplate;
38 38 private final String groupName;
39 39 private final RedissonClient redissonClient;
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/message/AbstractRedisMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java
1   -package cn.iocoder.yudao.framework.mq.core.message;
  1 +package cn.iocoder.yudao.framework.mq.redis.core.message;
2 2  
3 3 import lombok.Data;
4 4  
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java
1   -package cn.iocoder.yudao.framework.mq.core.pubsub;
  1 +package cn.iocoder.yudao.framework.mq.redis.core.pubsub;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
  3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 4 import com.fasterxml.jackson.annotation.JsonIgnore;
5 5  
6 6 /**
... ... @@ -8,14 +8,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
8 8 *
9 9 * @author 芋道源码
10 10 */
11   -public abstract class AbstractChannelMessage extends AbstractRedisMessage {
  11 +public abstract class AbstractRedisChannelMessage extends AbstractRedisMessage {
12 12  
13 13 /**
14   - * 获得 Redis Channel
  14 + * 获得 Redis Channel,默认使用类名
15 15 *
16 16 * @return Channel
17 17 */
18 18 @JsonIgnore // 避免序列化。原因是,Redis 发布 Channel 消息的时候,已经会指定。
19   - public abstract String getChannel();
  19 + public String getChannel() {
  20 + return getClass().getSimpleName();
  21 + }
20 22  
21 23 }
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessageListener.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java
1   -package cn.iocoder.yudao.framework.mq.core.pubsub;
  1 +package cn.iocoder.yudao.framework.mq.redis.core.pubsub;
2 2  
3 3 import cn.hutool.core.util.TypeUtil;
4 4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5   -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
6   -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;
7   -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
8 8 import lombok.Setter;
9 9 import lombok.SneakyThrows;
10 10 import org.springframework.data.redis.connection.Message;
... ... @@ -20,7 +20,7 @@ import java.util.List;
20 20 *
21 21 * @author 芋道源码
22 22 */
23   -public abstract class AbstractChannelMessageListener<T extends AbstractChannelMessage> implements MessageListener {
  23 +public abstract class AbstractRedisChannelMessageListener<T extends AbstractRedisChannelMessage> implements MessageListener {
24 24  
25 25 /**
26 26 * 消息类型
... ... @@ -37,7 +37,7 @@ public abstract class AbstractChannelMessageListener&lt;T extends AbstractChannelMe
37 37 private RedisMQTemplate redisMQTemplate;
38 38  
39 39 @SneakyThrows
40   - protected AbstractChannelMessageListener() {
  40 + protected AbstractRedisChannelMessageListener() {
41 41 this.messageType = getMessageClass();
42 42 this.channel = messageType.getDeclaredConstructor().newInstance().getChannel();
43 43 }
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessage.java
1   -package cn.iocoder.yudao.framework.mq.core.stream;
  1 +package cn.iocoder.yudao.framework.mq.redis.core.stream;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
  3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 4 import com.fasterxml.jackson.annotation.JsonIgnore;
5 5  
6 6 /**
... ... @@ -8,14 +8,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
8 8 *
9 9 * @author 芋道源码
10 10 */
11   -public abstract class AbstractStreamMessage extends AbstractRedisMessage {
  11 +public abstract class AbstractRedisStreamMessage extends AbstractRedisMessage {
12 12  
13 13 /**
14   - * 获得 Redis Stream Key
  14 + * 获得 Redis Stream Key,默认使用类名
15 15 *
16 16 * @return Channel
17 17 */
18 18 @JsonIgnore // 避免序列化
19   - public abstract String getStreamKey();
  19 + public String getStreamKey() {
  20 + return getClass().getSimpleName();
  21 + }
20 22  
21 23 }
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessageListener.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessageListener.java
1   -package cn.iocoder.yudao.framework.mq.core.stream;
  1 +package cn.iocoder.yudao.framework.mq.redis.core.stream;
2 2  
3 3 import cn.hutool.core.util.TypeUtil;
4 4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5   -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
6   -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;
7   -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
8 8 import lombok.Getter;
9 9 import lombok.Setter;
10 10 import lombok.SneakyThrows;
... ... @@ -22,7 +22,7 @@ import java.util.List;
22 22 *
23 23 * @author 芋道源码
24 24 */
25   -public abstract class AbstractStreamMessageListener<T extends AbstractStreamMessage>
  25 +public abstract class AbstractRedisStreamMessageListener<T extends AbstractRedisStreamMessage>
26 26 implements StreamListener<String, ObjectRecord<String, String>> {
27 27  
28 28 /**
... ... @@ -48,7 +48,7 @@ public abstract class AbstractStreamMessageListener&lt;T extends AbstractStreamMess
48 48 private RedisMQTemplate redisMQTemplate;
49 49  
50 50 @SneakyThrows
51   - protected AbstractStreamMessageListener() {
  51 + protected AbstractRedisStreamMessageListener() {
52 52 this.messageType = getMessageClass();
53 53 this.streamKey = messageType.getDeclaredConstructor().newInstance().getStreamKey();
54 54 }
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列,基于 Redis 提供:
  3 + * 1. 基于 Pub/Sub 实现广播消费
  4 + * 2. 基于 Stream 实现集群消费
  5 + */
  6 +package cn.iocoder.yudao.framework.mq.redis;
... ...
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/org/springframework/data/redis/stream/DefaultStreamMessageListenerContainerX.java deleted
1   -package org.springframework.data.redis.stream;
2   -
3   -import cn.hutool.core.util.ReflectUtil;
4   -import org.springframework.data.redis.connection.RedisConnectionFactory;
5   -import org.springframework.data.redis.connection.stream.ByteRecord;
6   -import org.springframework.data.redis.connection.stream.ReadOffset;
7   -import org.springframework.data.redis.connection.stream.Record;
8   -import org.springframework.util.Assert;
9   -
10   -import java.util.Collections;
11   -import java.util.List;
12   -import java.util.function.Function;
13   -
14   -/**
15   - * 拓展 DefaultStreamMessageListenerContainer 实现,解决 Spring Data Redis + Redisson 结合使用时,Redisson 在 Stream 获得不到数据时,返回 null 而不是空 List,导致 NPE 异常。
16   - * 对应 issue:https://github.com/spring-projects/spring-data-redis/issues/2147 和 https://github.com/redisson/redisson/issues/4006
17   - * 目前看下来 Spring Data Redis 不肯加 null 判断,Redisson 暂时也没改返回 null 到空 List 的打算,所以暂时只能自己改,哽咽!
18   - *
19   - * @author 芋道源码
20   - */
21   -public class DefaultStreamMessageListenerContainerX<K, V extends Record<K, ?>> extends DefaultStreamMessageListenerContainer<K, V> {
22   -
23   - /**
24   - * 参考 {@link StreamMessageListenerContainer#create(RedisConnectionFactory, StreamMessageListenerContainerOptions)} 的实现
25   - */
26   - public static <K, V extends Record<K, ?>> StreamMessageListenerContainer<K, V> create(RedisConnectionFactory connectionFactory, StreamMessageListenerContainer.StreamMessageListenerContainerOptions<K, V> options) {
27   - Assert.notNull(connectionFactory, "RedisConnectionFactory must not be null!");
28   - Assert.notNull(options, "StreamMessageListenerContainerOptions must not be null!");
29   - return new DefaultStreamMessageListenerContainerX<>(connectionFactory, options);
30   - }
31   -
32   - public DefaultStreamMessageListenerContainerX(RedisConnectionFactory connectionFactory, StreamMessageListenerContainerOptions<K, V> containerOptions) {
33   - super(connectionFactory, containerOptions);
34   - }
35   -
36   - /**
37   - * 参考 {@link DefaultStreamMessageListenerContainer#register(StreamReadRequest, StreamListener)} 的实现
38   - */
39   - @Override
40   - public Subscription register(StreamReadRequest<K> streamRequest, StreamListener<K, V> listener) {
41   - return this.doRegisterX(getReadTaskX(streamRequest, listener));
42   - }
43   -
44   - @SuppressWarnings("unchecked")
45   - private StreamPollTask<K, V> getReadTaskX(StreamReadRequest<K> streamRequest, StreamListener<K, V> listener) {
46   - StreamPollTask<K, V> task = ReflectUtil.invoke(this, "getReadTask", streamRequest, listener);
47   - // 修改 readFunction 方法
48   - Function<ReadOffset, List<ByteRecord>> readFunction = (Function<ReadOffset, List<ByteRecord>>) ReflectUtil.getFieldValue(task, "readFunction");
49   - ReflectUtil.setFieldValue(task, "readFunction", (Function<ReadOffset, List<ByteRecord>>) readOffset -> {
50   - List<ByteRecord> records = readFunction.apply(readOffset);
51   - //【重点】保证 records 不是空,避免 NPE 的问题!!!
52   - return records != null ? records : Collections.emptyList();
53   - });
54   - return task;
55   - }
56   -
57   - private Subscription doRegisterX(Task task) {
58   - return ReflectUtil.invoke(this, "doRegister", task);
59   - }
60   -
61   -}
62   -
yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
1   -cn.iocoder.yudao.framework.mq.config.YudaoMQAutoConfiguration
2 1 \ No newline at end of file
  2 +cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQAutoConfiguration
  3 +cn.iocoder.yudao.framework.mq.rabbitmq.config.YudaoRabbitMQAutoConfiguration
3 4 \ No newline at end of file
... ...
yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md 0 → 100644
  1 +<http://www.iocoder.cn/Spring-Boot/RocketMQ/?yudao>
... ...
yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md 0 → 100644
  1 +<http://www.iocoder.cn/Spring-Boot/Kafka/?yudao>
... ...
yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md 0 → 100644
  1 +<http://www.iocoder.cn/Spring-Boot/RabbitMQ/?yudao>
... ...
yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md 0 → 100644
  1 +<http://www.iocoder.cn/Spring-Boot/RocketMQ/?yudao>
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLog.java
... ... @@ -5,7 +5,6 @@ import lombok.Data;
5 5 import javax.validation.constraints.NotNull;
6 6 import java.time.LocalDateTime;
7 7  
8   -// TODO @小吉祥:搞个 job,清理 14 天外的访问日志;
9 8 /**
10 9 * API 访问日志
11 10 *
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLog.java
... ... @@ -5,7 +5,6 @@ import lombok.Data;
5 5 import javax.validation.constraints.NotNull;
6 6 import java.time.LocalDateTime;
7 7  
8   -// TODO @小吉祥:搞个 job,清理 14 天外的异常日志;
9 8 /**
10 9 * API 错误日志
11 10 *
... ...
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java
... ... @@ -20,16 +20,16 @@ public enum BpmCommentTypeEnum {
20 20 ;
21 21  
22 22 /**
23   - * 结果
  23 + * 操作类型
24 24 */
25 25 private final Integer type;
26 26 /**
27   - * 描述
  27 + * 操作名字
28 28 */
29   - private final String desc;
  29 + private final String name;
30 30 /**
31   - * 模板信息
  31 + * 操作描述
32 32 */
33   - private final String templateComment;
  33 + private final String comment;
34 34  
35 35 }
... ...
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java
... ... @@ -30,13 +30,13 @@ public enum BpmProcessInstanceResultEnum {
30 30 * 相当于是 通过 APPROVE 的特殊状态
31 31 * 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成”
32 32 */
33   - ADD_SIGN_AFTER(7, "待后加签任务完成"),
  33 + SIGN_AFTER(7, "待后加签任务完成"),
34 34 /**
35 35 * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成”
36 36 * 相当于是 处理中 PROCESS 的特殊状态
37 37 * 例如:A 审批, A 前加签了 B,B 还未审核
38 38 */
39   - ADD_SIGN_BEFORE(8, "待前加签任务完成"),
  39 + SIGN_BEFORE(8, "待前加签任务完成"),
40 40 /**
41 41 * 【加签】后加签任务被创建时的初始状态
42 42 * 相当于是 处理中 PROCESS 的特殊状态
... ... @@ -71,7 +71,7 @@ public enum BpmProcessInstanceResultEnum {
71 71 public static boolean isEndResult(Integer result) {
72 72 return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(),
73 73 CANCEL.getResult(), BACK.getResult(),
74   - ADD_SIGN_AFTER.getResult());
  74 + SIGN_AFTER.getResult());
75 75 }
76 76  
77 77 }
... ...
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.enums.task;
3 3 import lombok.AllArgsConstructor;
4 4 import lombok.Getter;
5 5  
6   -
7 6 /**
8 7 * 流程任务 -- 加签类型枚举类型
9 8 */
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
... ... @@ -74,7 +74,7 @@ public class BpmTaskController {
74 74 return success(true);
75 75 }
76 76  
77   - @GetMapping("/get-return-list")
  77 + @GetMapping("/return-list")
78 78 @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮")
79 79 @Parameter(name = "taskId", description = "当前任务ID", required = true)
80 80 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
... ... @@ -98,27 +98,28 @@ public class BpmTaskController {
98 98 return success(true);
99 99 }
100 100  
101   - @PutMapping("/add-sign")
  101 + @PutMapping("/create-sign")
102 102 @Operation(summary = "加签", description = "before 前加签,after 后加签")
103 103 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
104   - public CommonResult<Boolean> addSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) {
105   - taskService.addSignTask(getLoginUserId(), reqVO);
  104 + public CommonResult<Boolean> createSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) {
  105 + taskService.createSignTask(getLoginUserId(), reqVO);
106 106 return success(true);
107 107 }
108 108  
109   - @PutMapping("/sub-sign")
  109 + @DeleteMapping("/delete-sign")
110 110 @Operation(summary = "减签")
111 111 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
112   - public CommonResult<Boolean> subSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) {
113   - taskService.subSignTask(getLoginUserId(), reqVO);
  112 + public CommonResult<Boolean> deleteSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) {
  113 + taskService.deleteSignTask(getLoginUserId(), reqVO);
114 114 return success(true);
115 115 }
116 116  
117   - @GetMapping("/get-children-task-list")
  117 + @GetMapping("children-list")
118 118 @Operation(summary = "获取能被减签的任务")
  119 + @Parameter(name = "parentId", description = "父级任务 ID", required = true)
119 120 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
120   - public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("taskId") String taskId) {
121   - return success(taskService.getChildrenTaskList(taskId));
  121 + public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("parentId") String parentId) {
  122 + return success(taskService.getChildrenTaskList(parentId));
122 123 }
123 124  
124 125 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java
... ... @@ -6,6 +6,7 @@ import lombok.Data;
6 6 import javax.validation.constraints.NotEmpty;
7 7 import java.util.Set;
8 8  
  9 +// TODO @海洋:类名,应该是 create 哈
9 10 @Schema(description = "管理后台 - 加签流程任务的 Request VO")
10 11 @Data
11 12 public class BpmTaskAddSignReqVO {
... ... @@ -26,4 +27,4 @@ public class BpmTaskAddSignReqVO {
26 27 @NotEmpty(message = "加签原因不能为空")
27 28 private String reason;
28 29  
29   -}
30 30 \ No newline at end of file
  31 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java
... ... @@ -5,6 +5,7 @@ import lombok.Data;
5 5  
6 6 import javax.validation.constraints.NotEmpty;
7 7  
  8 +// TODO @海洋:类名,应该是 delete 哈
8 9 @Schema(description = "管理后台 - 减签流程任务的 Request VO")
9 10 @Data
10 11 public class BpmTaskSubSignReqVO {
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
1 1 package cn.iocoder.yudao.module.bpm.convert.task;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.hutool.core.date.LocalDateTimeUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
5 5 import cn.hutool.core.util.StrUtil;
6 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  7 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 8 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
8 9 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
9 10 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
... ... @@ -25,6 +26,9 @@ import java.util.Date;
25 26 import java.util.List;
26 27 import java.util.Map;
27 28  
  29 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
  31 +
28 32 /**
29 33 * Bpm 任务 Convert
30 34 *
... ... @@ -167,32 +171,31 @@ public interface BpmTaskConvert {
167 171 default List<BpmTaskSubSignRespVO> convertList(List<BpmTaskExtDO> bpmTaskExtDOList,
168 172 Map<Long, AdminUserRespDTO> userMap,
169 173 Map<String, Task> idTaskMap){
170   - return CollectionUtils.convertList(bpmTaskExtDOList, task->{
171   - BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO();
172   - bpmTaskSubSignRespVO.setName(task.getName());
173   - bpmTaskSubSignRespVO.setId(task.getTaskId());
174   - Task sourceTask = idTaskMap.get(task.getTaskId());
  174 + return CollectionUtils.convertList(bpmTaskExtDOList, task -> {
  175 + BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO()
  176 + .setId(task.getTaskId()).setName(task.getName());
175 177 // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner
176   - String assignee = StrUtil.isNotEmpty(sourceTask.getAssignee()) ? sourceTask.getAssignee() : sourceTask.getOwner();
177   - AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(assignee));
178   - if (assignUser != null) {
179   - bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser));
180   - }
  178 + Task sourceTask = idTaskMap.get(task.getTaskId());
  179 + String assignee = ObjectUtil.defaultIfBlank(sourceTask.getOwner(),sourceTask.getAssignee());
  180 + MapUtils.findAndThen(userMap,NumberUtils.parseLong(assignee),
  181 + assignUser-> bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser)));
181 182 return bpmTaskSubSignRespVO;
182 183 });
183 184 }
184 185  
185 186 /**
186 187 * 转换任务为父子级
  188 + *
187 189 * @param sourceList 原始数据
188 190 * @return 转换后的父子级数组
189 191 */
190   - default List<BpmTaskRespVO> convertChildrenList(List<BpmTaskRespVO> sourceList){
191   - List<BpmTaskRespVO> childrenTaskList = CollectionUtils.filterList(sourceList, r -> StrUtil.isNotEmpty(r.getParentTaskId()));
192   - Map<String, List<BpmTaskRespVO>> parentChildrenTaskListMap = CollectionUtils.convertMultiMap(childrenTaskList, BpmTaskRespVO::getParentTaskId);
  192 + default List<BpmTaskRespVO> convertChildrenList(List<BpmTaskRespVO> sourceList) {
  193 + List<BpmTaskRespVO> childrenTaskList = filterList(sourceList, r -> StrUtil.isNotEmpty(r.getParentTaskId()));
  194 + Map<String, List<BpmTaskRespVO>> parentChildrenTaskListMap = convertMultiMap(childrenTaskList, BpmTaskRespVO::getParentTaskId);
193 195 for (BpmTaskRespVO bpmTaskRespVO : sourceList) {
194 196 bpmTaskRespVO.setChildren(parentChildrenTaskListMap.get(bpmTaskRespVO.getId()));
195 197 }
196   - return CollectionUtils.filterList(sourceList, r -> StrUtil.isEmpty(r.getParentTaskId()));
  198 + return filterList(sourceList, r -> StrUtil.isEmpty(r.getParentTaskId()));
197 199 }
  200 +
198 201 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java
... ... @@ -21,13 +21,13 @@ public interface BpmTaskExtMapper extends BaseMapperX&lt;BpmTaskExtDO&gt; {
21 21 return selectList(BpmTaskExtDO::getTaskId, taskIds);
22 22 }
23 23  
  24 + // TODO @海:BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST) 应该作为条件,mapper 不要有业务
24 25 default List<BpmTaskExtDO> selectProcessListByTaskIds(Collection<String> taskIds) {
25 26 return selectList(new LambdaQueryWrapperX<BpmTaskExtDO>()
26 27 .in(BpmTaskExtDO::getTaskId, taskIds)
27 28 .in(BpmTaskExtDO::getResult, BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST));
28 29 }
29 30  
30   -
31 31 default BpmTaskExtDO selectByTaskId(String taskId) {
32 32 return selectOne(BpmTaskExtDO::getTaskId, taskId);
33 33 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmSecurityConfiguration.java deleted
1   -package cn.iocoder.yudao.module.bpm.framework.bpm.config;
2   -
3   -import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
4   -import org.springframework.context.annotation.Bean;
5   -import org.springframework.context.annotation.Configuration;
6   -import org.springframework.security.config.annotation.web.builders.HttpSecurity;
7   -import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
8   -
9   -/**
10   - * @author kemengkai
11   - * @create 2022-05-07 08:15
12   - */
13   -@Configuration("bpmSecurityConfiguration")
14   -public class BpmSecurityConfiguration {
15   -
16   - @Bean("bpmAuthorizeRequestsCustomizer")
17   - public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
18   - return new AuthorizeRequestsCustomizer() {
19   -
20   - @Override
21   - public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
22   - // 任务回退接口
23   - registry.antMatchers(buildAdminApi("/bpm/task/back")).permitAll();
24   - }
25   -
26   - };
27   - }
28   -}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java
... ... @@ -12,6 +12,7 @@ import javax.validation.Valid;
12 12 * @author yunlongn
13 13 */
14 14 public interface BpmModelService {
  15 +
15 16 /**
16 17 * 获得流程模型分页
17 18 *
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
... ... @@ -288,5 +288,4 @@ public class BpmModelServiceImpl implements BpmModelService {
288 288 processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
289 289 }
290 290  
291   -
292 291 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
... ... @@ -163,7 +163,7 @@ public interface BpmTaskService {
163 163 * @param userId 被加签的用户和任务 ID,加签类型
164 164 * @param reqVO 当前用户 ID
165 165 */
166   - void addSignTask(Long userId, BpmTaskAddSignReqVO reqVO);
  166 + void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO);
167 167  
168 168 /**
169 169 * 任务减签名
... ... @@ -171,14 +171,14 @@ public interface BpmTaskService {
171 171 * @param userId 当前用户ID
172 172 * @param reqVO 被减签的任务 ID,理由
173 173 */
174   - void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO);
  174 + void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO);
175 175  
176 176 /**
177 177 * 获取指定任务的子任务和审批人信息
178 178 *
179   - * @param taskId 指定任务ID
  179 + * @param parentId 指定任务ID
180 180 * @return 子任务列表
181 181 */
182   - List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId);
  182 + List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId);
183 183  
184 184 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -53,7 +53,6 @@ import javax.annotation.Resource;
53 53 import javax.validation.Valid;
54 54 import java.time.LocalDateTime;
55 55 import java.util.*;
56   -import java.util.stream.Collectors;
57 56 import java.util.stream.Stream;
58 57  
59 58 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -240,10 +239,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
240 239 handleParentTask(task);
241 240 }
242 241  
  242 +
243 243 /**
244 244 * 审批通过存在“后加签”的任务。
245 245 * <p>
246   - * 注意:该任务不能马上完成,需要一个中间状态(ADD_SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理
  246 + * 注意:该任务不能马上完成,需要一个中间状态(SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理
247 247 *
248 248 * @param task 当前任务
249 249 * @param reqVO 前端请求参数
... ... @@ -251,7 +251,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
251 251 private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) {
252 252 // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态
253 253 taskExtMapper.updateByTaskId(
254   - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.ADD_SIGN_AFTER.getResult())
  254 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult())
255 255 .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now()));
256 256  
257 257 // 2. 激活子任务
... ... @@ -265,7 +265,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
265 265 }
266 266  
267 267 /**
268   - * 处理当前任务的父任务
  268 + * 处理当前任务的父任务,主要处理“加签”的情况
269 269 *
270 270 * @param task 当前任务
271 271 */
... ... @@ -274,76 +274,79 @@ public class BpmTaskServiceImpl implements BpmTaskService {
274 274 if (StrUtil.isBlank(parentTaskId)) {
275 275 return;
276 276 }
277   - if (StrUtil.isNotBlank(parentTaskId)) {
278   - // 1. 判断当前任务的父任务是否还有子任务
279   - Long childrenTaskCount = getChildrenTaskCount(parentTaskId);
280   - if (childrenTaskCount > 0) {
281   - return;
282   - }
283   - // 2. 获取父任务
284   - Task parentTask = validateTaskExist(parentTaskId);
285   -
286   - // 3. 情况一:处理向前加签
287   - String scopeType = parentTask.getScopeType();
288   - if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {
289   - // 3.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee
290   - taskService.resolveTask(parentTaskId);
291   - // 3.2 更新任务拓展表为处理中
292   - taskExtMapper.updateByTaskId(
293   - new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
294   - } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {
295   - // 3. 情况二:处理向后加签
296   - handleAfterSign(parentTask);
297   - }
  277 + // 1. 判断当前任务的父任务是否还有子任务
  278 + Long childrenTaskCount = getChildrenTaskCount(parentTaskId);
  279 + if (childrenTaskCount > 0) {
  280 + return;
  281 + }
  282 + // 2. 获取父任务
  283 + Task parentTask = validateTaskExist(parentTaskId);
298 284  
299   - // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签
300   - // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently
301   - // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的
302   - parentTask = getTask(parentTaskId);
303   - if (parentTask == null) {
304   - // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据
305   - return;
306   - }
307   - clearTaskScopeTypeAndSave(parentTask);
  285 + // 3. 处理加签情况
  286 + String scopeType = parentTask.getScopeType();
  287 + if(!validateSignType(scopeType)){
  288 + return;
308 289 }
  290 + // 3.1 情况一:处理向前加签
  291 + if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {
  292 + // 3.1.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee,这样它就可以被审批
  293 + taskService.resolveTask(parentTaskId);
  294 + // 3.1.2 更新任务拓展表为处理中
  295 + taskExtMapper.updateByTaskId(
  296 + new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
  297 + } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {
  298 + // 3.2 情况二:处理向后加签
  299 + handleParentTaskForAfterSign(parentTask);
  300 + }
  301 +
  302 + // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签
  303 + // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently
  304 + // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的
  305 + parentTask = getTask(parentTaskId);
  306 + if (parentTask == null) {
  307 + // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据
  308 + return;
  309 + }
  310 + clearTaskScopeTypeAndSave(parentTask);
309 311 }
310 312  
  313 +
311 314 /**
312 315 * 处理后加签任务
313 316 *
314 317 * @param parentTask 当前审批任务的父任务
315 318 */
316   - private void handleAfterSign(Task parentTask) {
  319 + // TODO @海:这个逻辑,怎么感觉可以是 parentTask 的 parent,再去调用 handleParentTask 方法;可以微信聊下;
  320 + private void handleParentTaskForAfterSign(Task parentTask) {
317 321 String parentTaskId = parentTask.getId();
318   - //1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己
  322 + // 1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己
319 323 BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
320   - BpmTaskExtDO currentTaskUpdateEntity = new BpmTaskExtDO().setTaskId(parentTask.getId())
  324 + BpmTaskExtDO currentTaskExtUpdateObj = new BpmTaskExtDO().setTaskId(parentTask.getId())
321 325 .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
322 326 if (currentTaskExt.getEndTime() == null) {
323 327 // 1.1 有这个判断是因为,以前没设置过结束时间,才去设置
324   - currentTaskUpdateEntity.setEndTime(LocalDateTime.now());
  328 + currentTaskExtUpdateObj.setEndTime(LocalDateTime.now());
325 329 }
326   - // 1.2 完成自己
327   - taskExtMapper.updateByTaskId(currentTaskUpdateEntity);
  330 + taskExtMapper.updateByTaskId(currentTaskExtUpdateObj);
  331 + // 1.2 完成自己(因为它已经没有子任务,所以也可以完成)
328 332 taskService.complete(parentTaskId);
329 333  
330 334 // 2. 如果有父级,递归查询上级任务是否都已经完成
331 335 if (StrUtil.isEmpty(parentTask.getParentTaskId())) {
332 336 return;
333 337 }
334   - // TODO @海:这块待讨论,脑子略乱;感觉 handleAfterSign 的后半段,和 handleParentTask 有点重叠???
335 338 // 2.1 判断整条链路的任务是否完成
336 339 // 例如从 A 任务加签了一个 B 任务,B 任务又加签了一个 C 任务,C 任务加签了 D 任务
337 340 // 此时,D 任务完成,要一直往上找到祖先任务 A调用 complete 方法完成 A 任务
338 341 boolean allChildrenTaskFinish = true;
339 342 while (StrUtil.isNotBlank(parentTask.getParentTaskId())) {
340 343 parentTask = validateTaskExist(parentTask.getParentTaskId());
341   - BpmTaskExtDO bpmTaskExtDO = taskExtMapper.selectByTaskId(parentTask.getId());
342   - if (bpmTaskExtDO == null) {
  344 + BpmTaskExtDO parentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
  345 + if (parentTaskExt == null) {
343 346 break;
344 347 }
345   - boolean currentTaskFinish = BpmProcessInstanceResultEnum.isEndResult(bpmTaskExtDO.getResult());
346   - // 2.2 如果 allChildrenTaskFinish 已经被赋值为 false ,则不会再赋值为 true,因为整个链路没有完成
  348 + boolean currentTaskFinish = BpmProcessInstanceResultEnum.isEndResult(parentTaskExt.getResult());
  349 + // 2.2 如果 allChildrenTaskFinish 已经被赋值为 false,则不会再赋值为 true,因为整个链路没有完成
347 350 if (allChildrenTaskFinish) {
348 351 allChildrenTaskFinish = currentTaskFinish;
349 352 }
... ... @@ -354,19 +357,19 @@ public class BpmTaskServiceImpl implements BpmTaskService {
354 357  
355 358 // 3 处理非完成状态的任务
356 359 // 3.1 判断当前任务的父任务是否还有子任务
357   - Long childrenTaskCount = getChildrenTaskCount(bpmTaskExtDO.getTaskId());
  360 + Long childrenTaskCount = getChildrenTaskCount(parentTaskExt.getTaskId());
358 361 if (childrenTaskCount > 0) {
359 362 continue;
360 363 }
361 364 // 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成
362   - if (BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult().equals(bpmTaskExtDO.getResult())) {
  365 + if (BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) {
363 366 // 3.3 需要修改该任务状态为处理中
364   - taskService.resolveTask(bpmTaskExtDO.getTaskId());
365   - bpmTaskExtDO.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
366   - taskExtMapper.updateByTaskId(bpmTaskExtDO);
  367 + taskService.resolveTask(parentTaskExt.getTaskId());
  368 + parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
  369 + taskExtMapper.updateByTaskId(parentTaskExt);
367 370 }
368 371 // 3.4 清空 scopeType 字段,用于任务没有子任务时使用该方法,方便任务可以再次被不同的方式加签
369   - parentTask = validateTaskExist(bpmTaskExtDO.getTaskId());
  372 + parentTask = validateTaskExist(parentTaskExt.getTaskId());
370 373 clearTaskScopeTypeAndSave(parentTask);
371 374 }
372 375  
... ... @@ -387,7 +390,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
387 390 taskService.saveTask(task);
388 391 }
389 392  
390   -
391 393 /**
392 394 * 获取子任务个数
393 395 *
... ... @@ -709,7 +711,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
709 711  
710 712 @Override
711 713 @Transactional(rollbackFor = Exception.class)
712   - public void addSignTask(Long userId, BpmTaskAddSignReqVO reqVO) {
  714 + public void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO) {
713 715 // 1. 获取和校验任务
714 716 TaskEntityImpl taskEntity = validateAddSign(userId, reqVO);
715 717 List<AdminUserRespDTO> userList = adminUserApi.getUserList(reqVO.getUserIdList());
... ... @@ -728,7 +730,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
728 730 // 2.3 更新扩展表状态
729 731 taskExtMapper.updateByTaskId(
730 732 new BpmTaskExtDO().setTaskId(taskEntity.getId())
731   - .setResult(BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult())
  733 + .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult())
732 734 .setReason(reqVO.getReason()));
733 735 }
734 736 // 2.4 记录加签方式,完成任务时需要用到判断
... ... @@ -737,12 +739,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
737 739 taskService.saveTask(taskEntity);
738 740  
739 741 // 3. 创建加签任务
740   - createAddSignChildrenTasks(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity);
  742 + createSignTask(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity);
741 743  
742 744 // 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason
743 745 AdminUserRespDTO currentUser = adminUserApi.getUser(userId);
744   - String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getTemplateComment(), currentUser.getNickname(), BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()),
745   - String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason());
  746 + String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), currentUser.getNickname(),
  747 + BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason());
746 748 taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(),
747 749 BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment);
748 750 }
... ... @@ -786,7 +788,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
786 788 * @param addSingUserIdList 被加签的用户 ID
787 789 * @param taskEntity 被加签的任务
788 790 */
789   - private void createAddSignChildrenTasks(List<String> addSingUserIdList, TaskEntityImpl taskEntity) {
  791 + private void createSignTask(List<String> addSingUserIdList, TaskEntityImpl taskEntity) {
790 792 if (CollUtil.isEmpty(addSingUserIdList)) {
791 793 return;
792 794 }
... ... @@ -795,23 +797,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
795 797 if (StrUtil.isBlank(addSignId)) {
796 798 continue;
797 799 }
798   - createChildrenTask(taskEntity, addSignId);
  800 + createSignTask(taskEntity, addSignId);
799 801 }
800 802 }
801 803  
802 804 /**
803   - * 创建子任务
  805 + * 创建加签子任务
804 806 *
805 807 * @param parentTask 父任务
806 808 * @param assignee 子任务的执行人
807   - * @return
808 809 */
809   - private void createChildrenTask(TaskEntityImpl parentTask, String assignee) {
  810 + private void createSignTask(TaskEntityImpl parentTask, String assignee) {
810 811 // 1. 生成子任务
811 812 TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID());
812 813 task = BpmTaskConvert.INSTANCE.convert(task, parentTask);
813 814 if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) {
814   - // 2.1 前加签,才设置审批人,否则设置 owner
  815 + // 2.1 前加签,设置审批人
815 816 task.setAssignee(assignee);
816 817 } else {
817 818 // 2.2.1 设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成
... ... @@ -825,9 +826,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
825 826  
826 827 @Override
827 828 @Transactional(rollbackFor = Exception.class)
828   - public void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO) {
  829 + public void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO) {
  830 + // 1.1 校验 task 可以被减签
829 831 Task task = validateSubSign(reqVO.getId());
830   - AdminUserRespDTO user = adminUserApi.getUser(userId);
  832 + // 1.2 校验取消人存在
831 833 AdminUserRespDTO cancelUser = null;
832 834 if (StrUtil.isNotBlank(task.getAssignee())) {
833 835 cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee()));
... ... @@ -836,20 +838,24 @@ public class BpmTaskServiceImpl implements BpmTaskService {
836 838 cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner()));
837 839 }
838 840 Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误");
839   - //1. 获取所有需要删除的任务 ID ,包含当前任务和所有子任务
  841 +
  842 + // 2. 删除任务和对应子任务
  843 + // 2.1 获取所有需要删除的任务 ID ,包含当前任务和所有子任务
840 844 List<String> allTaskIdList = getAllChildTaskIds(task.getId());
841   - //2. 删除任务和所有子任务
  845 + // 2.2 删除任务和所有子任务
842 846 taskService.deleteTasks(allTaskIdList);
843   - //3. 修改扩展表状态为取消
  847 + // 2.3 修改扩展表状态为取消
  848 + AdminUserRespDTO user = adminUserApi.getUser(userId);
844 849 taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
845 850 .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname())));
846   - //4.记录日志到父任务中 先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录
847   - String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getTemplateComment(), user.getNickname(), cancelUser.getNickname());
  851 +
  852 + // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录
  853 + String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname());
848 854 taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(),
849 855 BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment);
850   - //5. 处理当前任务的父任务
851   - this.handleParentTask(task);
852 856  
  857 + // 4. 处理当前任务的父任务
  858 + handleParentTask(task);
853 859 }
854 860  
855 861 /**
... ... @@ -860,14 +866,29 @@ public class BpmTaskServiceImpl implements BpmTaskService {
860 866 */
861 867 private Task validateSubSign(String id) {
862 868 Task task = validateTaskExist(id);
863   - //必须有parentId
864   - if (StrUtil.isEmpty(task.getParentTaskId())) {
  869 +
  870 + // 必须有 scopeType
  871 + String scopeType = task.getScopeType();
  872 + if (StrUtil.isEmpty(scopeType)) {
  873 + throw exception(TASK_SUB_SIGN_NO_PARENT);
  874 + }
  875 + // 并且值为 向前和向后加签
  876 + if (!validateSignType(scopeType)) {
865 877 throw exception(TASK_SUB_SIGN_NO_PARENT);
866 878 }
867 879 return task;
868 880 }
869 881  
870 882 /**
  883 + * 判断当前类型是否为加签
  884 + * @param scopeType 任务的 scopeType
  885 + * @return 当前 scopeType 为加签则返回 true
  886 + */
  887 + private boolean validateSignType(String scopeType){
  888 + return StrUtil.equalsAny(scopeType,BpmTaskAddSignTypeEnum.BEFORE.getType(),scopeType, BpmTaskAddSignTypeEnum.AFTER.getType());
  889 + }
  890 +
  891 + /**
871 892 * 获取所有要被取消的删除的任务 ID 集合
872 893 *
873 894 * @param parentTaskId 父级任务ID
... ... @@ -875,25 +896,40 @@ public class BpmTaskServiceImpl implements BpmTaskService {
875 896 */
876 897 public List<String> getAllChildTaskIds(String parentTaskId) {
877 898 List<String> allChildTaskIds = new ArrayList<>();
878   - //1. 先将自己放入
879   - allChildTaskIds.add(parentTaskId);
880   - //2. 递归获取子级
881   - recursiveGetChildTaskIds(parentTaskId, allChildTaskIds);
  899 + // 1. 递归获取子级
  900 + Stack<String> stack = new Stack<>();
  901 + // 1.1 将根任务ID入栈
  902 + stack.push(parentTaskId);
  903 + //控制遍历的次数不超过 Byte.MAX_VALUE,避免脏数据造成死循环
  904 + int count = 0;
  905 + // TODO @海:< 的前后空格,要注意哈;
  906 + while (!stack.isEmpty() && count<Byte.MAX_VALUE) {
  907 + // 1.2 弹出栈顶任务ID
  908 + String taskId = stack.pop();
  909 + // 1.3 将任务ID添加到结果集合中
  910 + allChildTaskIds.add(taskId);
  911 + // 1.4 获取该任务的子任务列表
  912 + // TODO @海:有个更高效的写法;一次性去 in 一层;不然每个节点,都去查询一次 db, 太浪费了;每次 in,最终就是 O(h) 查询,而不是 O(n) 查询;
  913 + List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);
  914 + if (CollUtil.isNotEmpty(childrenTaskIdList)) {
  915 + for (String childTaskId : childrenTaskIdList) {
  916 + // 1.5 将子任务ID入栈,以便后续处理
  917 + stack.push(childTaskId);
  918 + }
  919 + }
  920 + count++;
  921 + }
882 922 return allChildTaskIds;
883 923 }
884 924  
885 925 /**
886   - * 递归处理子级任务
  926 + * 获取指定父级任务的所有子任务 ID 集合
887 927 *
888   - * @param taskId 当前任务ID
889   - * @param taskIds 结果
  928 + * @param parentTaskId 父任务 ID
  929 + * @return 所有子任务的 ID 集合
890 930 */
891   - private void recursiveGetChildTaskIds(String taskId, List<String> taskIds) {
892   - List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);
893   - for (String childTaskId : childrenTaskIdList) {
894   - taskIds.add(childTaskId); // 将子任务的ID添加到集合中
895   - recursiveGetChildTaskIds(childTaskId, taskIds); // 递归获取子任务的子任务
896   - }
  931 + private List<String> getChildrenTaskIdList(String parentTaskId) {
  932 + return convertList(getChildrenTaskList0(parentTaskId), Task::getId);
897 933 }
898 934  
899 935 /**
... ... @@ -902,33 +938,32 @@ public class BpmTaskServiceImpl implements BpmTaskService {
902 938 * @param parentTaskId 父任务 ID
903 939 * @return 所有子任务的 ID 集合
904 940 */
905   - private List<String> getChildrenTaskIdList(String parentTaskId) {
  941 + private List<Task> getChildrenTaskList0(String parentTaskId) {
906 942 String tableName = managementService.getTableName(TaskEntity.class);
907   - String sql = "select ID_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
908   - List<Task> childrenTaskList = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
909   - return convertList(childrenTaskList, Task::getId);
  943 + // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询
  944 + String sql = "select ID_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
  945 + return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
910 946 }
911 947  
  948 +
912 949 @Override
913   - public List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId) {
914   - List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);
915   - if (CollUtil.isEmpty(childrenTaskIdList)) {
  950 + public List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId) {
  951 + // 1. 只查询进行中的任务 后加签的任务,可能不存在 assignee,所以还需要查询 owner
  952 + List<Task> taskList = getChildrenTaskList0(parentId);
  953 + if (CollUtil.isEmpty(taskList)) {
916 954 return Collections.emptyList();
917 955 }
918   - //1. 只查询进行中的任务
919   - List<BpmTaskExtDO> bpmTaskExtDOList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList);
920   - //2. 后加签的任务,可能不存在 assignee,所以还需要查询 owner
921   - List<Task> taskList = taskService.createTaskQuery().taskIds(childrenTaskIdList).list();
922   - Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId);
923   - //3. 将 owner 和 assignee 统一到一个集合中
924   - List<Long> userIds = taskList.stream()
925   - .flatMap(control ->
926   - Stream.of(control.getAssignee(), control.getOwner())
927   - .filter(Objects::nonNull))
928   - .distinct()
929   - .map(NumberUtils::parseLong)
930   - .collect(Collectors.toList());
  956 + List<String> childrenTaskIdList = convertList(taskList, Task::getId);
  957 +
  958 + // 2.1 将 owner 和 assignee 统一到一个集合中
  959 + List<Long> userIds = convertListByFlatMap(taskList, control ->
  960 + Stream.of(NumberUtils.parseLong(control.getAssignee()), NumberUtils.parseLong(control.getOwner()))
  961 + .filter(Objects::nonNull));
  962 + // 2.2 组装数据
931 963 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
932   - return BpmTaskConvert.INSTANCE.convertList(bpmTaskExtDOList, userMap, idTaskMap);
  964 + List<BpmTaskExtDO> taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList);
  965 + Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId);
  966 + return BpmTaskConvert.INSTANCE.convertList(taskExtList, userMap, idTaskMap);
933 967 }
  968 +
934 969 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java
... ... @@ -147,7 +147,7 @@ public class DatabaseDocController {
147 147 */
148 148 private static ProcessConfig buildProcessConfig() {
149 149 return ProcessConfig.builder()
150   - .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_")) // 忽略表前缀
  150 + .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_", "FLW_")) // 忽略表前缀
151 151 .build();
152 152 }
153 153  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java
... ... @@ -29,8 +29,6 @@ public class SecurityConfiguration {
29 29 .antMatchers("/swagger-resources/**").anonymous()
30 30 .antMatchers("/webjars/**").anonymous()
31 31 .antMatchers("/*/api-docs").anonymous();
32   - // 积木报表
33   - registry.antMatchers("/jmreport/**").permitAll();
34 32 // Spring Boot Actuator 的安全配置
35 33 registry.antMatchers("/actuator").anonymous()
36 34 .antMatchers("/actuator/**").anonymous();
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/JobLogCleanJob.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/JobLogCleanJob.java
1   -package cn.iocoder.yudao.module.infra.job.logger;
  1 +package cn.iocoder.yudao.module.infra.job.job;
2 2  
3 3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
4 4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
... ... @@ -33,7 +33,7 @@ public class JobLogCleanJob implements JobHandler {
33 33 @TenantIgnore
34 34 public String execute(String param) {
35 35 Integer count = jobLogService.cleanJobLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
36   - log.info("[count][定时执行清理定时任务日志数量 ({}) 个]", count);
  36 + log.info("[execute][定时执行清理定时任务日志数量 ({}) 个]", count);
37 37 return String.format("定时执行清理定时任务日志数量 %s 个", count);
38 38 }
39 39  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/AccessLogCleanJob.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/AccessLogCleanJob.java
1   -package cn.iocoder.yudao.module.infra.job.job;
  1 +package cn.iocoder.yudao.module.infra.job.logger;
2 2  
3 3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
4 4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
... ... @@ -34,7 +34,7 @@ public class AccessLogCleanJob implements JobHandler {
34 34 @TenantIgnore
35 35 public String execute(String param) {
36 36 Integer count = apiAccessLogService.cleanAccessLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
37   - log.info("[count][定时执行清理访问日志数量 ({}) 个]", count);
  37 + log.info("[execute][定时执行清理访问日志数量 ({}) 个]", count);
38 38 return String.format("定时执行清理错误日志数量 %s 个", count);
39 39 }
40 40  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/ErrorLogCleanJob.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/ErrorLogCleanJob.java
1   -package cn.iocoder.yudao.module.infra.job.job;
  1 +package cn.iocoder.yudao.module.infra.job.logger;
2 2  
3 3 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
4 4 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
... ... @@ -34,7 +34,7 @@ public class ErrorLogCleanJob implements JobHandler {
34 34 @TenantIgnore
35 35 public String execute(String param) {
36 36 Integer count = apiErrorLogService.cleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT);
37   - log.info("[count][定时执行清理错误日志数量 ({}) 个]", count);
  37 + log.info("[execute][定时执行清理错误日志数量 ({}) 个]", count);
38 38 return String.format("定时执行清理错误日志数量 %s 个", count);
39 39 }
40 40  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
... ... @@ -58,9 +58,9 @@ public class FileConfigServiceImpl implements FileConfigService {
58 58 FileConfigDO config = Objects.equals(CACHE_MASTER_ID, id) ?
59 59 fileConfigMapper.selectByMaster() : fileConfigMapper.selectById(id);
60 60 if (config != null) {
61   - fileClientFactory.createOrUpdateFileClient(id, config.getStorage(), config.getConfig());
  61 + fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
62 62 }
63   - return fileClientFactory.getFileClient(id);
  63 + return fileClientFactory.getFileClient(null == config ? id : config.getId());
64 64 }
65 65  
66 66 });
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm
... ... @@ -28,5 +28,5 @@ export function delete${simpleClassName}(id: number) {
28 28  
29 29 // 导出${table.classComment} Excel
30 30 export function export${simpleClassName}(params) {
31   - return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls')
  31 + return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls')
32 32 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm
1   -import type { BasicColumn, FormSchema } from '@/components/Table'
2   -import { useRender } from '@/components/Table'
3   -import { DICT_TYPE, getDictOptions } from '@/utils/dict'
  1 +import type {BasicColumn, FormSchema} from '@/components/Table'
  2 +import {useRender} from '@/components/Table'
  3 +import {DICT_TYPE, getDictOptions} from '@/utils/dict'
4 4  
5 5 export const columns: BasicColumn[] = [
6 6 #foreach($column in $columns)
... ... @@ -50,7 +50,7 @@ export const searchFormSchema: FormSchema[] = [
50 50 field: '${javaField}',
51 51 #if ($column.htmlType == "input")
52 52 component: 'Input',
53   - #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
  53 + #elseif ($column.htmlType == "select")
54 54 component: 'Select',
55 55 componentProps: {
56 56 #if ("" != $dictType)## 设置了 dictType 数据字典的情况
... ... @@ -59,6 +59,15 @@ export const searchFormSchema: FormSchema[] = [
59 59 options: [],
60 60 #end
61 61 },
  62 + #elseif ($column.htmlType == "radio")
  63 + component: 'Radio',
  64 + componentProps: {
  65 + #if ("" != $dictType)## 设置了 dictType 数据字典的情况
  66 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase()),
  67 + #else## 未设置 dictType 数据字典的情况
  68 + options: [],
  69 + #end
  70 + },
62 71 #elseif($column.htmlType == "datetime")
63 72 component: 'RangePicker',
64 73 #end
... ... @@ -181,7 +190,8 @@ export const updateFormSchema: FormSchema[] = [
181 190 fileType: 'file',
182 191 maxCount: 1,
183 192 },
184   - #elseif($column.htmlType == "editor")## 文本编辑器component: 'Editor',
  193 + #elseif($column.htmlType == "editor")## 文本编辑器
  194 + component: 'Editor',
185 195 #elseif($column.htmlType == "select")## 下拉框
186 196 component: 'Select',
187 197 componentProps: {
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm
1 1 <script lang="ts" setup>
2   -import ${ simpleClassName }Modal from './${simpleClassName}Modal.vue'
  2 +import ${simpleClassName}Modal from './${simpleClassName}Modal.vue'
3 3 import { columns, searchFormSchema } from './${classNameVar}.data'
4 4 import { useI18n } from '@/hooks/web/useI18n'
5 5 import { useMessage } from '@/hooks/web/useMessage'
6 6 import { useModal } from '@/components/Modal'
7   -import { IconEnum } from '@/enums/appEnum'
8   -import { BasicTable, useTable, TableAction } from '@/components/Table'
9   -import { delete${ simpleClassName }, export${ simpleClassName }, get${ simpleClassName } Page } from '@/api/${table.moduleName}/${classNameVar}'
  7 +import { useTable } from '@/components/Table'
  8 +import { delete${simpleClassName}, export${simpleClassName}, get${simpleClassName}Page } from '@/api/${table.moduleName}/${classNameVar}'
10 9  
11 10 defineOptions({ name: '${table.className}' })
12 11  
... ... @@ -16,7 +15,7 @@ const [registerModal, { openModal }] = useModal()
16 15  
17 16 const [registerTable, { getForm, reload }] = useTable({
18 17 title: '${table.classComment}列表',
19   - api: get${ simpleClassName }Page,
  18 + api: get${simpleClassName}Page,
20 19 columns,
21 20 formConfig: { labelWidth: 120, schemas: searchFormSchema },
22 21 useSearchForm: true,
... ... @@ -43,14 +42,14 @@ async function handleExport() {
43 42 iconType: 'warning',
44 43 content: t('common.exportMessage'),
45 44 async onOk() {
46   - await export${ simpleClassName } (getForm().getFieldsValue())
  45 + await export${simpleClassName}(getForm().getFieldsValue())
47 46 createMessage.success(t('common.exportSuccessText'))
48 47 },
49 48 })
50 49 }
51 50  
52 51 async function handleDelete(record: Recordable) {
53   - await delete${ simpleClassName } (record.id)
  52 + await delete${simpleClassName}(record.id)
54 53 createMessage.success(t('common.delSuccessText'))
55 54 reload()
56 55 }
... ... @@ -62,7 +61,7 @@ async function handleDelete(record: Recordable) {
62 61 <a-button type="primary" v-auth="['${permissionPrefix}:create']" :preIcon="IconEnum.ADD" @click="handleCreate">
63 62 {{ t('action.create') }}
64 63 </a-button>
65   - <a-button type="warning" v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport">
  64 + <a-button v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport">
66 65 {{ t('action.export') }}
67 66 </a-button>
68 67 </template>
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java
... ... @@ -258,12 +258,12 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
258 258 Long id = fileConfig.getId();
259 259 // mock 获得 Client
260 260 FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig());
261   - when(fileClientFactory.getFileClient(eq(0L))).thenReturn(fileClient);
  261 + when(fileClientFactory.getFileClient(eq(fileConfig.getId()))).thenReturn(fileClient);
262 262  
263 263 // 调用,并断言
264 264 assertSame(fileClient, fileConfigService.getMasterFileClient());
265 265 // 断言缓存
266   - verify(fileClientFactory).createOrUpdateFileClient(eq(0L), eq(fileConfig.getStorage()),
  266 + verify(fileClientFactory).createOrUpdateFileClient(eq(fileConfig.getId()), eq(fileConfig.getStorage()),
267 267 eq(fileConfig.getConfig()));
268 268 }
269 269  
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/dto/ProductCommentCreateReqDTO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.api.comment.dto;
2 2  
3 3 import lombok.Data;
4 4  
  5 +import javax.validation.constraints.NotNull;
5 6 import java.util.List;
6 7  
7 8 /**
... ... @@ -15,6 +16,7 @@ public class ProductCommentCreateReqDTO {
15 16 /**
16 17 * 商品 SKU 编号
17 18 */
  19 + @NotNull(message = "商品 SKU 编号不能为空")
18 20 private Long skuId;
19 21 /**
20 22 * 订单编号
... ... @@ -26,20 +28,19 @@ public class ProductCommentCreateReqDTO {
26 28 private Long orderItemId;
27 29  
28 30 /**
29   - * 评分星级 1-5 分
30   - */
31   - private Integer scores;
32   - /**
33 31 * 描述星级 1-5 分
34 32 */
  33 + @NotNull(message = "描述星级不能为空")
35 34 private Integer descriptionScores;
36 35 /**
37 36 * 服务星级 1-5 分
38 37 */
  38 + @NotNull(message = "服务星级不能为空")
39 39 private Integer benefitScores;
40 40 /**
41 41 * 评论内容
42 42 */
  43 + @NotNull(message = "评论内容不能为空")
43 44 private String content;
44 45 /**
45 46 * 评论图片地址数组,以逗号分隔最多上传 9 张
... ... @@ -49,11 +50,12 @@ public class ProductCommentCreateReqDTO {
49 50 /**
50 51 * 是否匿名
51 52 */
  53 + @NotNull(message = "是否匿名不能为空")
52 54 private Boolean anonymous;
53 55 /**
54 56 * 评价人
55 57 */
  58 + @NotNull(message = "评价人不能为空")
56 59 private Long userId;
57 60  
58   -
59 61 }
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/property/ProductPropertyValueApi.java deleted
1   -package cn.iocoder.yudao.module.product.api.property;
2   -
3   -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
4   -
5   -import java.util.Collection;
6   -import java.util.List;
7   -
8   -/**
9   - * 商品属性值 API 接口
10   - *
11   - * @author 芋道源码
12   - */
13   -public interface ProductPropertyValueApi {
14   -
15   - /**
16   - * 根据编号数组,获得属性值列表
17   - *
18   - * @param ids 编号数组
19   - * @return 属性值明细列表
20   - */
21   - List<ProductPropertyValueDetailRespDTO> getPropertyValueDetailList(Collection<Long> ids);
22   -
23   -}
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
... ... @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.product.api.spu.dto;
3 3 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
4 4 import lombok.Data;
5 5  
6   -import java.util.List;
7   -
8 6 // TODO @LeeYan9: ProductSpuRespDTO
9 7 /**
10 8 * 商品 SPU 信息 Response DTO
... ... @@ -27,55 +25,22 @@ public class ProductSpuRespDTO {
27 25 */
28 26 private String name;
29 27 /**
30   - * 关键字
31   - */
32   - private String keyword;
33   - /**
34 28 * 单位
35 29 *
36 30 * 对应 product_unit 数据字典
37 31 */
38 32 private Integer unit;
39   - /**
40   - * 商品简介
41   - */
42   - private String introduction;
43   - /**
44   - * 商品详情
45   - */
46   - private String description;
47   - // TODO @芋艿:是不是要删除
48   - /**
49   - * 商品条码(一维码)
50   - */
51   - private String barCode;
52 33  
53 34 /**
54 35 * 商品分类编号
55 36 */
56 37 private Long categoryId;
57 38 /**
58   - * 商品品牌编号
59   - */
60   - private Long brandId;
61   - /**
62 39 * 商品封面图
63 40 */
64 41 private String picUrl;
65   - /**
66   - * 商品轮播图
67   - */
68   - private List<String> sliderPicUrls;
69   - /**
70   - * 商品视频
71   - */
72   - private String videoUrl;
73 42  
74 43 /**
75   - * 排序字段
76   - */
77   - private Integer sort;
78   - /**
79 44 * 商品状态
80 45 * <p>
81 46 * 枚举 {@link ProductSpuStatusEnum}
... ... @@ -124,22 +89,6 @@ public class ProductSpuRespDTO {
124 89 */
125 90 private Integer giveIntegral;
126 91  
127   - // ========== 统计相关字段 =========
128   -
129   - /**
130   - * 商品销量
131   - */
132   - private Integer salesCount;
133   - /**
134   - * 虚拟销量
135   - */
136   - private Integer virtualSalesCount;
137   - /**
138   - * 商品点击量
139   - */
140   - private Integer clickCount;
141   -
142   -
143 92 // ========== 分销相关字段 =========
144 93  
145 94 /**
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/group/ProductGroupStyleEnum.java deleted
1   -package cn.iocoder.yudao.module.product.enums.group;
2   -
3   -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
4   -import lombok.AllArgsConstructor;
5   -import lombok.Getter;
6   -
7   -import java.util.Arrays;
8   -
9   -/**
10   - * 商品分组的样式枚举
11   - *
12   - * @author 芋道源码
13   - */
14   -@Getter
15   -@AllArgsConstructor
16   -public enum ProductGroupStyleEnum implements IntArrayValuable {
17   -
18   - ONE(1, "每列一个"),
19   - TWO(2, "每列两个"),
20   - THREE(2, "每列三个"),;
21   -
22   - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductGroupStyleEnum::getStyle).toArray();
23   -
24   - /**
25   - * 列表样式
26   - */
27   - private final Integer style;
28   - /**
29   - * 状态名
30   - */
31   - private final String name;
32   -
33   - @Override
34   - public int[] array() {
35   - return ARRAYS;
36   - }
37   -
38   -}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/property/ProductPropertyValueApiImpl.java deleted
1   -package cn.iocoder.yudao.module.product.api.property;
2   -
3   -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
4   -import cn.iocoder.yudao.module.product.convert.property.ProductPropertyValueConvert;
5   -import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
6   -import org.springframework.stereotype.Service;
7   -import org.springframework.validation.annotation.Validated;
8   -
9   -import javax.annotation.Resource;
10   -import java.util.Collection;
11   -import java.util.List;
12   -
13   -/**
14   - * 商品属性值 API 实现类
15   - *
16   - * @author 芋道源码
17   - */
18   -@Service
19   -@Validated
20   -public class ProductPropertyValueApiImpl implements ProductPropertyValueApi {
21   -
22   - @Resource
23   - private ProductPropertyValueService productPropertyValueService;
24   -
25   - @Override
26   - public List<ProductPropertyValueDetailRespDTO> getPropertyValueDetailList(Collection<Long> ids) {
27   - return ProductPropertyValueConvert.INSTANCE.convertList02(
28   - productPropertyValueService.getPropertyValueDetailList(ids));
29   - }
30   -
31   -}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
1 1 package cn.iocoder.yudao.module.product.api.sku;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
5 4 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
6 5 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
... ... @@ -11,7 +10,6 @@ import org.springframework.validation.annotation.Validated;
11 10  
12 11 import javax.annotation.Resource;
13 12 import java.util.Collection;
14   -import java.util.Collections;
15 13 import java.util.List;
16 14  
17 15 /**
... ... @@ -35,18 +33,12 @@ public class ProductSkuApiImpl implements ProductSkuApi {
35 33  
36 34 @Override
37 35 public List<ProductSkuRespDTO> getSkuList(Collection<Long> ids) {
38   - if (CollUtil.isEmpty(ids)) {
39   - return Collections.emptyList();
40   - }
41 36 List<ProductSkuDO> skus = productSkuService.getSkuList(ids);
42 37 return ProductSkuConvert.INSTANCE.convertList04(skus);
43 38 }
44 39  
45 40 @Override
46 41 public List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds) {
47   - if (CollUtil.isEmpty(spuIds)) {
48   - return Collections.emptyList();
49   - }
50 42 List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spuIds);
51 43 return ProductSkuConvert.INSTANCE.convertList04(skus);
52 44 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
... ... @@ -27,9 +27,6 @@ public class ProductSpuApiImpl implements ProductSpuApi {
27 27  
28 28 @Override
29 29 public List<ProductSpuRespDTO> getSpuList(Collection<Long> ids) {
30   - if (CollectionUtil.isEmpty(ids)) {
31   - return Collections.emptyList();
32   - }
33 30 return ProductSpuConvert.INSTANCE.convertList2(spuService.getSpuList(ids));
34 31 }
35 32  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyValueConvert.java
1 1 package cn.iocoder.yudao.module.product.convert.property;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5   -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
6   -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
7 4 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
8 5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
9 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
10   -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
11 7 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
12   -import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;
13 8 import org.mapstruct.Mapper;
14 9 import org.mapstruct.factory.Mappers;
15 10  
16 11 import java.util.List;
17   -import java.util.Map;
18   -
19   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
20 12  
21 13 /**
22 14 * 属性值 Convert
... ... @@ -38,18 +30,4 @@ public interface ProductPropertyValueConvert {
38 30  
39 31 PageResult<ProductPropertyValueRespVO> convertPage(PageResult<ProductPropertyValueDO> page);
40 32  
41   - default List<ProductPropertyValueDetailRespBO> convertList(List<ProductPropertyValueDO> values, List<ProductPropertyDO> keys) {
42   - Map<Long, ProductPropertyDO> keyMap = convertMap(keys, ProductPropertyDO::getId);
43   - return CollectionUtils.convertList(values, value -> {
44   - ProductPropertyValueDetailRespBO valueDetail = new ProductPropertyValueDetailRespBO()
45   - .setValueId(value.getId()).setValueName(value.getName());
46   - // 设置属性项
47   - MapUtils.findAndThen(keyMap, value.getPropertyId(),
48   - key -> valueDetail.setPropertyId(key.getId()).setPropertyName(key.getName()));
49   - return valueDetail;
50   - });
51   - }
52   -
53   - List<ProductPropertyValueDetailRespDTO> convertList02(List<ProductPropertyValueDetailRespBO> list);
54   -
55 33 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java
... ... @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.Produc
5 5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
6 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
7 7 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
8   -import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;
9 8  
10 9 import java.util.Collection;
11 10 import java.util.List;
... ... @@ -57,14 +56,6 @@ public interface ProductPropertyValueService {
57 56 List<ProductPropertyValueDO> getPropertyValueListByPropertyId(Collection<Long> propertyIds);
58 57  
59 58 /**
60   - * 根据编号数组,获得属性值列表
61   - *
62   - * @param ids 编号数组
63   - * @return 属性值明细列表
64   - */
65   - List<ProductPropertyValueDetailRespBO> getPropertyValueDetailList(Collection<Long> ids);
66   -
67   - /**
68 59 * 根据属性项编号,活的属性值数量
69 60 *
70 61 * @param propertyId 属性项编号数
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java
1 1 package cn.iocoder.yudao.module.product.service.property;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 4 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
6 5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
7 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
8 7 import cn.iocoder.yudao.module.product.convert.property.ProductPropertyValueConvert;
9   -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
10 8 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
11 9 import cn.iocoder.yudao.module.product.dal.mysql.property.ProductPropertyValueMapper;
12   -import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;
13 10 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
14 11 import org.springframework.context.annotation.Lazy;
15 12 import org.springframework.stereotype.Service;
... ... @@ -17,11 +14,9 @@ import org.springframework.validation.annotation.Validated;
17 14  
18 15 import javax.annotation.Resource;
19 16 import java.util.Collection;
20   -import java.util.Collections;
21 17 import java.util.List;
22 18  
23 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
25 20 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_EXISTS;
26 21 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS;
27 22  
... ... @@ -100,23 +95,6 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ
100 95 }
101 96  
102 97 @Override
103   - public List<ProductPropertyValueDetailRespBO> getPropertyValueDetailList(Collection<Long> ids) {
104   - // 获得属性值列表
105   - if (CollUtil.isEmpty(ids)) {
106   - return Collections.emptyList();
107   - }
108   - List<ProductPropertyValueDO> values = productPropertyValueMapper.selectBatchIds(ids);
109   - if (CollUtil.isEmpty(values)) {
110   - return Collections.emptyList();
111   - }
112   - // 获得属性项列表
113   - List<ProductPropertyDO> keys = productPropertyService.getPropertyList(
114   - convertSet(values, ProductPropertyValueDO::getPropertyId));
115   - // 组装明细
116   - return ProductPropertyValueConvert.INSTANCE.convertList(values, keys);
117   - }
118   -
119   - @Override
120 98 public Integer getPropertyValueCountByPropertyId(Long propertyId) {
121 99 return productPropertyValueMapper.selectCountByPropertyId(propertyId);
122 100 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/bo/ProductPropertyValueDetailRespBO.java deleted
1   -package cn.iocoder.yudao.module.product.service.property.bo;
2   -
3   -import lombok.Data;
4   -
5   -/**
6   - * 商品属性项的明细 Response BO
7   - *
8   - * @author 芋道源码
9   - */
10   -@Data
11   -public class ProductPropertyValueDetailRespBO {
12   -
13   - /**
14   - * 属性的编号
15   - */
16   - private Long propertyId;
17   -
18   - /**
19   - * 属性的名称
20   - */
21   - private String propertyName;
22   -
23   - /**
24   - * 属性值的编号
25   - */
26   - private Long valueId;
27   -
28   - /**
29   - * 属性值的名称
30   - */
31   - private String valueName;
32   -
33   -}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
... ... @@ -153,6 +153,9 @@ public class ProductSkuServiceImpl implements ProductSkuService {
153 153  
154 154 @Override
155 155 public List<ProductSkuDO> getSkuListBySpuId(Collection<Long> spuIds) {
  156 + if (CollUtil.isEmpty(spuIds)) {
  157 + return Collections.emptyList();
  158 + }
156 159 return productSkuMapper.selectListBySpuId(spuIds);
157 160 }
158 161  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
... ... @@ -188,6 +188,9 @@ public class ProductSpuServiceImpl implements ProductSpuService {
188 188  
189 189 @Override
190 190 public List<ProductSpuDO> getSpuList(Collection<Long> ids) {
  191 + if (CollUtil.isEmpty(ids)) {
  192 + return Collections.emptyList();
  193 + }
191 194 return productSpuMapper.selectBatchIds(ids);
192 195 }
193 196  
... ...
yudao-module-mall/yudao-module-promotion-api/pom.xml
... ... @@ -13,7 +13,7 @@
13 13  
14 14 <name>${project.artifactId}</name>
15 15 <description>
16   - market 模块 API,暴露给其它模块调用
  16 + promotion 模块 API,暴露给其它模块调用
17 17 </description>
18 18  
19 19 <dependencies>
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApi.java deleted
1   -package cn.iocoder.yudao.module.promotion.api.combination;
2   -
3   -/**
4   - * 拼团活动 Api 接口
5   - *
6   - * @author HUIHUI
7   - */
8   -public interface CombinationActivityApi {
9   -
10   -}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
... ... @@ -42,14 +42,6 @@ public interface CombinationRecordApi {
42 42 boolean isCombinationRecordSuccess(Long userId, Long orderId);
43 43  
44 44 /**
45   - * 更新拼团状态为【失败】
46   - *
47   - * @param userId 用户编号
48   - * @param orderId 订单编号
49   - */
50   - void updateRecordStatusToFailed(Long userId, Long orderId);
51   -
52   - /**
53 45 * 【下单前】校验是否满足拼团活动条件
54 46 *
55 47 * 如果校验失败,则抛出业务异常
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/PriceApi.java deleted
1   -package cn.iocoder.yudao.module.promotion.api.price;
2   -
3   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
4   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
5   -
6   -/**
7   - * 价格 API 接口
8   - *
9   - * @author 芋道源码
10   - */
11   -public interface PriceApi {
12   -
13   - /**
14   - * 计算商品的价格
15   - *
16   - * @param calculateReqDTO 价格请求
17   - * @return 价格相应
18   - */
19   - PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO);
20   -
21   -}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/CouponMeetRespDTO.java deleted
1   -package cn.iocoder.yudao.module.promotion.api.price.dto;
2   -
3   -import lombok.Data;
4   -
5   -/**
6   - * 优惠劵的匹配信息 Response DTO
7   - *
8   - * why 放在 price 包下?主要获取的时候,需要涉及到较多的价格计算逻辑,放在 price 可以更好的复用逻辑
9   - *
10   - * @author 芋道源码
11   - */
12   -@Data
13   -public class CouponMeetRespDTO {
14   -
15   - /**
16   - * 优惠劵编号
17   - */
18   - private Long id;
19   -
20   - // ========== 非优惠劵的基本信息字段 ==========
21   - /**
22   - * 是否匹配
23   - */
24   - private Boolean meet;
25   - /**
26   - * 不匹配的提示,即 {@link #meet} = true 才有值
27   - *
28   - * 例如说:
29   - * 1. 所结算商品没有符合条件的商品
30   - * 2. 差 XXX 元可用优惠劵
31   - * 3. 优惠劵未到使用时间
32   - */
33   - private String meetTip;
34   -
35   -}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateReqDTO.java deleted
1   -package cn.iocoder.yudao.module.promotion.api.price.dto;
2   -
3   -import lombok.Data;
4   -
5   -import javax.validation.constraints.Min;
6   -import javax.validation.constraints.NotNull;
7   -import java.util.List;
8   -
9   -/**
10   - * 价格计算 Request DTO
11   - *
12   - * @author 芋道源码
13   - */
14   -@Data
15   -@Deprecated
16   -public class PriceCalculateReqDTO {
17   -
18   - /**
19   - * 用户编号
20   - *
21   - * 对应 MemberUserDO 的 id 编号
22   - */
23   - private Long userId;
24   -
25   - /**
26   - * 优惠劵编号
27   - */
28   - private Long couponId;
29   -
30   - /**
31   - * 收货地址编号
32   - */
33   - private Long addressId;
34   -
35   - /**
36   - * 商品 SKU 数组
37   - */
38   - @NotNull(message = "商品数组不能为空")
39   - private List<Item> items;
40   -
41   - /**
42   - * 商品 SKU
43   - */
44   - @Data
45   - public static class Item {
46   -
47   - /**
48   - * SKU 编号
49   - */
50   - @NotNull(message = "商品 SKU 编号不能为空")
51   - private Long skuId;
52   -
53   - /**
54   - * SKU 数量
55   - */
56   - @NotNull(message = "商品 SKU 数量不能为空")
57   - @Min(value = 0L, message = "商品 SKU 数量必须大于等于 0") // 可传递 0 数量,用于购物车未选中的情况
58   - private Integer count;
59   -
60   - }
61   -
62   -}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateRespDTO.java deleted
1   -package cn.iocoder.yudao.module.promotion.api.price.dto;
2   -
3   -import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
4   -import lombok.Data;
5   -
6   -import java.util.List;
7   -
8   -/**
9   - * 价格计算 Response DTO
10   - *
11   - * 整体设计,参考 taobao 的技术文档:
12   - * 1. <a href="https://developer.alibaba.com/docs/doc.htm?treeId=1&articleId=1029&docType=1">订单管理</a>
13   - * 2. <a href="https://open.taobao.com/docV3.htm?docId=108471&docType=1">常用订单金额说明</a>
14   - *
15   - * 举个例子:<a href="https://img.alicdn.com/top/i1/LB1mALAi4HI8KJjy1zbXXaxdpXa">订单图</a>
16   - * 输入:
17   - * 1. 订单实付: trade.payment = 198.00;订单邮费:5 元;
18   - * 2. 商品级优惠 圣诞价: 省 29.00 元 和 圣诞价:省 150.00 元; 订单级优惠,圣诞 2:省 5.00 元;
19   - * 分摊:
20   - * 1. 商品 1:原价 108 元,优惠 29 元,子订单实付 79 元,分摊主订单优惠 1.99 元;
21   - * 2. 商品 2:原价 269 元,优惠 150 元,子订单实付 119 元,分摊主订单优惠 3.01 元;
22   - *
23   - * @author 芋道源码
24   - */
25   -@Data
26   -@Deprecated
27   -public class PriceCalculateRespDTO {
28   -
29   - /**
30   - * 订单
31   - */
32   - private Order order;
33   -
34   - /**
35   - * 营销活动数组
36   - *
37   - * 只对应 {@link Order#items} 商品匹配的活动
38   - */
39   - private List<Promotion> promotions;
40   -
41   - // TODO @芋艿:需要改造下,主要是价格字段
42   - /**
43   - * 订单
44   - */
45   - @Data
46   - public static class Order {
47   -
48   - /**
49   - * 商品原价(总),单位:分
50   - *
51   - * 基于 {@link OrderItem#getOriginalPrice()} 求和
52   - *
53   - * 对应 taobao 的 trade.total_fee 字段
54   - */
55   - private Integer totalPrice;
56   - /**
57   - * 订单优惠(总),单位:分
58   - *
59   - * 订单级优惠:对主订单的优惠,常见如:订单满 200 元减 10 元;订单满 80 包邮。
60   - *
61   - * 对应 taobao 的 order.discount_fee 字段
62   - */
63   - private Integer discountPrice;
64   - /**
65   - * 优惠劵减免金额(总),单位:分
66   - *
67   - * 对应 taobao 的 trade.coupon_fee 字段
68   - */
69   - private Integer couponPrice;
70   - /**
71   - * 积分减免金额(总),单位:分
72   - *
73   - * 对应 taobao 的 trade.point_fee 字段
74   - */
75   - private Integer pointPrice;
76   - /**
77   - * 运费金额,单位:分
78   - */
79   - private Integer deliveryPrice;
80   - /**
81   - * 最终购买金额(总),单位:分
82   - *
83   - * = {@link OrderItem#getPayPrice()} 求和
84   - * - {@link #couponPrice}
85   - * - {@link #pointPrice}
86   - * + {@link #deliveryPrice}
87   - * - {@link #discountPrice}
88   - */
89   - private Integer payPrice;
90   - /**
91   - * 商品 SKU 数组
92   - */
93   - private List<OrderItem> items;
94   -
95   - // ========== 营销基本信息 ==========
96   - /**
97   - * 优惠劵编号
98   - */
99   - private Long couponId;
100   -
101   - }
102   -
103   - /**
104   - * 订单商品 SKU
105   - */
106   - @Data
107   - public static class OrderItem {
108   -
109   - /**
110   - * SPU 编号
111   - */
112   - private Long spuId;
113   - /**
114   - * SKU 编号
115   - */
116   - private Long skuId;
117   - /**
118   - * 购买数量
119   - */
120   - private Integer count;
121   -
122   - /**
123   - * 商品原价(总),单位:分
124   - *
125   - * = {@link #originalUnitPrice} * {@link #getCount()}
126   - */
127   - private Integer originalPrice;
128   - /**
129   - * 商品原价(单),单位:分
130   - *
131   - * 对应 ProductSkuDO 的 price 字段
132   - * 对应 taobao 的 order.price 字段
133   - */
134   - private Integer originalUnitPrice;
135   - /**
136   - * 商品优惠(总),单位:分
137   - *
138   - * 商品级优惠:对单个商品的,常见如:商品原价的 8 折;商品原价的减 50 元
139   - *
140   - * 对应 taobao 的 order.discount_fee 字段
141   - */
142   - private Integer discountPrice;
143   - /**
144   - * 子订单实付金额,不算主订单分摊金额,单位:分
145   - *
146   - * = {@link #originalPrice}
147   - * - {@link #discountPrice}
148   - *
149   - * 对应 taobao 的 order.payment 字段
150   - */
151   - private Integer payPrice;
152   -
153   - /**
154   - * 子订单分摊金额(总),单位:分
155   - * 需要分摊 {@link Order#discountPrice}、{@link Order#couponPrice}、{@link Order#pointPrice}
156   - *
157   - * 对应 taobao 的 order.part_mjz_discount 字段
158   - * 淘宝说明:子订单分摊优惠基础逻辑:一般正常优惠券和满减优惠按照子订单的金额进行分摊,特殊情况如果优惠券是指定商品使用的,只会分摊到对应商品子订单上不分摊。
159   - */
160   - private Integer orderPartPrice;
161   - /**
162   - * 分摊后子订单实付金额(总),单位:分
163   - *
164   - * = {@link #payPrice}
165   - * - {@link #orderPartPrice}
166   - *
167   - * 对应 taobao 的 divide_order_fee 字段
168   - */
169   - private Integer orderDividePrice;
170   -
171   - }
172   -
173   - /**
174   - * 营销明细
175   - */
176   - @Data
177   - @Deprecated
178   - public static class Promotion {
179   -
180   - /**
181   - * 营销编号
182   - *
183   - * 例如说:营销活动的编号、优惠劵的编号
184   - */
185   - private Long id;
186   - /**
187   - * 营销名字
188   - */
189   - private String name;
190   - /**
191   - * 营销类型
192   - *
193   - * 枚举 {@link PromotionTypeEnum}
194   - */
195   - private Integer type;
196   - /**
197   - * 营销级别
198   - *
199   - * 枚举 @link PromotionLevelEnum} TODO PromotionLevelEnum 没有这个枚举类
200   - */
201   - private Integer level;
202   - /**
203   - * 计算时的原价(总),单位:分
204   - */
205   - private Integer totalPrice;
206   - /**
207   - * 计算时的优惠(总),单位:分
208   - */
209   - private Integer discountPrice;
210   - /**
211   - * 匹配的商品 SKU 数组
212   - */
213   - private List<PromotionItem> items;
214   -
215   - // ========== 匹配情况 ==========
216   -
217   - /**
218   - * 是否满足优惠条件
219   - */
220   - private Boolean match;
221   - /**
222   - * 满足条件的提示
223   - *
224   - * 如果 {@link #match} = true 满足,则提示“圣诞价:省 150.00 元”
225   - * 如果 {@link #match} = false 不满足,则提示“购满 85 元,可减 40 元”
226   - */
227   - private String description;
228   -
229   - }
230   -
231   - /**
232   - * 营销匹配的商品 SKU
233   - */
234   - @Data
235   - public static class PromotionItem {
236   -
237   - /**
238   - * 商品 SKU 编号
239   - */
240   - private Long skuId;
241   - /**
242   - * 计算时的原价(总),单位:分
243   - */
244   - private Integer originalPrice;
245   - /**
246   - * 计算时的优惠(总),单位:分
247   - */
248   - private Integer discountPrice;
249   -
250   - }
251   -
252   -}
yudao-module-mall/yudao-module-promotion-biz/pom.xml
... ... @@ -14,8 +14,8 @@
14 14 <name>${project.artifactId}</name>
15 15  
16 16 <description>
17   - market模块,主要实现营销相关功能
18   - 例如:营销活动、banner广告、优惠券、优惠码等功能。
  17 + promotion 模块,主要实现营销相关功能
  18 + 例如:营销活动、banner 广告、优惠券、优惠码等功能。
19 19 </description>
20 20  
21 21 <dependencies>
... ... @@ -49,10 +49,6 @@
49 49 <groupId>cn.iocoder.boot</groupId>
50 50 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
51 51 </dependency>
52   - <dependency>
53   - <groupId>cn.iocoder.boot</groupId>
54   - <artifactId>yudao-spring-boot-starter-biz-weixin</artifactId>
55   - </dependency>
56 52  
57 53 <!-- Web 相关 -->
58 54 <dependency>
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.api.bargain;
2 2  
3 3 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
4 4 import org.springframework.stereotype.Service;
  5 +import org.springframework.validation.annotation.Validated;
5 6  
6 7 import javax.annotation.Resource;
7 8  
... ... @@ -11,6 +12,7 @@ import javax.annotation.Resource;
11 12 * @author HUIHUI
12 13 */
13 14 @Service
  15 +@Validated
14 16 public class BargainActivityApiImpl implements BargainActivityApi {
15 17  
16 18 @Resource
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApiImpl.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.bargain;
3 3 import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO;
4 4 import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService;
5 5 import org.springframework.stereotype.Service;
  6 +import org.springframework.validation.annotation.Validated;
6 7  
7 8 import javax.annotation.Resource;
8 9  
... ... @@ -12,6 +13,7 @@ import javax.annotation.Resource;
12 13 * @author HUIHUI
13 14 */
14 15 @Service
  16 +@Validated
15 17 public class BargainRecordApiImpl implements BargainRecordApi {
16 18  
17 19 @Resource
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApiImpl.java deleted
1   -package cn.iocoder.yudao.module.promotion.api.combination;
2   -
3   -import org.springframework.stereotype.Service;
4   -
5   -/**
6   - * 拼团活动 Api 接口实现类
7   - *
8   - * @author HUIHUI
9   - */
10   -@Service
11   -public class CombinationActivityApiImpl implements CombinationActivityApi {
12   -
13   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR
8 8 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
9 9 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
10 10 import org.springframework.stereotype.Service;
  11 +import org.springframework.validation.annotation.Validated;
11 12  
12 13 import javax.annotation.Resource;
13 14  
... ... @@ -20,6 +21,7 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINA
20 21 * @author HUIHUI
21 22 */
22 23 @Service
  24 +@Validated
23 25 public class CombinationRecordApiImpl implements CombinationRecordApi {
24 26  
25 27 @Resource
... ... @@ -45,11 +47,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
45 47 }
46 48  
47 49 @Override
48   - public void updateRecordStatusToFailed(Long userId, Long orderId) {
49   - recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.FAILED.getStatus(), userId, orderId);
50   - }
51   -
52   - @Override
53 50 public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, Long skuId, Integer count) {
54 51 return recordService.validateJoinCombination(userId, activityId, headId, skuId, count);
55 52 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert;
8 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
9 9 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
10 10 import org.springframework.stereotype.Service;
  11 +import org.springframework.validation.annotation.Validated;
11 12  
12 13 import javax.annotation.Resource;
13 14  
... ... @@ -17,6 +18,7 @@ import javax.annotation.Resource;
17 18 * @author 芋道源码
18 19 */
19 20 @Service
  21 +@Validated
20 22 public class CouponApiImpl implements CouponApi {
21 23  
22 24 @Resource
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO
4 4 import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
5 5 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
6 6 import org.springframework.stereotype.Service;
  7 +import org.springframework.validation.annotation.Validated;
7 8  
8 9 import javax.annotation.Resource;
9 10 import java.util.Collection;
... ... @@ -15,6 +16,7 @@ import java.util.List;
15 16 * @author 芋道源码
16 17 */
17 18 @Service
  19 +@Validated
18 20 public class DiscountActivityApiImpl implements DiscountActivityApi {
19 21  
20 22 @Resource
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/price/PriceApiImpl.java deleted
1   -package cn.iocoder.yudao.module.promotion.api.price;
2   -
3   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
4   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
5   -import cn.iocoder.yudao.module.promotion.service.price.PriceService;
6   -import org.springframework.stereotype.Service;
7   -
8   -import javax.annotation.Resource;
9   -
10   -/**
11   - * 价格 API 实现类
12   - *
13   - * @author 芋道源码
14   - */
15   -@Service
16   -public class PriceApiImpl implements PriceApi {
17   -
18   - @Resource
19   - private PriceService priceService;
20   -
21   - @Override
22   - public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) {
23   - //return priceService.calculatePrice(calculateReqDTO); TODO 没有 calculatePrice 这个方法
24   -
25   - return null;
26   - }
27   -
28   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.reward;
3 3 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
4 4 import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
5 5 import org.springframework.stereotype.Service;
  6 +import org.springframework.validation.annotation.Validated;
6 7  
7 8 import javax.annotation.Resource;
8 9 import java.util.Collection;
... ... @@ -14,6 +15,7 @@ import java.util.List;
14 15 * @author 芋道源码
15 16 */
16 17 @Service
  18 +@Validated
17 19 public class RewardActivityApiImpl implements RewardActivityApi {
18 20  
19 21 @Resource
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.seckill;
3 3 import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO;
4 4 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
5 5 import org.springframework.stereotype.Service;
  6 +import org.springframework.validation.annotation.Validated;
6 7  
7 8 import javax.annotation.Resource;
8 9  
... ... @@ -12,6 +13,7 @@ import javax.annotation.Resource;
12 13 * @author HUIHUI
13 14 */
14 15 @Service
  16 +@Validated
15 17 public class SeckillActivityApiImpl implements SeckillActivityApi {
16 18  
17 19 @Resource
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerRespVO.java
... ... @@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5 import lombok.ToString;
6 6  
  7 +import java.time.LocalDateTime;
  8 +
7 9 @Schema(description = "管理后台 - Banner Response VO")
8 10 @Data
9 11 @ToString(callSuper = true)
... ... @@ -12,4 +14,7 @@ public class BannerRespVO extends BannerBaseVO {
12 14 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED)
13 15 private Long id;
14 16  
  17 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59")
  18 + private LocalDateTime createTime;
  19 +
15 20 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java
... ... @@ -96,13 +96,13 @@ public class AppCouponTemplateController {
96 96 */
97 97 private Long getProductScopeValue(Integer productScope, Long spuId) {
98 98 // 通用券:没有商品范围
99   - if (productScope == null || ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) {
  99 + if (ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) {
100 100 return null;
101 101 }
102 102 // 品类券:查询商品的品类编号
103 103 if (Objects.equals(productScope, PromotionProductScopeEnum.CATEGORY.getScope()) && spuId != null) {
104   - return Optional.ofNullable(productSpuApi.getSpu(spuId))
105   - .map(ProductSpuRespDTO::getCategoryId).orElse(null);
  104 + ProductSpuRespDTO spu = productSpuApi.getSpu(spuId);
  105 + return spu != null ? spu.getCategoryId() : null;
106 106 }
107 107 // 商品卷:直接返回
108 108 return spuId;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/price/PriceConvert.java deleted
1   -package cn.iocoder.yudao.module.promotion.convert.price;
2   -
3   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4   -import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
5   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
6   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
7   -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
8   -import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
9   -import org.mapstruct.Mapper;
10   -import org.mapstruct.factory.Mappers;
11   -
12   -import java.util.ArrayList;
13   -import java.util.List;
14   -import java.util.Map;
15   -
16   -@Mapper
17   -public interface PriceConvert {
18   -
19   - PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class);
20   -
21   - default PriceCalculateRespDTO convert(PriceCalculateReqDTO calculateReqDTO, List<ProductSkuRespDTO> skuList) {
22   - // 创建 PriceCalculateRespDTO 对象
23   - PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO();
24   - // 创建它的 Order 属性
25   - PriceCalculateRespDTO.Order order = new PriceCalculateRespDTO.Order().setTotalPrice(0).setDiscountPrice(0)
26   - .setCouponPrice(0).setPointPrice(0).setDeliveryPrice(0).setPayPrice(0)
27   - .setItems(new ArrayList<>()).setCouponId(calculateReqDTO.getCouponId());
28   - priceCalculate.setOrder(order).setPromotions(new ArrayList<>());
29   - // 创建它的 OrderItem 属性
30   - Map<Long, Integer> skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(),
31   - PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount);
32   - skuList.forEach(sku -> {
33   - Integer count = skuIdCountMap.get(sku.getId());
34   - PriceCalculateRespDTO.OrderItem orderItem = new PriceCalculateRespDTO.OrderItem()
35   - .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count)
36   - .setOriginalUnitPrice(sku.getPrice()).setOriginalPrice(sku.getPrice() * count)
37   - .setDiscountPrice(0).setOrderPartPrice(0);
38   - orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice());
39   - priceCalculate.getOrder().getItems().add(orderItem);
40   - // 补充价格信息到 Order 中
41   - order.setTotalPrice(order.getTotalPrice() + orderItem.getOriginalPrice())
42   - .setPayPrice(order.getTotalPrice());
43   - });
44   - return priceCalculate;
45   - }
46   -
47   - CouponMeetRespDTO convert(CouponDO coupon);
48   -
49   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/UserCreateConsumer.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/CouponTakeByRegisterConsumer.java
1 1 package cn.iocoder.yudao.module.promotion.mq.consumer.coupon;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
4   -import cn.iocoder.yudao.module.promotion.mq.message.coupon.UserCreateMessage;
  3 +import cn.iocoder.yudao.module.member.message.user.MemberUserCreateMessage;
5 4 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
6 5 import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.event.EventListener;
  7 +import org.springframework.scheduling.annotation.Async;
7 8 import org.springframework.stereotype.Component;
8 9  
9 10 import javax.annotation.Resource;
10 11  
11 12 /**
12   - * 针对 {@link UserCreateMessage} 的消费者
  13 + * 用户注册时,发送优惠劵的消费者,基 {@link MemberUserCreateMessage} 消息
13 14 *
14 15 * @author owen
15 16 */
16 17 @Component
17 18 @Slf4j
18   -public class UserCreateConsumer extends AbstractStreamMessageListener<UserCreateMessage> {
  19 +public class CouponTakeByRegisterConsumer {
19 20  
20 21 @Resource
21 22 private CouponService couponService;
22 23  
23   - @Override
24   - public void onMessage(UserCreateMessage message) {
  24 + @EventListener
  25 + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
  26 + public void onMessage(MemberUserCreateMessage message) {
25 27 log.info("[onMessage][消息内容({})]", message);
26 28 couponService.takeCouponByRegister(message.getUserId());
27 29 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消费者
  3 + */
  4 +package cn.iocoder.yudao.module.promotion.mq.consumer;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消息
  3 + */
  4 +package cn.iocoder.yudao.module.promotion.mq.message;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/producer/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的生产者
  3 + */
  4 +package cn.iocoder.yudao.module.promotion.mq.producer;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
... ... @@ -108,8 +108,8 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
108 108 }
109 109  
110 110 // 2. 校验商品 sku 都存在
111   - Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
112   - ProductSkuRespDTO::getId);
  111 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(singletonList(spuId));
  112 + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
113 113 products.forEach(product -> {
114 114 if (!skuMap.containsKey(product.getSkuId())) {
115 115 throw exception(SKU_NOT_EXISTS);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
... ... @@ -22,15 +22,6 @@ import java.util.Map;
22 22 public interface CombinationRecordService {
23 23  
24 24 /**
25   - * 更新拼团状态
26   - *
27   - * @param status 状态
28   - * @param userId 用户编号
29   - * @param orderId 订单编号
30   - */
31   - void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);
32   -
33   - /**
34 25 * 【下单前】校验是否满足拼团活动条件
35 26 *
36 27 * 如果校验失败,则抛出业务异常
... ... @@ -63,15 +54,6 @@ public interface CombinationRecordService {
63 54 CombinationRecordDO getCombinationRecord(Long userId, Long orderId);
64 55  
65 56 /**
66   - * 获取拼团记录
67   - *
68   - * @param userId 用户 id
69   - * @param activityId 活动 id
70   - * @return 拼团记录列表
71   - */
72   - List<CombinationRecordDO> getCombinationRecordListByUserIdAndActivityId(Long userId, Long activityId);
73   -
74   - /**
75 57 * 【下单前】校验是否满足拼团活动条件
76 58 *
77 59 * 如果校验失败,则抛出业务异常
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
... ... @@ -24,6 +24,7 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecord
24 24 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
25 25 import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
26 26 import lombok.extern.slf4j.Slf4j;
  27 +import org.springframework.context.annotation.Lazy;
27 28 import org.springframework.stereotype.Service;
28 29 import org.springframework.transaction.annotation.Transactional;
29 30 import org.springframework.validation.annotation.Validated;
... ... @@ -64,27 +65,9 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
64 65 private ProductSkuApi productSkuApi;
65 66  
66 67 @Resource
  68 + @Lazy
67 69 private TradeOrderApi tradeOrderApi;
68 70  
69   - @Override
70   - @Transactional(rollbackFor = Exception.class)
71   - public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
72   - // 校验拼团是否存在
73   - CombinationRecordDO record = validateCombinationRecord(userId, orderId);
74   -
75   - // 更新状态
76   - combinationRecordMapper.updateById(new CombinationRecordDO().setId(record.getId()).setStatus(status));
77   - }
78   -
79   - private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
80   - // 校验拼团是否存在
81   - CombinationRecordDO recordDO = combinationRecordMapper.selectByUserIdAndOrderId(userId, orderId);
82   - if (recordDO == null) {
83   - throw exception(COMBINATION_RECORD_NOT_EXISTS);
84   - }
85   - return recordDO;
86   - }
87   -
88 71 // TODO @芋艿:在详细预览下;
89 72 @Override
90 73 public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(
... ... @@ -230,11 +213,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
230 213 }
231 214  
232 215 @Override
233   - public List<CombinationRecordDO> getCombinationRecordListByUserIdAndActivityId(Long userId, Long activityId) {
234   - return combinationRecordMapper.selectListByUserIdAndActivityId(userId, activityId);
235   - }
236   -
237   - @Override
238 216 public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId,
239 217 Long skuId, Integer count) {
240 218 KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(userId, activityId,
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
... ... @@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil;
7 7 import cn.hutool.core.util.StrUtil;
8 8 import cn.hutool.extra.spring.SpringUtil;
9 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
11 10 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
12 11 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
13 12 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
... ... @@ -80,12 +79,11 @@ public class CouponServiceImpl implements CouponService {
80 79 public PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO) {
81 80 // 获得用户编号
82 81 if (StrUtil.isNotEmpty(pageReqVO.getNickname())) {
83   - Set<Long> userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageReqVO.getNickname()),
84   - MemberUserRespDTO::getId);
85   - if (CollUtil.isEmpty(userIds)) {
  82 + List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
  83 + if (CollUtil.isEmpty(users)) {
86 84 return PageResult.empty();
87 85 }
88   - pageReqVO.setUserIds(userIds);
  86 + pageReqVO.setUserIds(convertSet(users, MemberUserRespDTO::getId));
89 87 }
90 88 // 分页查询
91 89 return couponMapper.selectPage(pageReqVO);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceService.java deleted
1   -package cn.iocoder.yudao.module.promotion.service.price;
2   -
3   -import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
4   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
5   -
6   -import java.util.List;
7   -
8   -/**
9   - * 价格计算 Service 接口
10   - *
11   - * @author 芋道源码
12   - */
13   -public interface PriceService {
14   -
15   - /**
16   - * 获得优惠劵的匹配信息列表
17   - *
18   - * @param calculateReqDTO 价格请求
19   - * @return 价格响应
20   - */
21   - List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO);
22   -
23   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java deleted
1   -package cn.iocoder.yudao.module.promotion.service.price;
2   -
3   -import cn.hutool.core.collection.CollUtil;
4   -import cn.iocoder.yudao.framework.common.exception.ServiceException;
5   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6   -import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
7   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
8   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
9   -import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert;
10   -import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
11   -import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
12   -import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
13   -import lombok.extern.slf4j.Slf4j;
14   -import org.springframework.stereotype.Service;
15   -import org.springframework.validation.annotation.Validated;
16   -
17   -import javax.annotation.Resource;
18   -import java.util.Collections;
19   -import java.util.List;
20   -
21   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
22   -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW;
23   -
24   -/**
25   - * 价格计算 Service 实现类
26   - *
27   - * 优惠计算顺序:min(限时折扣, 会员折扣) > 满减送 > 优惠券。
28   - * 参考文档:
29   - * 1. <a href="https://help.youzan.com/displaylist/detail_4_4-1-60384">有赞文档:限时折扣、满减送、优惠券哪个优先计算?</a>
30   - *
31   - * TODO 芋艿:进一步完善
32   - * 1. 限时折扣:指定金额、减免金额、折扣
33   - * 2. 满减送:循环、折扣
34   - * 3. 优惠劵:待定
35   - *
36   - * @author 芋道源码
37   - */
38   -@Service
39   -@Validated
40   -@Slf4j
41   -public class PriceServiceImpl implements PriceService {
42   -
43   - @Resource
44   - private CouponService couponService;
45   -
46   - @Override
47   - public List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO) {
48   - // 先计算一轮价格
49   -// PriceCalculateRespDTO priceCalculate = calculatePrice(calculateReqDTO);
50   - PriceCalculateRespDTO priceCalculate = null;
51   -
52   - // 获得用户的待使用优惠劵
53   - List<CouponDO> couponList = couponService.getCouponList(calculateReqDTO.getUserId(), CouponStatusEnum.UNUSED.getStatus());
54   - if (CollUtil.isEmpty(couponList)) {
55   - return Collections.emptyList();
56   - }
57   -
58   - // 获得优惠劵的匹配信息
59   - return CollectionUtils.convertList(couponList, coupon -> {
60   - CouponMeetRespDTO couponMeetRespDTO = PriceConvert.INSTANCE.convert(coupon);
61   - try {
62   - // 校验优惠劵
63   - couponService.validCoupon(coupon);
64   -
65   - // 获得匹配的商品 SKU 数组
66   - // TODO 芋艿:后续处理
67   -// List<PriceCalculateRespDTO.OrderItem> orderItems = getMatchCouponOrderItems(priceCalculate, coupon);
68   - List<PriceCalculateRespDTO.OrderItem> orderItems = null;
69   - if (CollUtil.isEmpty(orderItems)) {
70   - return couponMeetRespDTO.setMeet(false).setMeetTip("所结算商品没有符合条件的商品");
71   - }
72   -
73   - // 计算是否满足优惠劵的使用金额
74   - Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);
75   - assert originPrice != null;
76   - if (originPrice < coupon.getUsePrice()) {
77   - return couponMeetRespDTO.setMeet(false)
78   -// .setMeetTip(String.format("差 %s 元可用优惠劵", formatPrice(coupon.getUsePrice() - originPrice)));
79   - .setMeetTip("所结算的商品中未满足使用的金额");
80   - }
81   - } catch (ServiceException serviceException) {
82   - couponMeetRespDTO.setMeet(false);
83   - if (serviceException.getCode().equals(COUPON_VALID_TIME_NOT_NOW.getCode())) {
84   - couponMeetRespDTO.setMeetTip("优惠劵未到使用时间");
85   - } else {
86   - log.error("[getMeetCouponList][calculateReqDTO({}) 获得优惠劵匹配信息异常]", calculateReqDTO, serviceException);
87   - couponMeetRespDTO.setMeetTip("优惠劵不满足使用条件");
88   - }
89   - return couponMeetRespDTO;
90   - }
91   - // 满足
92   - return couponMeetRespDTO.setMeet(true);
93   - });
94   - }
95   -
96   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
... ... @@ -123,8 +123,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
123 123 }
124 124  
125 125 // 2. 校验商品 sku 都存在
126   - Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
127   - ProductSkuRespDTO::getId);
  126 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(singletonList(spuId));
  127 + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
128 128 products.forEach(product -> {
129 129 if (!skuMap.containsKey(product.getSkuId())) {
130 130 throw exception(SKU_NOT_EXISTS);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java
... ... @@ -138,7 +138,7 @@ public class DiscountActivityServiceImplTest extends BaseDbUnitTest {
138 138 Long id = dbDiscountActivity.getId();
139 139  
140 140 // 调用
141   - discountActivityService.closeRewardActivity(id);
  141 + discountActivityService.closeDiscountActivity(id);
142 142 // 校验状态
143 143 DiscountActivityDO discountActivity = discountActivityMapper.selectById(id);
144 144 assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus());
... ...
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java deleted
1   -package cn.iocoder.yudao.module.promotion.service.price;
2   -
3   -import cn.iocoder.yudao.framework.common.exception.ServiceException;
4   -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
5   -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
6   -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
7   -import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
8   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
9   -import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
10   -import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
11   -import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
12   -import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
13   -import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
14   -import org.junit.jupiter.api.Test;
15   -import org.mockito.InjectMocks;
16   -import org.mockito.Mock;
17   -
18   -import java.util.List;
19   -
20   -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
21   -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
22   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
23   -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW;
24   -import static java.util.Arrays.asList;
25   -import static java.util.Collections.singletonList;
26   -import static org.junit.jupiter.api.Assertions.*;
27   -import static org.mockito.ArgumentMatchers.eq;
28   -import static org.mockito.Mockito.doThrow;
29   -import static org.mockito.Mockito.when;
30   -
31   -/**
32   - * {@link PriceServiceImpl} 的单元测试
33   - *
34   - * @author 芋道源码
35   - */
36   -public class PriceServiceTest extends BaseMockitoUnitTest {
37   -
38   - @InjectMocks
39   - private PriceServiceImpl priceService;
40   -
41   - @Mock
42   - private RewardActivityService rewardActivityService;
43   - @Mock
44   - private CouponService couponService;
45   - @Mock
46   - private ProductSkuApi productSkuApi;
47   -
48   - /**
49   - * 测试满减送活动,不匹配的情况
50   - */
51   - @Test
52   - public void testCalculatePrice_rewardActivityNotMeet() {
53   -
54   - }
55   -
56   - @Test
57   - public void testGetMeetCouponList() {
58   - // 准备参数
59   - PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(1024L)
60   - .setItems(singletonList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2)));
61   - // mock 方法(商品 SKU 信息)
62   - ProductSkuRespDTO productSku = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100));
63   - when(productSkuApi.getSkuList(eq(asSet(10L)))).thenReturn(singletonList(productSku));
64   - // mock 方法(情况一:优惠劵未到使用时间)
65   - CouponDO coupon01 = randomPojo(CouponDO.class);
66   - doThrow(new ServiceException(COUPON_VALID_TIME_NOT_NOW)).when(couponService).validCoupon(coupon01);
67   - // mock 方法(情况二:所结算商品没有符合条件的商品)
68   - CouponDO coupon02 = randomPojo(CouponDO.class);
69   - // mock 方法(情况三:使用金额不足)
70   - CouponDO coupon03 = randomPojo(CouponDO.class, o -> o.setProductScope(PromotionProductScopeEnum.ALL.getScope())
71   - .setUsePrice(300));
72   - // mock 方法(情况五:满足条件)
73   - CouponDO coupon04 = randomPojo(CouponDO.class, o -> o.setProductScope(PromotionProductScopeEnum.ALL.getScope())
74   - .setUsePrice(190));
75   - // mock 方法(获得用户的待使用优惠劵)
76   - when(couponService.getCouponList(eq(1024L), eq(CouponStatusEnum.UNUSED.getStatus())))
77   - .thenReturn(asList(coupon01, coupon02, coupon03, coupon04));
78   - // 调用
79   - List<CouponMeetRespDTO> list = priceService.getMeetCouponList(calculateReqDTO);
80   - // 断言
81   - assertEquals(list.size(), 4);
82   - // 断言情况一:优惠劵未到使用时间
83   - CouponMeetRespDTO couponMeetRespDTO01 = list.get(0);
84   - assertPojoEquals(couponMeetRespDTO01, coupon01);
85   - assertFalse(couponMeetRespDTO01.getMeet());
86   - assertEquals(couponMeetRespDTO01.getMeetTip(), "优惠劵未到使用时间");
87   - // 断言情况二:所结算商品没有符合条件的商品
88   - CouponMeetRespDTO couponMeetRespDTO02 = list.get(1);
89   - assertPojoEquals(couponMeetRespDTO02, coupon02);
90   - assertFalse(couponMeetRespDTO02.getMeet());
91   - assertEquals(couponMeetRespDTO02.getMeetTip(), "所结算商品没有符合条件的商品");
92   - // 断言情况三:差 %s 元可用优惠劵
93   - CouponMeetRespDTO couponMeetRespDTO03 = list.get(2);
94   - assertPojoEquals(couponMeetRespDTO03, coupon03);
95   - assertFalse(couponMeetRespDTO03.getMeet());
96   - assertEquals(couponMeetRespDTO03.getMeetTip(), "所结算的商品中未满足使用的金额");
97   - // 断言情况四:满足条件
98   - CouponMeetRespDTO couponMeetRespDTO04 = list.get(3);
99   - assertPojoEquals(couponMeetRespDTO04, coupon04);
100   - assertTrue(couponMeetRespDTO04.getMeet());
101   - assertNull(couponMeetRespDTO04.getMeetTip());
102   - }
103   -
104   -}
yudao-module-mall/yudao-module-statistics-biz/pom.xml
... ... @@ -58,7 +58,6 @@
58 58 <groupId>cn.iocoder.boot</groupId>
59 59 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
60 60 </dependency>
61   -
62 61 <dependency>
63 62 <groupId>cn.iocoder.boot</groupId>
64 63 <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
... ...
yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/member/MemberStatisticsDO.java
1 1 package cn.iocoder.yudao.module.statistics.dal.dataobject.member;
2 2  
3   -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import com.baomidou.mybatisplus.annotation.KeySequence;
5 5 import com.baomidou.mybatisplus.annotation.TableId;
6 6 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -23,7 +23,7 @@ import java.time.LocalDateTime;
23 23 @Builder
24 24 @NoArgsConstructor
25 25 @AllArgsConstructor
26   -public class MemberStatisticsDO extends TenantBaseDO {
  26 +public class MemberStatisticsDO extends BaseDO {
27 27  
28 28 /**
29 29 * 编号,主键自增
... ...
yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/trade/TradeStatisticsDO.java
1 1 package cn.iocoder.yudao.module.statistics.dal.dataobject.trade;
2 2  
3   -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import com.baomidou.mybatisplus.annotation.KeySequence;
5 5 import com.baomidou.mybatisplus.annotation.TableId;
6 6 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -23,7 +23,7 @@ import java.time.LocalDateTime;
23 23 @Builder
24 24 @NoArgsConstructor
25 25 @AllArgsConstructor
26   -public class TradeStatisticsDO extends TenantBaseDO {
  26 +public class TradeStatisticsDO extends BaseDO {
27 27  
28 28 /**
29 29 * 编号,主键自增
... ...
yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsServiceImpl.java
1 1 package cn.iocoder.yudao.module.statistics.service.pay;
2 2  
3   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  3 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
4 4 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
5 5 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
6 6 import cn.iocoder.yudao.module.statistics.dal.mysql.pay.PayWalletStatisticsMapper;
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java
... ... @@ -77,6 +77,7 @@ public class BrokerageUserController {
77 77 @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
78 78 public CommonResult<BrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) {
79 79 BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id);
  80 + // TODO @疯狂:是不是搞成一个统一的 convert?
80 81 BrokerageUserRespVO respVO = BrokerageUserConvert.INSTANCE.convert(brokerageUser);
81 82 return success(BrokerageUserConvert.INSTANCE.copyTo(memberUserApi.getUser(id), respVO));
82 83 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 7 import cn.iocoder.yudao.framework.common.util.string.StrUtils;
8 8 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
9 9 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
10   -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  10 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
11 11 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
12 12 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
13 13 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
... ... @@ -241,7 +241,7 @@ public interface TradeOrderConvert {
241 241 return reqBO;
242 242 }
243 243  
244   - default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, AddressRespDTO address) {
  244 + default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address) {
245 245 AppTradeOrderSettlementRespVO respVO = convert0(calculate, address);
246 246 if (address != null) {
247 247 respVO.getAddress().setAreaName(AreaUtils.format(address.getAreaId()));
... ... @@ -249,7 +249,7 @@ public interface TradeOrderConvert {
249 249 return respVO;
250 250 }
251 251  
252   - AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
  252 + AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address);
253 253  
254 254 List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
255 255  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java
... ... @@ -232,7 +232,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
232 232 return PageResult.empty();
233 233 }
234 234 // 1.2 根据昵称过滤下级用户
235   - Map<Long, MemberUserRespDTO> userMap = convertMapByFilter(memberUserApi.getUserList(childIds),
  235 + List<MemberUserRespDTO> users = memberUserApi.getUserList(childIds);
  236 + Map<Long, MemberUserRespDTO> userMap = convertMapByFilter(users,
236 237 user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()),
237 238 MemberUserRespDTO::getId);
238 239 if (CollUtil.isEmpty(userMap)) {
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
... ... @@ -11,8 +11,8 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
11 11 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
12 12 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
13 13 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
14   -import cn.iocoder.yudao.module.member.api.address.AddressApi;
15   -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  14 +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
  15 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
16 16 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
17 17 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
18 18 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
... ... @@ -98,7 +98,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
98 98 @Resource
99 99 private PayOrderApi payOrderApi;
100 100 @Resource
101   - private AddressApi addressApi;
  101 + private MemberAddressApi addressApi;
102 102 @Resource
103 103 private ProductCommentApi productCommentApi;
104 104  
... ... @@ -110,7 +110,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
110 110 @Override
111 111 public AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) {
112 112 // 1. 获得收货地址
113   - AddressRespDTO address = getAddress(userId, settlementReqVO.getAddressId());
  113 + MemberAddressRespDTO address = getAddress(userId, settlementReqVO.getAddressId());
114 114 if (address != null) {
115 115 settlementReqVO.setAddressId(address.getId());
116 116 }
... ... @@ -129,7 +129,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
129 129 * @param addressId 地址编号
130 130 * @return 地址
131 131 */
132   - private AddressRespDTO getAddress(Long userId, Long addressId) {
  132 + private MemberAddressRespDTO getAddress(Long userId, Long addressId) {
133 133 if (addressId != null) {
134 134 return addressApi.getAddress(addressId, userId);
135 135 }
... ... @@ -193,7 +193,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
193 193 // 物流信息
194 194 order.setDeliveryType(createReqVO.getDeliveryType());
195 195 if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
196   - AddressRespDTO address = addressApi.getAddress(createReqVO.getAddressId(), userId);
  196 + MemberAddressRespDTO address = addressApi.getAddress(createReqVO.getAddressId(), userId);
197 197 Assert.notNull(address, "地址({}) 不能为空", createReqVO.getAddressId()); // 价格计算时,已经计算
198 198 order.setReceiverName(address.getName()).setReceiverMobile(address.getMobile())
199 199 .setReceiverAreaId(address.getAreaId()).setReceiverDetailAddress(address.getDetailAddress());
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
... ... @@ -4,8 +4,8 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.lang.Assert;
5 5 import cn.hutool.core.util.StrUtil;
6 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7   -import cn.iocoder.yudao.module.member.api.address.AddressApi;
8   -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  7 +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
  8 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
9 9 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
10 10 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
11 11 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
... ... @@ -41,7 +41,7 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
41 41 public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
42 42  
43 43 @Resource
44   - private AddressApi addressApi;
  44 + private MemberAddressApi addressApi;
45 45  
46 46 @Resource
47 47 private DeliveryPickUpStoreService deliveryPickUpStoreService;
... ... @@ -81,7 +81,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
81 81 // 价格计算时,如果为空就不算~最终下单,会校验该字段不允许空
82 82 return;
83 83 }
84   - AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
  84 + MemberAddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
85 85 Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
86 86  
87 87 // 情况一:全局包邮
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java
1 1 package cn.iocoder.yudao.module.trade.service.order;
2 2  
3   -import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
4 3 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5   -import cn.iocoder.yudao.module.member.api.address.AddressApi;
6   -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  4 +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
7 5 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
8 6 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
9 7 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
10 8 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
11   -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
12 9 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
13   -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
14 10 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
15   -import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
16   -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
17 11 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
18   -import cn.iocoder.yudao.module.promotion.api.price.PriceApi;
19   -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
20 12 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
21   -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
22 13 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
23   -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
24 14 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
25 15 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
26   -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
27   -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
28 16 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
29   -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
30 17 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
31 18 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
32 19 import org.junit.jupiter.api.BeforeEach;
... ... @@ -36,17 +23,11 @@ import org.springframework.context.annotation.Import;
36 23  
37 24 import javax.annotation.Resource;
38 25 import java.time.Duration;
39   -import java.util.Arrays;
40   -import java.util.List;
41 26  
42   -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
43 27 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
44 28 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
45   -import static java.util.Collections.singletonList;
46 29 import static org.junit.jupiter.api.Assertions.*;
47   -import static org.mockito.ArgumentMatchers.argThat;
48 30 import static org.mockito.ArgumentMatchers.eq;
49   -import static org.mockito.Mockito.verify;
50 31 import static org.mockito.Mockito.when;
51 32  
52 33 /**
... ... @@ -72,12 +53,12 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
72 53 private ProductSpuApi productSpuApi;
73 54 @MockBean
74 55 private ProductSkuApi productSkuApi;
75   - @MockBean
76   - private PriceApi priceApi;
  56 +// @MockBean
  57 +// private PriceApi priceApi;
77 58 @MockBean
78 59 private PayOrderApi payOrderApi;
79 60 @MockBean
80   - private AddressApi addressApi;
  61 + private MemberAddressApi addressApi;
81 62 @MockBean
82 63 private CouponApi couponApi;
83 64  
... ... @@ -90,159 +71,159 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
90 71 when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1));
91 72 }
92 73  
93   - @Test
94   - public void testCreateTradeOrder_success() {
95   - // 准备参数
96   - Long userId = 100L;
97   - String userIp = "127.0.0.1";
98   -// AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO()
99   -// .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true)
100   -// .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3),
101   -// new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4)));
102   - AppTradeOrderCreateReqVO reqVO = null;
103   - // TODO 芋艿:重新高下
104   - // mock 方法(商品 SKU 检查)
105   - ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L)
106   - .setPrice(50).setStock(100)
107   - .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(111L).setValueId(222L))));
108   - ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L)
109   - .setPrice(20).setStock(50))
110   - .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(333L).setValueId(444L)));
111   - when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02));
112   - // mock 方法(商品 SPU 检查)
113   - ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L)
114   - .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()).setName("商品 1"));
115   - ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L)
116   - .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));
117   - when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02));
118   - // mock 方法(用户收件地址的校验)
119   - AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿")
120   - .setMobile("15601691300").setAreaId(3306).setDetailAddress("土豆村");
121   - when(addressApi.getAddress(eq(10L), eq(userId))).thenReturn(addressRespDTO);
122   - // mock 方法(价格计算)
123   - PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem()
124   - .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50)
125   - .setDiscountPrice(20).setPayPrice(130).setOrderPartPrice(7).setOrderDividePrice(35);
126   - PriceCalculateRespDTO.OrderItem priceOrderItem02 = new PriceCalculateRespDTO.OrderItem()
127   - .setSpuId(21L).setSkuId(2L).setCount(4).setOriginalPrice(80).setOriginalUnitPrice(20)
128   - .setDiscountPrice(40).setPayPrice(40).setOrderPartPrice(15).setOrderDividePrice(25);
129   - PriceCalculateRespDTO.Order priceOrder = new PriceCalculateRespDTO.Order()
130   - .setTotalPrice(230).setDiscountPrice(0).setCouponPrice(30)
131   - .setPointPrice(10).setDeliveryPrice(20).setPayPrice(80).setCouponId(101L).setCouponPrice(30)
132   - .setItems(Arrays.asList(priceOrderItem01, priceOrderItem02));
133   - when(priceApi.calculatePrice(argThat(priceCalculateReqDTO -> {
134   - assertEquals(priceCalculateReqDTO.getUserId(), 100L);
135   - assertEquals(priceCalculateReqDTO.getCouponId(), 101L);
136   - assertEquals(priceCalculateReqDTO.getItems().get(0).getSkuId(), 1L);
137   - assertEquals(priceCalculateReqDTO.getItems().get(0).getCount(), 3);
138   - assertEquals(priceCalculateReqDTO.getItems().get(1).getSkuId(), 2L);
139   - assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4);
140   - return true;
141   - }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder));
142   - // mock 方法(创建支付单)
143   - when(payOrderApi.createOrder(argThat(createReqDTO -> {
144   - assertEquals(createReqDTO.getAppId(), 888L);
145   - assertEquals(createReqDTO.getUserIp(), userIp);
146   - assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空
147   - assertEquals(createReqDTO.getSubject(), "商品 1 等多件");
148   - assertNull(createReqDTO.getBody());
149   - assertEquals(createReqDTO.getPrice(), 80);
150   - assertNotNull(createReqDTO.getExpireTime());
151   - return true;
152   - }))).thenReturn(1000L);
153   -
154   - // 调用方法
155   - TradeOrderDO order = tradeOrderUpdateService.createOrder(userId, userIp, reqVO, null);
156   - // 断言 TradeOrderDO 订单
157   - List<TradeOrderDO> tradeOrderDOs = tradeOrderMapper.selectList();
158   - assertEquals(tradeOrderDOs.size(), 1);
159   - TradeOrderDO tradeOrderDO = tradeOrderDOs.get(0);
160   - assertEquals(tradeOrderDO.getId(), order.getId());
161   - assertNotNull(tradeOrderDO.getNo());
162   - assertEquals(tradeOrderDO.getType(), TradeOrderTypeEnum.NORMAL.getType());
163   - assertEquals(tradeOrderDO.getTerminal(), TerminalEnum.H5.getTerminal());
164   - assertEquals(tradeOrderDO.getUserId(), userId);
165   - assertEquals(tradeOrderDO.getUserIp(), userIp);
166   - assertEquals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus());
167   - assertEquals(tradeOrderDO.getProductCount(), 7);
168   - assertNull(tradeOrderDO.getFinishTime());
169   - assertNull(tradeOrderDO.getCancelTime());
170   - assertNull(tradeOrderDO.getCancelType());
171   - assertEquals(tradeOrderDO.getUserRemark(), "我是备注");
172   - assertNull(tradeOrderDO.getRemark());
173   - assertFalse(tradeOrderDO.getPayStatus());
174   - assertNull(tradeOrderDO.getPayTime());
175   - assertEquals(tradeOrderDO.getTotalPrice(), 230);
176   - assertEquals(tradeOrderDO.getDiscountPrice(), 0);
177   - assertEquals(tradeOrderDO.getAdjustPrice(), 0);
178   - assertEquals(tradeOrderDO.getPayPrice(), 80);
179   - assertEquals(tradeOrderDO.getPayOrderId(), 1000L);
180   - assertNull(tradeOrderDO.getPayChannelCode());
181   - assertNull(tradeOrderDO.getLogisticsId());
182   - assertNull(tradeOrderDO.getDeliveryTime());
183   - assertNull(tradeOrderDO.getReceiveTime());
184   - assertEquals(tradeOrderDO.getReceiverName(), "芋艿");
185   - assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300");
186   - assertEquals(tradeOrderDO.getReceiverAreaId(), 3306);
187   - assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");
188   - assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus());
189   - assertEquals(tradeOrderDO.getRefundPrice(), 0);
190   - assertEquals(tradeOrderDO.getCouponPrice(), 30);
191   - assertEquals(tradeOrderDO.getPointPrice(), 10);
192   - // 断言 TradeOrderItemDO 订单(第 1 个)
193   - List<TradeOrderItemDO> tradeOrderItemDOs = tradeOrderItemMapper.selectList();
194   - assertEquals(tradeOrderItemDOs.size(), 2);
195   - TradeOrderItemDO tradeOrderItemDO01 = tradeOrderItemDOs.get(0);
196   - assertNotNull(tradeOrderItemDO01.getId());
197   - assertEquals(tradeOrderItemDO01.getUserId(), userId);
198   - assertEquals(tradeOrderItemDO01.getOrderId(), order.getId());
199   - assertEquals(tradeOrderItemDO01.getSpuId(), 11L);
200   - assertEquals(tradeOrderItemDO01.getSkuId(), 1L);
201   - assertEquals(tradeOrderItemDO01.getProperties().size(), 1);
202   - assertEquals(tradeOrderItemDO01.getProperties().get(0).getPropertyId(), 111L);
203   - assertEquals(tradeOrderItemDO01.getProperties().get(0).getValueId(), 222L);
204   - //assertEquals(tradeOrderItemDO01.getSpuName(), sku01.getSpuName()); TODO 找不到spuName
205   - assertEquals(tradeOrderItemDO01.getPicUrl(), sku01.getPicUrl());
206   - assertEquals(tradeOrderItemDO01.getCount(), 3);
207   -// assertEquals(tradeOrderItemDO01.getOriginalPrice(), 150);
208   - assertEquals(tradeOrderItemDO01.getPrice(), 50);
209   - assertEquals(tradeOrderItemDO01.getDiscountPrice(), 20);
210   - assertEquals(tradeOrderItemDO01.getPayPrice(), 130);
211   - assertEquals(tradeOrderItemDO01.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
212   - // 断言 TradeOrderItemDO 订单(第 2 个)
213   - TradeOrderItemDO tradeOrderItemDO02 = tradeOrderItemDOs.get(1);
214   - assertNotNull(tradeOrderItemDO02.getId());
215   - assertEquals(tradeOrderItemDO02.getUserId(), userId);
216   - assertEquals(tradeOrderItemDO02.getOrderId(), order.getId());
217   - assertEquals(tradeOrderItemDO02.getSpuId(), 21L);
218   - assertEquals(tradeOrderItemDO02.getSkuId(), 2L);
219   - assertEquals(tradeOrderItemDO02.getProperties().size(), 1);
220   - assertEquals(tradeOrderItemDO02.getProperties().get(0).getPropertyId(), 333L);
221   - assertEquals(tradeOrderItemDO02.getProperties().get(0).getValueId(), 444L);
222   - //assertEquals(tradeOrderItemDO02.getSpuName(), sku02.getSpuName()); TODO 找不到spuName
223   - assertEquals(tradeOrderItemDO02.getPicUrl(), sku02.getPicUrl());
224   - assertEquals(tradeOrderItemDO02.getCount(), 4);
225   -// assertEquals(tradeOrderItemDO02.getOriginalPrice(), 80);
226   - assertEquals(tradeOrderItemDO02.getPrice(), 20);
227   - assertEquals(tradeOrderItemDO02.getDiscountPrice(), 40);
228   - assertEquals(tradeOrderItemDO02.getPayPrice(), 40);
229   - assertEquals(tradeOrderItemDO02.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
230   - // 校验调用
231   - verify(productSkuApi).updateSkuStock(argThat(updateStockReqDTO -> {
232   - assertEquals(updateStockReqDTO.getItems().size(), 2);
233   - assertEquals(updateStockReqDTO.getItems().get(0).getId(), 1L);
234   - assertEquals(updateStockReqDTO.getItems().get(0).getIncrCount(), 3);
235   - assertEquals(updateStockReqDTO.getItems().get(1).getId(), 2L);
236   - assertEquals(updateStockReqDTO.getItems().get(1).getIncrCount(), 4);
237   - return true;
238   - }));
239   - verify(couponApi).useCoupon(argThat(reqDTO -> {
240   - assertEquals(reqDTO.getId(), reqVO.getCouponId());
241   - assertEquals(reqDTO.getUserId(), userId);
242   - assertEquals(reqDTO.getOrderId(), order.getId());
243   - return true;
244   - }));
245   - }
  74 +// @Test
  75 +// public void testCreateTradeOrder_success() {
  76 +// // 准备参数
  77 +// Long userId = 100L;
  78 +// String userIp = "127.0.0.1";
  79 +//// AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO()
  80 +//// .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true)
  81 +//// .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3),
  82 +//// new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4)));
  83 +// AppTradeOrderCreateReqVO reqVO = null;
  84 +// // TODO 芋艿:重新高下
  85 +// // mock 方法(商品 SKU 检查)
  86 +// ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L)
  87 +// .setPrice(50).setStock(100)
  88 +// .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(111L).setValueId(222L))));
  89 +// ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L)
  90 +// .setPrice(20).setStock(50))
  91 +// .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(333L).setValueId(444L)));
  92 +// when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02));
  93 +// // mock 方法(商品 SPU 检查)
  94 +// ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L)
  95 +// .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()).setName("商品 1"));
  96 +// ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L)
  97 +// .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));
  98 +// when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02));
  99 +// // mock 方法(用户收件地址的校验)
  100 +// MemberAddressRespDTO addressRespDTO = new MemberAddressRespDTO().setId(10L).setUserId(userId).setName("芋艿")
  101 +// .setMobile("15601691300").setAreaId(3306).setDetailAddress("土豆村");
  102 +// when(addressApi.getAddress(eq(10L), eq(userId))).thenReturn(addressRespDTO);
  103 +// // mock 方法(价格计算)
  104 +// PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem()
  105 +// .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50)
  106 +// .setDiscountPrice(20).setPayPrice(130).setOrderPartPrice(7).setOrderDividePrice(35);
  107 +// PriceCalculateRespDTO.OrderItem priceOrderItem02 = new PriceCalculateRespDTO.OrderItem()
  108 +// .setSpuId(21L).setSkuId(2L).setCount(4).setOriginalPrice(80).setOriginalUnitPrice(20)
  109 +// .setDiscountPrice(40).setPayPrice(40).setOrderPartPrice(15).setOrderDividePrice(25);
  110 +// PriceCalculateRespDTO.Order priceOrder = new PriceCalculateRespDTO.Order()
  111 +// .setTotalPrice(230).setDiscountPrice(0).setCouponPrice(30)
  112 +// .setPointPrice(10).setDeliveryPrice(20).setPayPrice(80).setCouponId(101L).setCouponPrice(30)
  113 +// .setItems(Arrays.asList(priceOrderItem01, priceOrderItem02));
  114 +// when(priceApi.calculatePrice(argThat(priceCalculateReqDTO -> {
  115 +// assertEquals(priceCalculateReqDTO.getUserId(), 100L);
  116 +// assertEquals(priceCalculateReqDTO.getCouponId(), 101L);
  117 +// assertEquals(priceCalculateReqDTO.getItems().get(0).getSkuId(), 1L);
  118 +// assertEquals(priceCalculateReqDTO.getItems().get(0).getCount(), 3);
  119 +// assertEquals(priceCalculateReqDTO.getItems().get(1).getSkuId(), 2L);
  120 +// assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4);
  121 +// return true;
  122 +// }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder));
  123 +// // mock 方法(创建支付单)
  124 +// when(payOrderApi.createOrder(argThat(createReqDTO -> {
  125 +// assertEquals(createReqDTO.getAppId(), 888L);
  126 +// assertEquals(createReqDTO.getUserIp(), userIp);
  127 +// assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空
  128 +// assertEquals(createReqDTO.getSubject(), "商品 1 等多件");
  129 +// assertNull(createReqDTO.getBody());
  130 +// assertEquals(createReqDTO.getPrice(), 80);
  131 +// assertNotNull(createReqDTO.getExpireTime());
  132 +// return true;
  133 +// }))).thenReturn(1000L);
  134 +//
  135 +// // 调用方法
  136 +// TradeOrderDO order = tradeOrderUpdateService.createOrder(userId, userIp, reqVO, null);
  137 +// // 断言 TradeOrderDO 订单
  138 +// List<TradeOrderDO> tradeOrderDOs = tradeOrderMapper.selectList();
  139 +// assertEquals(tradeOrderDOs.size(), 1);
  140 +// TradeOrderDO tradeOrderDO = tradeOrderDOs.get(0);
  141 +// assertEquals(tradeOrderDO.getId(), order.getId());
  142 +// assertNotNull(tradeOrderDO.getNo());
  143 +// assertEquals(tradeOrderDO.getType(), TradeOrderTypeEnum.NORMAL.getType());
  144 +// assertEquals(tradeOrderDO.getTerminal(), TerminalEnum.H5.getTerminal());
  145 +// assertEquals(tradeOrderDO.getUserId(), userId);
  146 +// assertEquals(tradeOrderDO.getUserIp(), userIp);
  147 +// assertEquals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus());
  148 +// assertEquals(tradeOrderDO.getProductCount(), 7);
  149 +// assertNull(tradeOrderDO.getFinishTime());
  150 +// assertNull(tradeOrderDO.getCancelTime());
  151 +// assertNull(tradeOrderDO.getCancelType());
  152 +// assertEquals(tradeOrderDO.getUserRemark(), "我是备注");
  153 +// assertNull(tradeOrderDO.getRemark());
  154 +// assertFalse(tradeOrderDO.getPayStatus());
  155 +// assertNull(tradeOrderDO.getPayTime());
  156 +// assertEquals(tradeOrderDO.getTotalPrice(), 230);
  157 +// assertEquals(tradeOrderDO.getDiscountPrice(), 0);
  158 +// assertEquals(tradeOrderDO.getAdjustPrice(), 0);
  159 +// assertEquals(tradeOrderDO.getPayPrice(), 80);
  160 +// assertEquals(tradeOrderDO.getPayOrderId(), 1000L);
  161 +// assertNull(tradeOrderDO.getPayChannelCode());
  162 +// assertNull(tradeOrderDO.getLogisticsId());
  163 +// assertNull(tradeOrderDO.getDeliveryTime());
  164 +// assertNull(tradeOrderDO.getReceiveTime());
  165 +// assertEquals(tradeOrderDO.getReceiverName(), "芋艿");
  166 +// assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300");
  167 +// assertEquals(tradeOrderDO.getReceiverAreaId(), 3306);
  168 +// assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");
  169 +// assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus());
  170 +// assertEquals(tradeOrderDO.getRefundPrice(), 0);
  171 +// assertEquals(tradeOrderDO.getCouponPrice(), 30);
  172 +// assertEquals(tradeOrderDO.getPointPrice(), 10);
  173 +// // 断言 TradeOrderItemDO 订单(第 1 个)
  174 +// List<TradeOrderItemDO> tradeOrderItemDOs = tradeOrderItemMapper.selectList();
  175 +// assertEquals(tradeOrderItemDOs.size(), 2);
  176 +// TradeOrderItemDO tradeOrderItemDO01 = tradeOrderItemDOs.get(0);
  177 +// assertNotNull(tradeOrderItemDO01.getId());
  178 +// assertEquals(tradeOrderItemDO01.getUserId(), userId);
  179 +// assertEquals(tradeOrderItemDO01.getOrderId(), order.getId());
  180 +// assertEquals(tradeOrderItemDO01.getSpuId(), 11L);
  181 +// assertEquals(tradeOrderItemDO01.getSkuId(), 1L);
  182 +// assertEquals(tradeOrderItemDO01.getProperties().size(), 1);
  183 +// assertEquals(tradeOrderItemDO01.getProperties().get(0).getPropertyId(), 111L);
  184 +// assertEquals(tradeOrderItemDO01.getProperties().get(0).getValueId(), 222L);
  185 +// //assertEquals(tradeOrderItemDO01.getSpuName(), sku01.getSpuName()); TODO 找不到spuName
  186 +// assertEquals(tradeOrderItemDO01.getPicUrl(), sku01.getPicUrl());
  187 +// assertEquals(tradeOrderItemDO01.getCount(), 3);
  188 +//// assertEquals(tradeOrderItemDO01.getOriginalPrice(), 150);
  189 +// assertEquals(tradeOrderItemDO01.getPrice(), 50);
  190 +// assertEquals(tradeOrderItemDO01.getDiscountPrice(), 20);
  191 +// assertEquals(tradeOrderItemDO01.getPayPrice(), 130);
  192 +// assertEquals(tradeOrderItemDO01.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
  193 +// // 断言 TradeOrderItemDO 订单(第 2 个)
  194 +// TradeOrderItemDO tradeOrderItemDO02 = tradeOrderItemDOs.get(1);
  195 +// assertNotNull(tradeOrderItemDO02.getId());
  196 +// assertEquals(tradeOrderItemDO02.getUserId(), userId);
  197 +// assertEquals(tradeOrderItemDO02.getOrderId(), order.getId());
  198 +// assertEquals(tradeOrderItemDO02.getSpuId(), 21L);
  199 +// assertEquals(tradeOrderItemDO02.getSkuId(), 2L);
  200 +// assertEquals(tradeOrderItemDO02.getProperties().size(), 1);
  201 +// assertEquals(tradeOrderItemDO02.getProperties().get(0).getPropertyId(), 333L);
  202 +// assertEquals(tradeOrderItemDO02.getProperties().get(0).getValueId(), 444L);
  203 +// //assertEquals(tradeOrderItemDO02.getSpuName(), sku02.getSpuName()); TODO 找不到spuName
  204 +// assertEquals(tradeOrderItemDO02.getPicUrl(), sku02.getPicUrl());
  205 +// assertEquals(tradeOrderItemDO02.getCount(), 4);
  206 +//// assertEquals(tradeOrderItemDO02.getOriginalPrice(), 80);
  207 +// assertEquals(tradeOrderItemDO02.getPrice(), 20);
  208 +// assertEquals(tradeOrderItemDO02.getDiscountPrice(), 40);
  209 +// assertEquals(tradeOrderItemDO02.getPayPrice(), 40);
  210 +// assertEquals(tradeOrderItemDO02.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
  211 +// // 校验调用
  212 +// verify(productSkuApi).updateSkuStock(argThat(updateStockReqDTO -> {
  213 +// assertEquals(updateStockReqDTO.getItems().size(), 2);
  214 +// assertEquals(updateStockReqDTO.getItems().get(0).getId(), 1L);
  215 +// assertEquals(updateStockReqDTO.getItems().get(0).getIncrCount(), 3);
  216 +// assertEquals(updateStockReqDTO.getItems().get(1).getId(), 2L);
  217 +// assertEquals(updateStockReqDTO.getItems().get(1).getIncrCount(), 4);
  218 +// return true;
  219 +// }));
  220 +// verify(couponApi).useCoupon(argThat(reqDTO -> {
  221 +// assertEquals(reqDTO.getId(), reqVO.getCouponId());
  222 +// assertEquals(reqDTO.getUserId(), userId);
  223 +// assertEquals(reqDTO.getOrderId(), order.getId());
  224 +// return true;
  225 +// }));
  226 +// }
246 227  
247 228 @Test
248 229 public void testUpdateOrderPaid() {
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java
... ... @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
2 2  
3 3 import cn.hutool.core.map.MapUtil;
4 4 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
5   -import cn.iocoder.yudao.module.member.api.address.AddressApi;
6   -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  5 +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
  6 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
7 7 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
8 8 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
9 9 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
... ... @@ -38,7 +38,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
38 38 private TradeDeliveryPriceCalculator calculator;
39 39  
40 40 @Mock
41   - private AddressApi addressApi;
  41 + private MemberAddressApi addressApi;
42 42  
43 43 @Mock
44 44 private DeliveryExpressTemplateService deliveryExpressTemplateService;
... ... @@ -80,7 +80,7 @@ public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest {
80 80 TradePriceCalculatorHelper.recountAllPrice(resultBO);
81 81  
82 82 // 准备收件地址数据
83   - AddressRespDTO addressResp = randomPojo(AddressRespDTO.class, item -> item.setAreaId(10));
  83 + MemberAddressRespDTO addressResp = randomPojo(MemberAddressRespDTO.class, item -> item.setAreaId(10));
84 84 when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp);
85 85  
86 86 // 准备运费模板费用配置数据
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApi.java renamed to yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApi.java
1 1 package cn.iocoder.yudao.module.member.api.address;
2 2  
3   -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  3 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
4 4  
5 5 /**
6 6 * 用户收件地址 API 接口
7 7 *
8 8 * @author 芋道源码
9 9 */
10   -public interface AddressApi {
  10 +public interface MemberAddressApi {
11 11  
12 12 /**
13 13 * 获得用户收件地址
... ... @@ -16,7 +16,7 @@ public interface AddressApi {
16 16 * @param userId 用户编号
17 17 * @return 用户收件地址
18 18 */
19   - AddressRespDTO getAddress(Long id, Long userId);
  19 + MemberAddressRespDTO getAddress(Long id, Long userId);
20 20  
21 21 /**
22 22 * 获得用户默认收件地址
... ... @@ -24,6 +24,6 @@ public interface AddressApi {
24 24 * @param userId 用户编号
25 25 * @return 用户收件地址
26 26 */
27   - AddressRespDTO getDefaultAddress(Long userId);
  27 + MemberAddressRespDTO getDefaultAddress(Long userId);
28 28  
29 29 }
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/AddressRespDTO.java renamed to yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/MemberAddressRespDTO.java
... ... @@ -8,7 +8,7 @@ import lombok.Data;
8 8 * @author 芋道源码
9 9 */
10 10 @Data
11   -public class AddressRespDTO {
  11 +public class MemberAddressRespDTO {
12 12  
13 13 /**
14 14 * 编号
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java
... ... @@ -38,7 +38,8 @@ public interface MemberUserApi {
38 38 * @return 会员用户 Map
39 39 */
40 40 default Map<Long, MemberUserRespDTO> getUserMap(Collection<Long> ids) {
41   - return convertMap(getUserList(ids), MemberUserRespDTO::getId);
  41 + List<MemberUserRespDTO> list = getUserList(ids);
  42 + return convertMap(list, MemberUserRespDTO::getId);
42 43 }
43 44  
44 45 /**
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消息
  3 + */
  4 +package cn.iocoder.yudao.module.member.message;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/coupon/UserCreateMessage.java renamed to yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/user/MemberUserCreateMessage.java
1   -package cn.iocoder.yudao.module.promotion.mq.message.coupon;
  1 +package cn.iocoder.yudao.module.member.message.user;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
4 3 import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6 4  
7 5 import javax.validation.constraints.NotNull;
8 6  
... ... @@ -12,8 +10,7 @@ import javax.validation.constraints.NotNull;
12 10 * @author owen
13 11 */
14 12 @Data
15   -@EqualsAndHashCode(callSuper = true)
16   -public class UserCreateMessage extends AbstractStreamMessage {
  13 +public class MemberUserCreateMessage {
17 14  
18 15 /**
19 16 * 用户编号
... ... @@ -21,9 +18,4 @@ public class UserCreateMessage extends AbstractStreamMessage {
21 18 @NotNull(message = "用户编号不能为空")
22 19 private Long userId;
23 20  
24   - @Override
25   - public String getStreamKey() {
26   - return "member.create.send";
27   - }
28   -
29 21 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApiImpl.java renamed to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApiImpl.java
1 1 package cn.iocoder.yudao.module.member.api.address;
2 2  
3   -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  3 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
4 4 import cn.iocoder.yudao.module.member.convert.address.AddressConvert;
5 5 import cn.iocoder.yudao.module.member.service.address.AddressService;
6 6 import org.springframework.stereotype.Service;
... ... @@ -15,18 +15,18 @@ import javax.annotation.Resource;
15 15 */
16 16 @Service
17 17 @Validated
18   -public class AddressApiImpl implements AddressApi {
  18 +public class MemberAddressApiImpl implements MemberAddressApi {
19 19  
20 20 @Resource
21 21 private AddressService addressService;
22 22  
23 23 @Override
24   - public AddressRespDTO getAddress(Long id, Long userId) {
  24 + public MemberAddressRespDTO getAddress(Long id, Long userId) {
25 25 return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id));
26 26 }
27 27  
28 28 @Override
29   - public AddressRespDTO getDefaultAddress(Long userId) {
  29 + public MemberAddressRespDTO getDefaultAddress(Long userId) {
30 30 return AddressConvert.INSTANCE.convert02(addressService.getDefaultUserAddress(userId));
31 31 }
32 32  
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/MemberPointRecordController.java
... ... @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.member.controller.admin.point;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
6   -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
7 5 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO;
8 6 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordRespVO;
9 7 import cn.iocoder.yudao.module.member.convert.point.MemberPointRecordConvert;
10 8 import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO;
  9 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
11 10 import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
  11 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
12 12 import io.swagger.v3.oas.annotations.Operation;
13 13 import io.swagger.v3.oas.annotations.tags.Tag;
14 14 import org.springframework.security.access.prepost.PreAuthorize;
... ... @@ -35,7 +35,7 @@ public class MemberPointRecordController {
35 35 private MemberPointRecordService pointRecordService;
36 36  
37 37 @Resource
38   - private MemberUserApi memberUserApi;
  38 + private MemberUserService memberUserService;
39 39  
40 40 @GetMapping("/page")
41 41 @Operation(summary = "获得用户积分记录分页")
... ... @@ -48,7 +48,7 @@ public class MemberPointRecordController {
48 48 }
49 49  
50 50 // 拼接结果返回
51   - List<MemberUserRespDTO> users = memberUserApi.getUserList(
  51 + List<MemberUserDO> users = memberUserService.getUserList(
52 52 convertSet(pageResult.getList(), MemberPointRecordDO::getUserId));
53 53 return success(MemberPointRecordConvert.INSTANCE.convertPage(pageResult, users));
54 54 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/MemberSignInRecordController.java
... ... @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.member.controller.admin.signin;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
6   -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
7 5 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO;
8 6 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO;
9 7 import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert;
10 8 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
  9 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
11 10 import cn.iocoder.yudao.module.member.service.signin.MemberSignInRecordService;
  11 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
12 12 import io.swagger.v3.oas.annotations.Operation;
13 13 import io.swagger.v3.oas.annotations.tags.Tag;
14 14 import org.springframework.security.access.prepost.PreAuthorize;
... ... @@ -35,7 +35,7 @@ public class MemberSignInRecordController {
35 35 private MemberSignInRecordService signInRecordService;
36 36  
37 37 @Resource
38   - private MemberUserApi memberUserApi;
  38 + private MemberUserService memberUserService;
39 39  
40 40 @GetMapping("/page")
41 41 @Operation(summary = "获得签到记录分页")
... ... @@ -48,7 +48,7 @@ public class MemberSignInRecordController {
48 48 }
49 49  
50 50 // 拼接结果返回
51   - List<MemberUserRespDTO> users = memberUserApi.getUserList(
  51 + List<MemberUserDO> users = memberUserService.getUserList(
52 52 convertSet(pageResult.getList(), MemberSignInRecordDO::getUserId));
53 53 return success(MemberSignInRecordConvert.INSTANCE.convertPage(pageResult, users));
54 54 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
... ... @@ -4,7 +4,7 @@ Content-Type: application/json
4 4 tenant-id: {{appTenentId}}
5 5  
6 6 {
7   - "mobile": "15601691300",
  7 + "mobile": "15601691388",
8 8 "password": "admin123"
9 9 }
10 10  
... ... @@ -14,7 +14,7 @@ Content-Type: application/json
14 14 tenant-id: {{appTenentId}}
15 15  
16 16 {
17   - "mobile": "15601691399",
  17 + "mobile": "15601691388",
18 18 "scene": 1
19 19 }
20 20  
... ... @@ -22,9 +22,10 @@ tenant-id: {{appTenentId}}
22 22 POST {{appApi}}/member/auth/sms-login
23 23 Content-Type: application/json
24 24 tenant-id: {{appTenentId}}
  25 +terminal: 30
25 26  
26 27 {
27   - "mobile": "15601691301",
  28 + "mobile": "15601691388",
28 29 "code": 9999
29 30 }
30 31  
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java
1 1 package cn.iocoder.yudao.module.member.convert.address;
2 2  
3 3 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
4   -import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  4 +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
5 5 import cn.iocoder.yudao.module.member.controller.admin.address.vo.AddressRespVO;
6 6 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO;
7 7 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO;
... ... @@ -33,7 +33,7 @@ public interface AddressConvert {
33 33  
34 34 List<AppAddressRespVO> convertList(List<MemberAddressDO> list);
35 35  
36   - AddressRespDTO convert02(MemberAddressDO bean);
  36 + MemberAddressRespDTO convert02(MemberAddressDO bean);
37 37  
38 38 @Named("convertAreaIdToAreaName")
39 39 default String convertAreaIdToAreaName(Integer areaId) {
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointRecordConvert.java
... ... @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.member.convert.point;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
5   -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
6 5 import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordRespVO;
7 6 import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordRespVO;
8 7 import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO;
  8 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
9 9 import org.mapstruct.Mapper;
10 10 import org.mapstruct.factory.Mappers;
11 11  
... ... @@ -24,10 +24,10 @@ public interface MemberPointRecordConvert {
24 24  
25 25 MemberPointRecordConvert INSTANCE = Mappers.getMapper(MemberPointRecordConvert.class);
26 26  
27   - default PageResult<MemberPointRecordRespVO> convertPage(PageResult<MemberPointRecordDO> pageResult, List<MemberUserRespDTO> users) {
  27 + default PageResult<MemberPointRecordRespVO> convertPage(PageResult<MemberPointRecordDO> pageResult, List<MemberUserDO> users) {
28 28 PageResult<MemberPointRecordRespVO> voPageResult = convertPage(pageResult);
29 29 // user 拼接
30   - Map<Long, MemberUserRespDTO> userMap = convertMap(users, MemberUserRespDTO::getId);
  30 + Map<Long, MemberUserDO> userMap = convertMap(users, MemberUserDO::getId);
31 31 voPageResult.getList().forEach(record -> MapUtils.findAndThen(userMap, record.getUserId(),
32 32 memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname())));
33 33 return voPageResult;
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java
... ... @@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7   -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
8 7 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO;
9 8 import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordRespVO;
10 9 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO;
11 10 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
  11 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
12 12 import org.mapstruct.Mapper;
13 13 import org.mapstruct.factory.Mappers;
14 14  
... ... @@ -28,10 +28,10 @@ public interface MemberSignInRecordConvert {
28 28  
29 29 MemberSignInRecordConvert INSTANCE = Mappers.getMapper(MemberSignInRecordConvert.class);
30 30  
31   - default PageResult<MemberSignInRecordRespVO> convertPage(PageResult<MemberSignInRecordDO> pageResult, List<MemberUserRespDTO> users) {
  31 + default PageResult<MemberSignInRecordRespVO> convertPage(PageResult<MemberSignInRecordDO> pageResult, List<MemberUserDO> users) {
32 32 PageResult<MemberSignInRecordRespVO> voPageResult = convertPage(pageResult);
33 33 // user 拼接
34   - Map<Long, MemberUserRespDTO> userMap = convertMap(users, MemberUserRespDTO::getId);
  34 + Map<Long, MemberUserDO> userMap = convertMap(users, MemberUserDO::getId);
35 35 voPageResult.getList().forEach(record -> MapUtils.findAndThen(userMap, record.getUserId(),
36 36 memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname())));
37 37 return voPageResult;
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/consumer/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消费者
  3 + */
  4 +package cn.iocoder.yudao.module.member.mq.consumer;
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的消息
  3 + */
  4 +package cn.iocoder.yudao.module.member.mq.message;
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/user/UserCreateMessage.java deleted
1   -package cn.iocoder.yudao.module.member.mq.message.user;
2   -
3   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -
7   -import javax.validation.constraints.NotNull;
8   -
9   -/**
10   - * 会员用户创建消息
11   - *
12   - * @author owen
13   - */
14   -@Data
15   -@EqualsAndHashCode(callSuper = true)
16   -public class UserCreateMessage extends AbstractStreamMessage {
17   -
18   - /**
19   - * 用户编号
20   - */
21   - @NotNull(message = "用户编号不能为空")
22   - private Long userId;
23   -
24   - @Override
25   - public String getStreamKey() {
26   - return "member.create.send";
27   - }
28   -
29   -}
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列的生产者
  3 + */
  4 +package cn.iocoder.yudao.module.member.mq.producer;
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/UserCreateProducer.java renamed to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/MemberUserProducer.java
1 1 package cn.iocoder.yudao.module.member.mq.producer.user;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
4   -import cn.iocoder.yudao.module.member.mq.message.user.UserCreateMessage;
  3 +import cn.iocoder.yudao.module.member.message.user.MemberUserCreateMessage;
5 4 import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.context.ApplicationContext;
6 6 import org.springframework.stereotype.Component;
7 7  
8 8 import javax.annotation.Resource;
9 9  
10 10 /**
11   - * 会员用户创建 Producer
  11 + * 会员用户 Producer
12 12 *
13 13 * @author owen
14 14 */
15 15 @Slf4j
16 16 @Component
17   -public class UserCreateProducer {
  17 +public class MemberUserProducer {
18 18  
19 19 @Resource
20   - private RedisMQTemplate redisMQTemplate;
  20 + private ApplicationContext applicationContext;
21 21  
22 22 /**
23   - * 发送 {@link UserCreateMessage} 消息
  23 + * 发送 {@link MemberUserCreateMessage} 消息
24 24 *
25 25 * @param userId 用户编号
26 26 */
27 27 public void sendUserCreateMessage(Long userId) {
28   - redisMQTemplate.send(new UserCreateMessage().setUserId(userId));
  28 + applicationContext.publishEvent(new MemberUserCreateMessage().setUserId(userId));
29 29 }
30 30  
31 31 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java
... ... @@ -7,18 +7,18 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 8 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
9 9 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
10   -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
11   -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
12 10 import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO;
13 11 import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordSummaryRespVO;
14 12 import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert;
15 13 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO;
16 14 import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO;
  15 +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
17 16 import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInRecordMapper;
18 17 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
19 18 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
20 19 import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
21 20 import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
  21 +import cn.iocoder.yudao.module.member.service.user.MemberUserService;
22 22 import org.apache.commons.lang3.StringUtils;
23 23 import org.springframework.stereotype.Service;
24 24 import org.springframework.transaction.annotation.Transactional;
... ... @@ -53,7 +53,7 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
53 53 private MemberLevelService memberLevelService;
54 54  
55 55 @Resource
56   - private MemberUserApi memberUserApi;
  56 + private MemberUserService memberUserService;
57 57  
58 58 @Override
59 59 public AppMemberSignInRecordSummaryRespVO getSignInRecordSummary(Long userId) {
... ... @@ -126,12 +126,12 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService
126 126 // 根据用户昵称查询出用户ids
127 127 Set<Long> userIds = null;
128 128 if (StringUtils.isNotBlank(pageReqVO.getNickname())) {
129   - List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
  129 + List<MemberUserDO> users = memberUserService.getUserListByNickname(pageReqVO.getNickname());
130 130 // 如果查询用户结果为空直接返回无需继续查询
131 131 if (CollUtil.isEmpty(users)) {
132 132 return PageResult.empty();
133 133 }
134   - userIds = convertSet(users, MemberUserRespDTO::getId);
  134 + userIds = convertSet(users, MemberUserDO::getId);
135 135 }
136 136 // 分页查询
137 137 return signInRecordMapper.selectPage(pageReqVO, userIds);
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
... ... @@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil;
7 7 import cn.hutool.core.util.StrUtil;
8 8 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
9 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10   -import cn.iocoder.yudao.module.infra.api.file.FileApi;
11 10 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
12 11 import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
13 12 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserResetPasswordReqVO;
... ... @@ -18,7 +17,7 @@ import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
18 17 import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
19 18 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
20 19 import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
21   -import cn.iocoder.yudao.module.member.mq.producer.user.UserCreateProducer;
  20 +import cn.iocoder.yudao.module.member.mq.producer.user.MemberUserProducer;
22 21 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
23 22 import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
24 23 import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
... ... @@ -29,7 +28,6 @@ import org.springframework.stereotype.Service;
29 28 import org.springframework.transaction.annotation.Transactional;
30 29 import org.springframework.transaction.support.TransactionSynchronization;
31 30 import org.springframework.transaction.support.TransactionSynchronizationManager;
32   -import org.springframework.transaction.support.TransactionTemplate;
33 31  
34 32 import javax.annotation.Resource;
35 33 import javax.validation.Valid;
... ... @@ -55,18 +53,13 @@ public class MemberUserServiceImpl implements MemberUserService {
55 53 private MemberUserMapper memberUserMapper;
56 54  
57 55 @Resource
58   - private FileApi fileApi;
59   - @Resource
60 56 private SmsCodeApi smsCodeApi;
61 57  
62 58 @Resource
63 59 private PasswordEncoder passwordEncoder;
64 60  
65 61 @Resource
66   - private UserCreateProducer registerCouponProducer;
67   -
68   - @Resource
69   - private TransactionTemplate transactionTemplate;
  62 + private MemberUserProducer memberUserProducer;
70 63  
71 64 @Override
72 65 public MemberUserDO getUserByMobile(String mobile) {
... ... @@ -107,7 +100,7 @@ public class MemberUserServiceImpl implements MemberUserService {
107 100  
108 101 @Override
109 102 public void afterCommit() {
110   - registerCouponProducer.sendUserCreateMessage(user.getId());
  103 + memberUserProducer.sendUserCreateMessage(user.getId());
111 104 }
112 105  
113 106 });
... ...
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImplTest.java renamed to yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/MemberAddressServiceImplTest.java
... ... @@ -24,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
24 24 * @author 芋道源码
25 25 */
26 26 @Import(AddressServiceImpl.class)
27   -public class AddressServiceImplTest extends BaseDbUnitTest {
  27 +public class MemberAddressServiceImplTest extends BaseDbUnitTest {
28 28  
29 29 @Resource
30 30 private AddressServiceImpl addressService;
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java
... ... @@ -11,6 +11,8 @@ import javax.validation.constraints.NotNull;
11 11 import java.util.Map;
12 12  
13 13 /**
  14 + * 转账单创建 Request DTO
  15 + *
14 16 * @author jason
15 17 */
16 18 @Data
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/member/PayWalletBizTypeEnum.java renamed to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/wallet/PayWalletBizTypeEnum.java
1   -package cn.iocoder.yudao.module.pay.enums.member;
  1 +package cn.iocoder.yudao.module.pay.enums.wallet;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
4 4 import lombok.AllArgsConstructor;
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/package-info.java deleted
1   -package cn.iocoder.yudao.module.pay;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletController.java
... ... @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollectionUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 7 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
9 8 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
10 9 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO;
... ... @@ -26,12 +25,10 @@ import javax.annotation.Resource;
26 25 import javax.validation.Valid;
27 26 import java.util.List;
28 27 import java.util.Map;
29   -import java.util.Set;
30 28  
31 29 import static cn.iocoder.yudao.framework.common.enums.UserTypeEnum.MEMBER;
32 30 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
33   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
34   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  31 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
35 32  
36 33 @Tag(name = "管理后台 - 用户钱包")
37 34 @RestController
... ... @@ -50,6 +47,7 @@ public class PayWalletController {
50 47 @Operation(summary = "获得用户钱包明细")
51 48 public CommonResult<PayWalletRespVO> getWallet(PayWalletUserReqVO reqVO) {
52 49 PayWalletDO wallet = payWalletService.getOrCreateWallet(reqVO.getUserId(), MEMBER.getValue());
  50 + // TODO jason:如果为空,返回给前端只要 null 就可以了
53 51 MemberUserRespDTO memberUser = memberUserApi.getUser(reqVO.getUserId());
54 52 String nickname = memberUser == null ? "" : memberUser.getNickname();
55 53 String avatar = memberUser == null ? "" : memberUser.getAvatar();
... ... @@ -61,9 +59,8 @@ public class PayWalletController {
61 59 @PreAuthorize("@ss.hasPermission('pay:wallet:query')")
62 60 public CommonResult<PageResult<PayWalletRespVO>> getWalletPage(@Valid PayWalletPageReqVO pageVO) {
63 61 if (StrUtil.isNotEmpty(pageVO.getNickname())) {
64   - Set<Long> userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageVO.getNickname()),
65   - MemberUserRespDTO::getId);
66   - pageVO.setUserIds(userIds);
  62 + List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageVO.getNickname());
  63 + pageVO.setUserIds(convertSet(users, MemberUserRespDTO::getId));
67 64 }
68 65 // TODO @jason:管理员也可以先查询下。。
69 66 // 暂时支持查询 userType 会员类型。管理员类型还不知道使用场景
... ... @@ -71,8 +68,8 @@ public class PayWalletController {
71 68 if (CollectionUtil.isEmpty(pageResult.getList())) {
72 69 return success(new PageResult<>(pageResult.getTotal()));
73 70 }
74   - List<Long> userIds = convertList(pageResult.getList(), PayWalletDO::getUserId);
75   - Map<Long, MemberUserRespDTO> userMap = convertMap(memberUserApi.getUserList(userIds),MemberUserRespDTO::getId);
  71 + List<MemberUserRespDTO> users = memberUserApi.getUserList(convertList(pageResult.getList(), PayWalletDO::getUserId));
  72 + Map<Long, MemberUserRespDTO> userMap = convertMap(users, MemberUserRespDTO::getId);
76 73 return success(PayWalletConvert.INSTANCE.convertPage(pageResult, userMap));
77 74 }
78 75  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletTransactionDO.java
1 1 package cn.iocoder.yudao.module.pay.dal.dataobject.wallet;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  4 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
5 5 import com.baomidou.mybatisplus.annotation.KeySequence;
6 6 import com.baomidou.mybatisplus.annotation.TableId;
7 7 import com.baomidou.mybatisplus.annotation.TableName;
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
... ... @@ -17,7 +17,7 @@ import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
17 17 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
18 18 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
19 19 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
20   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  20 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
21 21 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
22 22 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
23 23 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
... ... @@ -421,6 +421,7 @@ public class PayOrderServiceImpl implements PayOrderService {
421 421 return;
422 422 }
423 423  
  424 + // TODO 芋艿:应该 new 出来更新
424 425 order.setPrice(payPrice);
425 426 orderMapper.updateById(order);
426 427 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
... ... @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
11 11 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
12 12 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO;
13 13 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper;
14   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  14 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
15 15 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
16 16 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
17 17 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
... ... @@ -64,6 +64,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
64 64 @Transactional(rollbackFor = Exception.class)
65 65 public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, String userIp,
66 66 AppPayWalletRechargeCreateReqVO reqVO) {
  67 +
67 68 // 1.1 计算充值金额
68 69 int payPrice;
69 70 int bonusPrice = 0;
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
... ... @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO;
5 5 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
6 6 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
7   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  7 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
8 8  
9 9 /**
10 10 * 钱包 Service 接口
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
... ... @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
8 8 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
9 9 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
10 10 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper;
11   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  11 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
12 12 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
13 13 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
14 14 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO;
... ... @@ -22,8 +22,8 @@ import java.time.LocalDateTime;
22 22  
23 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 24 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
25   -import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT;
26   -import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT_REFUND;
  25 +import static cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum.PAYMENT;
  26 +import static cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum.PAYMENT_REFUND;
27 27  
28 28 /**
29 29 * 钱包 Service 实现类
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java
... ... @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionPageReqVO;
5 5 import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO;
6 6 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
7   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  7 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
8 8 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO;
9 9  
10 10 import javax.validation.Valid;
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java
... ... @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
8 8 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
9 9 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper;
10 10 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
11   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  11 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
12 12 import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO;
13 13 import lombok.extern.slf4j.Slf4j;
14 14 import org.springframework.stereotype.Service;
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/WalletTransactionCreateReqBO.java
1 1 package cn.iocoder.yudao.module.pay.service.wallet.bo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
4   -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
  4 +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
5 5 import lombok.Data;
6 6  
7 7 import javax.validation.constraints.NotEmpty;
... ...
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.order;
3 3 import cn.hutool.extra.spring.SpringUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
6   -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
7 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
8 7 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
9 8 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
... ... @@ -68,8 +67,6 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
68 67 private PayOrderExtensionMapper orderExtensionMapper;
69 68  
70 69 @MockBean
71   - private PayClientFactory payClientFactory;
72   - @MockBean
73 70 private PayProperties properties;
74 71 @MockBean
75 72 private PayAppService appService;
... ... @@ -351,7 +348,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
351 348 .thenReturn(channel);
352 349 // mock 方法(client)
353 350 PayClient client = mock(PayClient.class);
354   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  351 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
355 352 // mock 方法()
356 353 PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o ->
357 354 o.setChannelErrorCode("001").setChannelErrorMsg("模拟异常"));
... ... @@ -405,7 +402,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
405 402 .thenReturn(channel);
406 403 // mock 方法(client)
407 404 PayClient client = mock(PayClient.class);
408   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  405 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
409 406 // mock 方法(支付渠道的调用)
410 407 PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null)
411 408 .setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou"));
... ... @@ -463,7 +460,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
463 460 orderExtensionMapper.insert(orderExtension);
464 461 // mock 方法(PayClient 已支付)
465 462 PayClient client = mock(PayClient.class);
466   - when(payClientFactory.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client);
  463 + when(channelService.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client);
467 464 when(client.getOrder(eq(orderExtension.getNo()))).thenReturn(randomPojo(PayOrderRespDTO.class,
468 465 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())));
469 466  
... ... @@ -482,7 +479,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
482 479 orderExtensionMapper.insert(orderExtension);
483 480 // mock 方法(PayClient 已支付)
484 481 PayClient client = mock(PayClient.class);
485   - when(payClientFactory.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client);
  482 + when(channelService.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client);
486 483 when(client.getOrder(eq(orderExtension.getNo()))).thenReturn(randomPojo(PayOrderRespDTO.class,
487 484 o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
488 485  
... ... @@ -639,7 +636,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
639 636 orderExtensionMapper.insert(orderExtension);
640 637 // 准备参数
641 638 PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
642   - .setFeeRate(0.1D));
  639 + .setFeeRate(10D));
643 640 PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
644 641 o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())
645 642 .setOutTradeNo("P110"));
... ... @@ -656,7 +653,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
656 653 .setChannelId(10L).setChannelCode(channel.getCode())
657 654 .setSuccessTime(notify.getSuccessTime()).setExtensionId(orderExtension.getId()).setNo(orderExtension.getNo())
658 655 .setChannelOrderNo(notify.getChannelOrderNo()).setChannelUserId(notify.getChannelUserId())
659   - .setChannelFeeRate(0.1D).setChannelFeePrice(1);
  656 + .setChannelFeeRate(10D).setChannelFeePrice(1);
660 657 assertPojoEquals(order, orderMapper.selectOne(null),
661 658 "updateTime", "updater");
662 659 // 断言,调用
... ... @@ -874,7 +871,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
874 871 orderExtensionMapper.insert(orderExtension);
875 872 // mock 方法(PayClient)
876 873 PayClient client = mock(PayClient.class);
877   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  874 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
878 875 // mock 方法(PayClient 异常)
879 876 when(client.getOrder(any())).thenThrow(new RuntimeException());
880 877  
... ... @@ -901,7 +898,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
901 898 orderExtensionMapper.insert(orderExtension);
902 899 // mock 方法(PayClient)
903 900 PayClient client = mock(PayClient.class);
904   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  901 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
905 902 // mock 方法(PayClient 成功返回)
906 903 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
907 904 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
... ... @@ -935,7 +932,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
935 932 orderExtensionMapper.insert(orderExtension);
936 933 // mock 方法(PayClient)
937 934 PayClient client = mock(PayClient.class);
938   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  935 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
939 936 // mock 方法(PayClient 成功返回)
940 937 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
941 938 o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()));
... ... @@ -966,7 +963,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
966 963 orderExtensionMapper.insert(orderExtension);
967 964 // mock 方法(PayClient)
968 965 PayClient client = mock(PayClient.class);
969   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  966 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
970 967  
971 968 // 调用
972 969 int count = orderService.expireOrder();
... ... @@ -1013,7 +1010,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
1013 1010 orderExtensionMapper.insert(orderExtension);
1014 1011 // mock 方法(PayClient)
1015 1012 PayClient client = mock(PayClient.class);
1016   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  1013 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
1017 1014 // mock 方法(PayClient 退款返回)
1018 1015 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
1019 1016 o -> o.setStatus(PayOrderStatusEnum.REFUND.getStatus()));
... ... @@ -1047,7 +1044,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
1047 1044 orderExtensionMapper.insert(orderExtension);
1048 1045 // mock 方法(PayClient)
1049 1046 PayClient client = mock(PayClient.class);
1050   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  1047 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
1051 1048 // mock 方法(PayClient 成功返回)
1052 1049 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
1053 1050 o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
... ... @@ -1081,7 +1078,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
1081 1078 orderExtensionMapper.insert(orderExtension);
1082 1079 // mock 方法(PayClient)
1083 1080 PayClient client = mock(PayClient.class);
1084   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  1081 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
1085 1082 // mock 方法(PayClient 关闭返回)
1086 1083 PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class,
1087 1084 o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()));
... ...
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.service.refund;
3 3 import cn.hutool.extra.spring.SpringUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
6   -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
7 6 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
8 7 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
9 8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
... ... @@ -67,8 +66,6 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
67 66 @MockBean
68 67 private PayProperties payProperties;
69 68 @MockBean
70   - private PayClientFactory payClientFactory;
71   - @MockBean
72 69 private PayOrderService orderService;
73 70 @MockBean
74 71 private PayAppService appService;
... ... @@ -335,7 +332,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
335 332 when(channelService.validPayChannel(eq(1L))).thenReturn(channel);
336 333 // mock 方法(client)
337 334 PayClient client = mock(PayClient.class);
338   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  335 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
339 336 // mock 数据(refund 已存在)
340 337 PayRefundDO refund = randomPojo(PayRefundDO.class, o ->
341 338 o.setAppId(1L).setMerchantRefundId("200"));
... ... @@ -367,7 +364,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
367 364 when(channelService.validPayChannel(eq(10L))).thenReturn(channel);
368 365 // mock 方法(client)
369 366 PayClient client = mock(PayClient.class);
370   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  367 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
371 368 // mock 方法(client 调用发生异常)
372 369 when(client.unifiedRefund(any(PayRefundUnifiedReqDTO.class))).thenThrow(new RuntimeException());
373 370  
... ... @@ -411,7 +408,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
411 408 when(channelService.validPayChannel(eq(10L))).thenReturn(channel);
412 409 // mock 方法(client)
413 410 PayClient client = mock(PayClient.class);
414   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  411 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
415 412 // mock 方法(client 成功)
416 413 PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class);
417 414 when(client.unifiedRefund(argThat(unifiedReqDTO -> {
... ... @@ -668,7 +665,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
668 665 refundMapper.insert(refund);
669 666 // mock 方法(client)
670 667 PayClient client = mock(PayClient.class);
671   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  668 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
672 669 // mock 方法(client 返回指定状态)
673 670 PayRefundRespDTO respDTO = randomPojo(PayRefundRespDTO.class, o -> o.setStatus(status));
674 671 when(client.getRefund(eq("P110"), eq("R220"))).thenReturn(respDTO);
... ... @@ -690,7 +687,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
690 687 refundMapper.insert(refund);
691 688 // mock 方法(client)
692 689 PayClient client = mock(PayClient.class);
693   - when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
  690 + when(channelService.getPayClient(eq(10L))).thenReturn(client);
694 691 // mock 方法(client 抛出异常)
695 692 when(client.getRefund(eq("P110"), eq("R220"))).thenThrow(new RuntimeException());
696 693  
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
... ... @@ -14,12 +14,12 @@ public interface SocialClientApi {
14 14 /**
15 15 * 获得社交平台的授权 URL
16 16 *
17   - * @param type 社交平台的类型 {@link SocialTypeEnum}
  17 + * @param socialType 社交平台的类型 {@link SocialTypeEnum}
18 18 * @param userType 用户类型
19 19 * @param redirectUri 重定向 URL
20 20 * @return 社交平台的授权 URL
21 21 */
22   - String getAuthorizeUrl(Integer type, Integer userType, String redirectUri);
  22 + String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri);
23 23  
24 24 /**
25 25 * 创建微信公众号 JS SDK 初始化所需的签名
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java
... ... @@ -35,12 +35,12 @@ public interface SocialUserApi {
35 35 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
36 36 *
37 37 * @param userType 用户类型
38   - * @param type 社交平台的类型
  38 + * @param socialType 社交平台的类型
39 39 * @param code 授权码
40 40 * @param state state
41 41 * @return 社交用户
42 42 */
43   - SocialUserRespDTO getSocialUser(Integer userType, Integer type,
  43 + SocialUserRespDTO getSocialUser(Integer userType, Integer socialType,
44 44 String code, String state);
45 45  
46 46 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java
... ... @@ -24,8 +24,8 @@ public class SocialClientApiImpl implements SocialClientApi {
24 24 private SocialClientService socialClientService;
25 25  
26 26 @Override
27   - public String getAuthorizeUrl(Integer type, Integer userType, String redirectUri) {
28   - return socialClientService.getAuthorizeUrl(type, userType, redirectUri);
  27 + public String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) {
  28 + return socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
29 29 }
30 30  
31 31 @Override
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java
... ... @@ -33,8 +33,8 @@ public class SocialUserApiImpl implements SocialUserApi {
33 33 }
34 34  
35 35 @Override
36   - public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) {
37   - return socialUserService.getSocialUser(userType, type, code, state);
  36 + public SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state) {
  37 + return socialUserService.getSocialUser(userType, socialType, code, state);
38 38 }
39 39  
40 40 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
... ... @@ -148,7 +148,8 @@ public class AuthController {
148 148 })
149 149 public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
150 150 @RequestParam("redirectUri") String redirectUri) {
151   - return success(socialClientService.getAuthorizeUrl(type, UserTypeEnum.ADMIN.getValue(), redirectUri));
  151 + return success(socialClientService.getAuthorizeUrl(
  152 + type, UserTypeEnum.ADMIN.getValue(), redirectUri));
152 153 }
153 154  
154 155 @PostMapping("/social-login")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.http
... ... @@ -6,9 +6,9 @@ tenant-id: {{adminTenentId}}
6 6  
7 7 {
8 8 "templateCode": "test_01",
9   - "mobile": "156016913900",
10   - "params": {
11   - "key01": "value01",
12   - "key02": "value02"
  9 + "mobile": "15601691390",
  10 + "templateParams": {
  11 + "operation": "value01",
  12 + "code": "value02"
13 13 }
14 14 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/dict/DictDataConvert.java
... ... @@ -31,5 +31,4 @@ public interface DictDataConvert {
31 31  
32 32 List<AppDictDataRespVO> convertList03(List<DictDataDO> list);
33 33  
34   - List<DictDataRespDTO> convertList04(List<DictDataDO> list);
35 34 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java
1 1 package cn.iocoder.yudao.module.system.mq.consumer.mail;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
4 3 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
5   -import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
6 4 import cn.iocoder.yudao.module.system.service.mail.MailSendService;
7 5 import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.event.EventListener;
  7 +import org.springframework.scheduling.annotation.Async;
8 8 import org.springframework.stereotype.Component;
9 9  
10 10 import javax.annotation.Resource;
... ... @@ -16,12 +16,13 @@ import javax.annotation.Resource;
16 16 */
17 17 @Component
18 18 @Slf4j
19   -public class MailSendConsumer extends AbstractStreamMessageListener<MailSendMessage> {
  19 +public class MailSendConsumer {
20 20  
21 21 @Resource
22 22 private MailSendService mailSendService;
23 23  
24   - @Override
  24 + @EventListener
  25 + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
25 26 public void onMessage(MailSendMessage message) {
26 27 log.info("[onMessage][消息内容({})]", message);
27 28 mailSendService.doSendMail(message);
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java
... ... @@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.system.mq.consumer.sms;
2 2  
3 3 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
4 4 import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
5   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
6 5 import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.event.EventListener;
  7 +import org.springframework.scheduling.annotation.Async;
7 8 import org.springframework.stereotype.Component;
8 9  
9 10 import javax.annotation.Resource;
... ... @@ -15,12 +16,13 @@ import javax.annotation.Resource;
15 16 */
16 17 @Component
17 18 @Slf4j
18   -public class SmsSendConsumer extends AbstractStreamMessageListener<SmsSendMessage> {
  19 +public class SmsSendConsumer {
19 20  
20 21 @Resource
21 22 private SmsSendService smsSendService;
22 23  
23   - @Override
  24 + @EventListener
  25 + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
24 26 public void onMessage(SmsSendMessage message) {
25 27 log.info("[onMessage][消息内容({})]", message);
26 28 smsSendService.doSendSms(message);
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java
1 1 package cn.iocoder.yudao.module.system.mq.message.mail;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
4 3 import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6 4  
7 5 import javax.validation.constraints.NotEmpty;
8 6 import javax.validation.constraints.NotNull;
... ... @@ -13,8 +11,7 @@ import javax.validation.constraints.NotNull;
13 11 * @author 芋道源码
14 12 */
15 13 @Data
16   -@EqualsAndHashCode(callSuper = true)
17   -public class MailSendMessage extends AbstractStreamMessage {
  14 +public class MailSendMessage {
18 15  
19 16 /**
20 17 * 邮件日志编号
... ... @@ -47,9 +44,4 @@ public class MailSendMessage extends AbstractStreamMessage {
47 44 @NotEmpty(message = "邮件内容不能为空")
48 45 private String content;
49 46  
50   - @Override
51   - public String getStreamKey() {
52   - return "system.mail.send";
53   - }
54   -
55 47 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sms/SmsSendMessage.java
1 1 package cn.iocoder.yudao.module.system.mq.message.sms;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.KeyValue;
4   -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
5 4 import lombok.Data;
6   -import lombok.EqualsAndHashCode;
7 5  
8 6 import javax.validation.constraints.NotNull;
9 7 import java.util.List;
... ... @@ -14,8 +12,7 @@ import java.util.List;
14 12 * @author 芋道源码
15 13 */
16 14 @Data
17   -@EqualsAndHashCode(callSuper = true)
18   -public class SmsSendMessage extends AbstractStreamMessage {
  15 +public class SmsSendMessage {
19 16  
20 17 /**
21 18 * 短信日志编号
... ... @@ -42,9 +39,4 @@ public class SmsSendMessage extends AbstractStreamMessage {
42 39 */
43 40 private List<KeyValue<String, Object>> templateParams;
44 41  
45   - @Override
46   - public String getStreamKey() {
47   - return "system.sms.send";
48   - }
49   -
50 42 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java
1 1 package cn.iocoder.yudao.module.system.mq.producer.mail;
2 2  
3   -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
4 3 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
5 4 import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.context.ApplicationContext;
6 6 import org.springframework.stereotype.Component;
7 7  
8 8 import javax.annotation.Resource;
... ... @@ -18,7 +18,7 @@ import javax.annotation.Resource;
18 18 public class MailProducer {
19 19  
20 20 @Resource
21   - private RedisMQTemplate redisMQTemplate;
  21 + private ApplicationContext applicationContext;
22 22  
23 23 /**
24 24 * 发送 {@link MailSendMessage} 消息
... ... @@ -35,7 +35,7 @@ public class MailProducer {
35 35 MailSendMessage message = new MailSendMessage()
36 36 .setLogId(sendLogId).setMail(mail).setAccountId(accountId)
37 37 .setNickname(nickname).setTitle(title).setContent(content);
38   - redisMQTemplate.send(message);
  38 + applicationContext.publishEvent(message);
39 39 }
40 40  
41 41 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java
1 1 package cn.iocoder.yudao.module.system.mq.producer.sms;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.KeyValue;
4   -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
5 4 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
6 5 import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.ApplicationContext;
7 7 import org.springframework.stereotype.Component;
8 8  
9 9 import javax.annotation.Resource;
... ... @@ -20,7 +20,7 @@ import java.util.List;
20 20 public class SmsProducer {
21 21  
22 22 @Resource
23   - private RedisMQTemplate redisMQTemplate;
  23 + private ApplicationContext applicationContext;
24 24  
25 25 /**
26 26 * 发送 {@link SmsSendMessage} 消息
... ... @@ -35,7 +35,7 @@ public class SmsProducer {
35 35 Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
36 36 SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile);
37 37 message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
38   - redisMQTemplate.send(message);
  38 + applicationContext.publishEvent(message);
39 39 }
40 40  
41 41 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordService.java
... ... @@ -91,8 +91,8 @@ public interface SensitiveWordService {
91 91 * 判断文本是否包含敏感词
92 92 *
93 93 * @param text 文本
94   - * @param tags 表述数组
95   - * @return 是否包含
  94 + * @param tags 标签数组
  95 + * @return 是否包含敏感词
96 96 */
97 97 boolean isTextValid(String text, List<String> tags);
98 98  
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java
... ... @@ -258,6 +258,7 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
258 258 if (trie == null) {
259 259 continue;
260 260 }
  261 + // 如果有一个标签不合法,则返回 false 不合法
261 262 if (!trie.isValid(text)) {
262 263 return false;
263 264 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
... ... @@ -5,7 +5,6 @@ import cn.hutool.core.util.StrUtil;
5 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
8   -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
9 8 import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
10 9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
11 10 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
... ... @@ -53,9 +52,6 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
53 52 @Resource
54 53 private SmsChannelService smsChannelService;
55 54  
56   - @Resource
57   - private SmsClientFactory smsClientFactory;
58   -
59 55 @Override
60 56 public Long createSmsTemplate(SmsTemplateCreateReqVO createReqVO) {
61 57 // 校验短信渠道
... ... @@ -173,7 +169,7 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
173 169 @VisibleForTesting
174 170 void validateApiTemplate(Long channelId, String apiTemplateId) {
175 171 // 获得短信模板
176   - SmsClient smsClient = smsClientFactory.getSmsClient(channelId);
  172 + SmsClient smsClient = smsChannelService.getSmsClient(channelId);
177 173 Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId));
178 174 SmsCommonResult<SmsTemplateRespDTO> templateResult = smsClient.getSmsTemplate(apiTemplateId);
179 175 // 校验短信模板是否正确
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
... ... @@ -38,12 +38,12 @@ public interface SocialUserService {
38 38 /**
39 39 * 取消绑定社交用户
40 40 *
41   - * @param userId 用户编号
  41 + * @param userId 用户编号
42 42 * @param userType 全局用户类型
43   - * @param type 社交平台的类型 {@link SocialTypeEnum}
44   - * @param openid 社交平台的 openid
  43 + * @param socialType 社交平台的类型 {@link SocialTypeEnum}
  44 + * @param openid 社交平台的 openid
45 45 */
46   - void unbindSocialUser(Long userId, Integer userType, Integer type, String openid);
  46 + void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid);
47 47  
48 48 /**
49 49 * 获得社交用户
... ... @@ -51,12 +51,12 @@ public interface SocialUserService {
51 51 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
52 52 *
53 53 * @param userType 用户类型
54   - * @param type 社交平台的类型
55   - * @param code 授权码
56   - * @param state state
  54 + * @param socialType 社交平台的类型
  55 + * @param code 授权码
  56 + * @param state state
57 57 * @return 社交用户
58 58 */
59   - SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state);
  59 + SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state);
60 60  
61 61 // ==================== 社交用户 CRUD ====================
62 62  
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
... ... @@ -84,9 +84,9 @@ public class SocialUserServiceImpl implements SocialUserService {
84 84 }
85 85  
86 86 @Override
87   - public void unbindSocialUser(Long userId, Integer userType, Integer type, String openid) {
  87 + public void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid) {
88 88 // 获得 openid 对应的 SocialUserDO 社交用户
89   - SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(type, openid);
  89 + SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, openid);
90 90 if (socialUser == null) {
91 91 throw exception(SOCIAL_USER_NOT_FOUND);
92 92 }
... ... @@ -96,9 +96,9 @@ public class SocialUserServiceImpl implements SocialUserService {
96 96 }
97 97  
98 98 @Override
99   - public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) {
  99 + public SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state) {
100 100 // 获得社交用户
101   - SocialUserDO socialUser = authSocialUser(type, userType, code, state);
  101 + SocialUserDO socialUser = authSocialUser(socialType, userType, code, state);
102 102 Assert.notNull(socialUser, "社交用户不能为空");
103 103  
104 104 // 如果未绑定的社交用户,则无法自动登录,进行报错
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/collection/SimpleTrie.java
... ... @@ -30,9 +30,10 @@ public class SimpleTrie {
30 30 * @param strs 字符串数组
31 31 */
32 32 public SimpleTrie(Collection<String> strs) {
33   - children = new HashMap<>();
  33 + // 排序,优先使用较短的前缀
  34 + strs = CollUtil.sort(strs, String::compareTo);
34 35 // 构建树
35   - CollUtil.sort(strs, String::compareTo); // 排序,优先使用较短的前缀
  36 + children = new HashMap<>();
36 37 for (String str : strs) {
37 38 Map<Character, Object> child = children;
38 39 // 遍历每个字符
... ... @@ -56,11 +57,11 @@ public class SimpleTrie {
56 57 * 验证文本是否合法,即不包含敏感词
57 58 *
58 59 * @param text 文本
59   - * @return 是否 ok
  60 + * @return 是否 true-合法 false-不合法
60 61 */
61 62 public boolean isValid(String text) {
62 63 // 遍历 text,使用每一个 [i, n) 段的字符串,使用 children 前缀树匹配,是否包含敏感词
63   - for (int i = 0; i < text.length() - 1; i++) {
  64 + for (int i = 0; i < text.length(); i++) {
64 65 Map<Character, Object> child = (Map<Character, Object>) children.get(text.charAt(i));
65 66 if (child == null) {
66 67 continue;
... ... @@ -74,14 +75,17 @@ public class SimpleTrie {
74 75 }
75 76  
76 77 /**
77   - * 验证文本从指定位置开始,是否包含某个敏感词
  78 + * 验证文本从指定位置开始,是否不包含某个敏感词
78 79 *
79 80 * @param text 文本
80 81 * @param index 开始位置
81 82 * @param child 节点(当前遍历到的)
82   - * @return 是否包含
  83 + * @return 是否不包含 true-不包含 false-包含
83 84 */
84 85 private boolean recursion(String text, int index, Map<Character, Object> child) {
  86 + if (child.containsKey(CHARACTER_END)) {
  87 + return false;
  88 + }
85 89 if (index == text.length()) {
86 90 return true;
87 91 }
... ... @@ -99,7 +103,7 @@ public class SimpleTrie {
99 103 */
100 104 public List<String> validate(String text) {
101 105 Set<String> results = new HashSet<>();
102   - for (int i = 0; i < text.length() - 1; i++) {
  106 + for (int i = 0; i < text.length(); i++) {
103 107 Character c = text.charAt(i);
104 108 Map<Character, Object> child = (Map<Character, Object>) children.get(c);
105 109 if (child == null) {
... ... @@ -127,6 +131,9 @@ public class SimpleTrie {
127 131 */
128 132 @SuppressWarnings("unchecked")
129 133 private static boolean recursionWithResult(String text, int index, Map<Character, Object> child, StringBuilder result) {
  134 + if (child.containsKey(CHARACTER_END)) {
  135 + return false;
  136 + }
130 137 if (index == text.length()) {
131 138 return true;
132 139 }
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java
... ... @@ -56,20 +56,28 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
56 56 SensitiveWordDO wordDO2 = randomPojo(SensitiveWordDO.class, o -> o.setName("笨蛋")
57 57 .setTags(singletonList("蔬菜")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
58 58 sensitiveWordMapper.insert(wordDO2);
  59 + SensitiveWordDO wordDO3 = randomPojo(SensitiveWordDO.class, o -> o.setName("白")
  60 + .setTags(singletonList("测试")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  61 + sensitiveWordMapper.insert(wordDO3);
  62 + SensitiveWordDO wordDO4 = randomPojo(SensitiveWordDO.class, o -> o.setName("白痴")
  63 + .setTags(singletonList("测试")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  64 + sensitiveWordMapper.insert(wordDO4);
59 65  
60 66 // 调用
61 67 sensitiveWordService.initLocalCache();
62 68 // 断言 sensitiveWordTagsCache 缓存
63   - assertEquals(SetUtils.asSet("论坛", "蔬菜"), sensitiveWordService.getSensitiveWordTagSet());
  69 + assertEquals(SetUtils.asSet("论坛", "蔬菜", "测试"), sensitiveWordService.getSensitiveWordTagSet());
64 70 // 断言 sensitiveWordCache
65   - assertEquals(2, sensitiveWordService.getSensitiveWordCache().size());
  71 + assertEquals(4, sensitiveWordService.getSensitiveWordCache().size());
66 72 assertPojoEquals(wordDO1, sensitiveWordService.getSensitiveWordCache().get(0));
67 73 assertPojoEquals(wordDO2, sensitiveWordService.getSensitiveWordCache().get(1));
  74 + assertPojoEquals(wordDO3, sensitiveWordService.getSensitiveWordCache().get(2));
68 75 // 断言 tagSensitiveWordTries 缓存
69 76 assertNotNull(sensitiveWordService.getDefaultSensitiveWordTrie());
70   - assertEquals(2, sensitiveWordService.getTagSensitiveWordTries().size());
  77 + assertEquals(3, sensitiveWordService.getTagSensitiveWordTries().size());
71 78 assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("论坛"));
72 79 assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("蔬菜"));
  80 + assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("测试"));
73 81 }
74 82  
75 83 @Test
... ... @@ -231,11 +239,17 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
231 239 testInitLocalCache();
232 240 // 准备参数
233 241 String text = "你是傻瓜,你是笨蛋";
234   -
235 242 // 调用
236 243 List<String> result = sensitiveWordService.validateText(text, null);
237 244 // 断言
238 245 assertEquals(Arrays.asList("傻瓜", "笨蛋"), result);
  246 +
  247 + // 准备参数
  248 + String text2 = "你是傻瓜,你是笨蛋,你是白";
  249 + // 调用
  250 + List<String> result2 = sensitiveWordService.validateText(text2, null);
  251 + // 断言
  252 + assertEquals(Arrays.asList("傻瓜", "笨蛋","白"), result2);
239 253 }
240 254  
241 255 @Test
... ... @@ -243,11 +257,18 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
243 257 testInitLocalCache();
244 258 // 准备参数
245 259 String text = "你是傻瓜,你是笨蛋";
246   -
247 260 // 调用
248 261 List<String> result = sensitiveWordService.validateText(text, singletonList("论坛"));
249 262 // 断言
250 263 assertEquals(singletonList("傻瓜"), result);
  264 +
  265 +
  266 + // 准备参数
  267 + String text2 = "你是白";
  268 + // 调用
  269 + List<String> result2 = sensitiveWordService.validateText(text2, singletonList("测试"));
  270 + // 断言
  271 + assertEquals(singletonList("白"), result2);
251 272 }
252 273  
253 274 @Test
... ... @@ -255,9 +276,13 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
255 276 testInitLocalCache();
256 277 // 准备参数
257 278 String text = "你是傻瓜,你是笨蛋";
258   -
259 279 // 调用,断言
260 280 assertFalse(sensitiveWordService.isTextValid(text, null));
  281 +
  282 + // 准备参数
  283 + String text2 = "你是白";
  284 + // 调用,断言
  285 + assertFalse(sensitiveWordService.isTextValid(text2, null));
261 286 }
262 287  
263 288 @Test
... ... @@ -265,9 +290,13 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
265 290 testInitLocalCache();
266 291 // 准备参数
267 292 String text = "你是傻瓜,你是笨蛋";
268   -
269 293 // 调用,断言
270 294 assertFalse(sensitiveWordService.isTextValid(text, singletonList("论坛")));
  295 +
  296 + // 准备参数
  297 + String text2 = "你是白";
  298 + // 调用,断言
  299 + assertFalse(sensitiveWordService.isTextValid(text2, singletonList("测试")));
271 300 }
272 301  
273 302 }
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
... ... @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
7 7 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
8 8 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
9   -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
10 9 import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
11 10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
12 11 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
... ... @@ -36,7 +35,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
36 35 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
37 36 import static org.junit.jupiter.api.Assertions.*;
38 37 import static org.mockito.ArgumentMatchers.eq;
39   -import static org.mockito.Mockito.*;
  38 +import static org.mockito.Mockito.when;
40 39  
41 40 @Import(SmsTemplateServiceImpl.class)
42 41 public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
... ... @@ -50,8 +49,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
50 49 @MockBean
51 50 private SmsChannelService smsChannelService;
52 51 @MockBean
53   - private SmsClientFactory smsClientFactory;
54   - @MockBean
55 52 private SmsClient smsClient;
56 53  
57 54 @Test
... ... @@ -82,7 +79,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
82 79 });
83 80 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
84 81 // mock 获得 API 短信模板成功
85   - when(smsClientFactory.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
  82 + when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
86 83 when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class,
87 84 o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode())));
88 85  
... ... @@ -117,7 +114,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
117 114 });
118 115 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
119 116 // mock 获得 API 短信模板成功
120   - when(smsClientFactory.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
  117 + when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
121 118 when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class,
122 119 o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode())));
123 120  
... ...
yudao-server/pom.xml
... ... @@ -37,11 +37,11 @@
37 37 </dependency>
38 38  
39 39 <!-- 会员中心。默认注释,保证编译速度 -->
40   - <dependency>
41   - <groupId>cn.iocoder.boot</groupId>
42   - <artifactId>yudao-module-member-biz</artifactId>
43   - <version>${revision}</version>
44   - </dependency>
  40 +<!-- <dependency>-->
  41 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  42 +<!-- <artifactId>yudao-module-member-biz</artifactId>-->
  43 +<!-- <version>${revision}</version>-->
  44 +<!-- </dependency>-->
45 45  
46 46 <!-- 数据报表。默认注释,保证编译速度 -->
47 47 <!-- <dependency>-->
... ... @@ -56,40 +56,40 @@
56 56 <!-- <version>${revision}</version>-->
57 57 <!-- </dependency>-->
58 58 <!-- 支付服务。默认注释,保证编译速度 -->
59   - <dependency>
60   - <groupId>cn.iocoder.boot</groupId>
61   - <artifactId>yudao-module-pay-biz</artifactId>
62   - <version>${revision}</version>
63   - </dependency>
  59 +<!-- <dependency>-->
  60 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  61 +<!-- <artifactId>yudao-module-pay-biz</artifactId>-->
  62 +<!-- <version>${revision}</version>-->
  63 +<!-- </dependency>-->
64 64  
65 65 <!-- 微信公众号模块。默认注释,保证编译速度 -->
66   - <dependency>
67   - <groupId>cn.iocoder.boot</groupId>
68   - <artifactId>yudao-module-mp-biz</artifactId>
69   - <version>${revision}</version>
70   - </dependency>
  66 +<!-- <dependency>-->
  67 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  68 +<!-- <artifactId>yudao-module-mp-biz</artifactId>-->
  69 +<!-- <version>${revision}</version>-->
  70 +<!-- </dependency>-->
71 71  
72 72 <!-- 商城相关模块。默认注释,保证编译速度-->
73   - <dependency>
74   - <groupId>cn.iocoder.boot</groupId>
75   - <artifactId>yudao-module-promotion-biz</artifactId>
76   - <version>${revision}</version>
77   - </dependency>
78   - <dependency>
79   - <groupId>cn.iocoder.boot</groupId>
80   - <artifactId>yudao-module-product-biz</artifactId>
81   - <version>${revision}</version>
82   - </dependency>
83   - <dependency>
84   - <groupId>cn.iocoder.boot</groupId>
85   - <artifactId>yudao-module-trade-biz</artifactId>
86   - <version>${revision}</version>
87   - </dependency>
88   - <dependency>
89   - <groupId>cn.iocoder.boot</groupId>
90   - <artifactId>yudao-module-statistics-biz</artifactId>
91   - <version>${revision}</version>
92   - </dependency>
  73 +<!-- <dependency>-->
  74 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  75 +<!-- <artifactId>yudao-module-promotion-biz</artifactId>-->
  76 +<!-- <version>${revision}</version>-->
  77 +<!-- </dependency>-->
  78 +<!-- <dependency>-->
  79 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  80 +<!-- <artifactId>yudao-module-product-biz</artifactId>-->
  81 +<!-- <version>${revision}</version>-->
  82 +<!-- </dependency>-->
  83 +<!-- <dependency>-->
  84 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  85 +<!-- <artifactId>yudao-module-trade-biz</artifactId>-->
  86 +<!-- <version>${revision}</version>-->
  87 +<!-- </dependency>-->
  88 +<!-- <dependency>-->
  89 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  90 +<!-- <artifactId>yudao-module-statistics-biz</artifactId>-->
  91 +<!-- <version>${revision}</version>-->
  92 +<!-- </dependency>-->
93 93  
94 94 <!-- spring boot 配置所需依赖 -->
95 95 <dependency>
... ...
yudao-server/src/main/resources/application-dev.yaml
... ... @@ -94,6 +94,23 @@ spring:
94 94 jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置
95 95 initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。
96 96  
  97 +--- #################### 消息队列相关 ####################
  98 +
  99 +# rocketmq 配置项,对应 RocketMQProperties 配置类
  100 +rocketmq:
  101 + name-server: 127.0.0.1:9876 # RocketMQ Namesrv
  102 +
  103 +spring:
  104 + # RabbitMQ 配置项,对应 RabbitProperties 配置类
  105 + rabbitmq:
  106 + host: 127.0.0.1 # RabbitMQ 服务的地址
  107 + port: 5672 # RabbitMQ 服务的端口
  108 + username: guest # RabbitMQ 服务的账号
  109 + password: guest # RabbitMQ 服务的密码
  110 + # Kafka 配置项,对应 KafkaProperties 配置类
  111 + kafka:
  112 + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔
  113 +
97 114 --- #################### 服务保障相关配置 ####################
98 115  
99 116 # Lock4j 配置项
... ...
yudao-server/src/main/resources/application-local.yaml
... ... @@ -109,6 +109,23 @@ spring:
109 109 jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置
110 110 initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。
111 111  
  112 +--- #################### 消息队列相关 ####################
  113 +
  114 +# rocketmq 配置项,对应 RocketMQProperties 配置类
  115 +rocketmq:
  116 + name-server: 127.0.0.1:9876 # RocketMQ Namesrv
  117 +
  118 +spring:
  119 + # RabbitMQ 配置项,对应 RabbitProperties 配置类
  120 + rabbitmq:
  121 + host: 127.0.0.1 # RabbitMQ 服务的地址
  122 + port: 5672 # RabbitMQ 服务的端口
  123 + username: guest # RabbitMQ 服务的账号
  124 + password: guest # RabbitMQ 服务的密码
  125 + # Kafka 配置项,对应 KafkaProperties 配置类
  126 + kafka:
  127 + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔
  128 +
112 129 --- #################### 服务保障相关配置 ####################
113 130  
114 131 # Lock4j 配置项
... ...
yudao-server/src/main/resources/application.yaml
... ... @@ -106,6 +106,32 @@ aj:
106 106 req-check-minute-limit: 60 # check 接口一分钟内请求数限制
107 107 req-verify-minute-limit: 60 # verify 接口一分钟内请求数限制
108 108  
  109 +--- #################### 消息队列相关 ####################
  110 +
  111 +# rocketmq 配置项,对应 RocketMQProperties 配置类
  112 +rocketmq:
  113 + # Producer 配置项
  114 + producer:
  115 + group: ${spring.application.name}_PRODUCER # 生产者分组
  116 +
  117 +spring:
  118 + # Kafka 配置项,对应 KafkaProperties 配置类
  119 + kafka:
  120 + # Kafka Producer 配置项
  121 + producer:
  122 + acks: 1 # 0-不应答。1-leader 应答。all-所有 leader 和 follower 应答。
  123 + retries: 3 # 发送失败时,重试发送的次数
  124 + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer # 消息的 value 的序列化
  125 + # Kafka Consumer 配置项
  126 + consumer:
  127 + auto-offset-reset: earliest # 设置消费者分组最初的消费进度为 earliest 。可参考博客 https://blog.csdn.net/lishuangzhe7047/article/details/74530417 理解
  128 + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
  129 + properties:
  130 + spring.json.trusted.packages: '*'
  131 + # Kafka Consumer Listener 监听器配置
  132 + listener:
  133 + missing-topics-fatal: false # 消费监听接口监听的主题不存在时,默认会报错。所以通过设置为 false ,解决报错
  134 +
109 135 --- #################### 芋道相关配置 ####################
110 136  
111 137 yudao:
... ... @@ -145,12 +171,6 @@ yudao:
145 171 - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants
146 172 - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
147 173 - cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants
148   - mq:
149   - redis:
150   - pubsub:
151   - enable: false # 是否开启 Redis pubsub 广播消费,默认为 true。这里设置成 false,可以按需开启
152   - stream:
153   - enable: false # 是否开启 Redis stream 集群消费,默认为 true。这里设置成 false,可以按需开启
154 174 tenant: # 多租户相关配置项
155 175 enable: true
156 176 ignore-urls:
... ...
yudao-server/src/main/resources/static/MP_verify_DKOvVzFP7vPwwHx2.txt deleted
1   -DKOvVzFP7vPwwHx2
2 0 \ No newline at end of file
yudao-server/src/main/resources/static/READMD.md deleted
1   -## 微信公众号
2   -
3   -参考文章:https://www.yuque.com/docs/share/0e2966dd-89f8-4b69-980d-b876168725df
4   -
5   -① 访问 social-login.html 选择【微信公众号】
6   -
7   -② 微信公众号授权完成后,跳转回 social-login2.html,输入手机号 + 密码,进行绑定
8   -
9   -## 微信小程序
10   -
11   -参考文章:https://www.yuque.com/docs/share/88e3d30a-6830-45fc-8c25-dae485aef3aa
12   -
13   -① 暂时使用 mini-program-test 项目
yudao-server/src/main/resources/static/pay_wx_pub.html deleted
1   -<!DOCTYPE html>
2   -<html>
3   -<head>
4   - <meta charset="UTF-8">
5   - <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
6   - <title>支付测试页</title>
7   - <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
8   - <script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
9   -</head>
10   -<body>
11   -<div>点击如下按钮,发起支付的测试</div>
12   -<div>
13   - <button id="wx_pub">微信公众号</button>
14   -</div>
15   -</body>
16   -<script>
17   - let shopOrderId = undefined;
18   - let payOrderId = undefined;
19   - let server = 'http://127.0.0.1:48080';
20   - // let server = 'http://niubi.natapp1.cc';
21   - // TODO openid
22   - let openid = "ockUAwIZ-0OeMZl9ogcZ4ILrGba0";
23   - $(function() {
24   - // 获得 JsapiTicket
25   - // 参考 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html 文档
26   - $.ajax({
27   - url: server + "/app-api/wx/mp/create-jsapi-signature?url=" + document.location.href,
28   - method: 'POST',
29   - headers: {
30   - 'tenant-id': 1
31   - },
32   - success: function( result ) {
33   - if (result.code !== 0) {
34   - alert('获取 JsapiTicket 失败,原因:' + result.msg)
35   - return;
36   - }
37   - var jsapiTicket = result.data;
38   - jsapiTicket.jsApiList = ['chooseWXPay'];
39   - jsapiTicket.debug = false;
40   -
41   - // 初始化 JS
42   - wx.config(jsapiTicket);
43   - }
44   - });
45   -
46   - // 自动发起商城订单编号
47   - $.ajax({
48   - url: server + "/app-api/shop/order/create",
49   - method: 'POST',
50   - success: function( result ) {
51   - if (result.code !== 0) {
52   - alert('创建商城订单失败,原因:' + result.msg)
53   - return;
54   - }
55   - shopOrderId = result.data.id;
56   - payOrderId = result.data.payOrderId;
57   - console.log("商城订单:" + shopOrderId)
58   - console.log("支付订单:" + payOrderId)
59   - }
60   - })
61   - })
62   -
63   - // 微信公众号
64   - $( "#wx_pub").on( "click", function() {
65   - if (typeof WeixinJSBridge == "undefined") {
66   - // if (document.addEventListener) {
67   - // document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
68   - // } else if (document.attachEvent) {
69   - // document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
70   - // document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
71   - // }
72   - alert('微信支付,只支持在微信客户端中使用!');
73   - return;
74   - }
75   - if (navigator.userAgent.indexOf('wechatdevtools') >= 0) {
76   - alert('微信支付,无法在微信开发者工具中使用!请使用微信客户端!');
77   - return;
78   - }
79   -
80   - // 提交支付
81   - // 参考 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6 文档
82   - // 参考 https://segmentfault.com/a/1190000020704650 文档
83   - $.ajax({
84   - url: server + "/app-api/pay/order/submit",
85   - method: 'POST',
86   - dataType: "json",
87   - contentType: "application/json",
88   - data: JSON.stringify({
89   - "id": payOrderId,
90   - "channelCode": 'wx_pub',
91   - "channelExtras": {
92   - "openid": openid
93   - }
94   - }),
95   - success: function( result ) {
96   - if (result.code !== 0) {
97   - alert('提交支付订单失败,原因:' + result.msg)
98   - return;
99   - }
100   - alert('点击确定,开始微信支付');
101   - // 开始调用微信支付
102   - let data = result.data.invokeResponse;
103   - wx.chooseWXPay({
104   - timestamp: data.timeStamp,
105   - nonceStr: data.nonceStr,
106   - package: data.packageValue,
107   - signType: data.signType,
108   - paySign: data.paySign,
109   - success: function (res) {
110   - alert(JSON.stringify(res));
111   - },
112   - error: function(e) {
113   - alert(JSON.stringify(e));
114   - }
115   - });
116   - }
117   - })
118   - });
119   -</script>
120   -</html>
yudao-ui-admin/package.json
1 1 {
2 2 "name": "yudao-ui-admin",
3   - "version": "1.8.0-snapshot",
  3 + "version": "1.8.3-snapshot",
4 4 "description": "芋道管理系统",
5 5 "author": "芋道",
6 6 "license": "MIT",
... ...