diff --git a/README.md b/README.md
index efdb44c7fc..c0ecdf6f49 100644
--- a/README.md
+++ b/README.md
@@ -308,26 +308,26 @@
| 框架 | 说明 | 版本 | 学习指南 |
|---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|
-| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 3.4.5 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
+| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 3.5.5 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |
-| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.23 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
-| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.7 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
+| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.27 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
+| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.12 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 4.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 /7.0 | |
-| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.32.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
-| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 6.1.10 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
-| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 6.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
-| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 8.0.1 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
+| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.35.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
+| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 6.2.9 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
+| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 6.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
+| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 8.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 7.0.0 | [文档](https://doc.iocoder.cn/bpm/) |
-| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
-| [Springdoc](https://springdoc.org/) | Swagger 文档 | 2.3.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
-| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 9.0.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
-| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 3.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
-| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.17.1 | |
+| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
+| [Springdoc](https://springdoc.org/) | Swagger 文档 | 2.8.9 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
+| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 9.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
+| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
+| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.30.14 | |
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.6.3 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
-| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.34 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
-| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.10.1 | - |
-| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 5.7.0 | - |
+| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.38 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
+| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.12.2 | - |
+| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 5.17.0 | - |
## 🐷 演示图
diff --git a/pom.xml b/pom.xml
index 621b67a4af..e1317e1240 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,12 +37,12 @@
17
${java.version}
${java.version}
- 3.2.2
+ 3.5.3
3.14.0
- 1.6.0
+ 1.7.2
1.18.38
- 3.5.4
+ 3.5.5
1.6.3
UTF-8
diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index 317e8b331f..c2cf9eda99 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -15,53 +15,54 @@
2025.08-SNAPSHOT
- 1.6.0
+ 1.7.2
- 3.5.4
+ 3.5.5
- 2.8.9
+ 2.8.11
4.5.0
- 1.2.24
+ 1.2.27
3.5.19
3.5.12
1.5.4
4.3.1
3.0.6
- 3.41.0
+ 3.51.0
8.1.3.140
8.6.0
5.1.0
- 3.3.3
+ 3.7.3
- 2.3.2
+ 2.3.4
2.2.7
- 9.0.0
+ 9.5.0
3.5.2
0.33.0
8.0.2.RELEASE
- 1.1.8
+ 1.1.11
5.2.0
7.0.1
1.4.0
- 1.18.3
+ 1.21.2
1.18.38
1.6.3
- 5.8.35
- 6.0.0-M19
- 1.2.0
+ 5.8.40
+ 6.0.0-M22
+ 1.3.0
2.4.1
1.2.83
33.4.8-jre
2.14.5
3.11.1
+ 3.18.0
0.1.55
- 3.1.0
+ 3.2.2
2.7.0
3.0.6
4.2.4.Final
@@ -74,7 +75,7 @@
1.4.0
2.0.0
1.9.5
- 4.7.5.B
+ 4.7.7-20250808.182223
@@ -524,13 +525,18 @@
commons-net
${commons-net.version}
-
com.jcraft
jsch
${jsch.version}
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
com.anji-plus
captcha-spring-boot-starter
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
index 47e5df004c..11f0a4b4c3 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
@@ -75,7 +75,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
if (TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) {
return false;
}
- // 如果添加了 @TenantIgnore 注解,显然也不忽略租户
+ // 如果添加了 @TenantIgnore 注解,则忽略租户
TenantIgnore tenantIgnore = tableInfo.getEntityType().getAnnotation(TenantIgnore.class);
return tenantIgnore != null;
}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java
index b856ce9542..f18ec1acf6 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java
@@ -13,11 +13,10 @@ public class TenantRabbitMQInitializer implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof RabbitTemplate) {
- RabbitTemplate rabbitTemplate = (RabbitTemplate) bean;
+ if (bean instanceof RabbitTemplate rabbitTemplate) {
rabbitTemplate.addBeforePublishPostProcessors(new TenantRabbitMQMessagePostProcessor());
}
return bean;
}
-}
\ No newline at end of file
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java
index 7f12ac5205..6c3247df14 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java
@@ -18,11 +18,9 @@ public class TenantRocketMQInitializer implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof DefaultRocketMQListenerContainer) {
- DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer) bean;
+ if (bean instanceof DefaultRocketMQListenerContainer container) {
initTenantConsumer(container.getConsumer());
- } else if (bean instanceof RocketMQTemplate) {
- RocketMQTemplate template = (RocketMQTemplate) bean;
+ } else if (bean instanceof RocketMQTemplate template) {
initTenantProducer(template.getProducer());
}
return bean;
@@ -50,4 +48,4 @@ public class TenantRocketMQInitializer implements BeanPostProcessor {
consumerImpl.registerConsumeMessageHook(new TenantRocketMQConsumeMessageHook());
}
-}
\ No newline at end of file
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java
index 4b08210971..5f8a4944d3 100644
--- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java
@@ -23,15 +23,13 @@ public class YudaoAsyncAutoConfiguration {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 处理 ThreadPoolTaskExecutor
- if (bean instanceof ThreadPoolTaskExecutor) {
- ThreadPoolTaskExecutor executor = (ThreadPoolTaskExecutor) bean;
+ if (bean instanceof ThreadPoolTaskExecutor executor) {
executor.setTaskDecorator(TtlRunnable::get);
return executor;
}
// 处理 SimpleAsyncTaskExecutor
// 参考 https://t.zsxq.com/CBoks 增加
- if (bean instanceof SimpleAsyncTaskExecutor) {
- SimpleAsyncTaskExecutor executor = (SimpleAsyncTaskExecutor) bean;
+ if (bean instanceof SimpleAsyncTaskExecutor executor) {
executor.setTaskDecorator(TtlRunnable::get);
return executor;
}
diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java
index 14a8a974f2..596b516757 100644
--- a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java
@@ -1,11 +1,7 @@
package cn.iocoder.yudao.framework.tracer.config;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
-import cn.iocoder.yudao.framework.tracer.core.aop.BizTraceAspect;
import cn.iocoder.yudao.framework.tracer.core.filter.TraceFilter;
-import io.opentracing.Tracer;
-import io.opentracing.util.GlobalTracer;
-import org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -20,32 +16,28 @@ import org.springframework.context.annotation.Bean;
*/
@AutoConfiguration
@ConditionalOnClass(name = {
- "org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer",
- "io.opentracing.Tracer",
+ "org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer", // 来自 apm-toolkit-opentracing.jar
+// "io.opentracing.Tracer", // 来自 opentracing-api.jar
"jakarta.servlet.Filter"
})
@EnableConfigurationProperties(TracerProperties.class)
@ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true)
public class YudaoTracerAutoConfiguration {
- @Bean
- public TracerProperties bizTracerProperties() {
- return new TracerProperties();
- }
-
- @Bean
- public BizTraceAspect bizTracingAop() {
- return new BizTraceAspect(tracer());
- }
-
- @Bean
- public Tracer tracer() {
- // 创建 SkywalkingTracer 对象
- SkywalkingTracer tracer = new SkywalkingTracer();
- // 设置为 GlobalTracer 的追踪器
- GlobalTracer.registerIfAbsent(tracer);
- return tracer;
- }
+ // TODO @芋艿:skywalking 不兼容最新的 opentracing 版本。同时,opentracing 也停止了维护,尬住了!后续换 opentelemetry 即可!
+// @Bean
+// public BizTraceAspect bizTracingAop() {
+// return new BizTraceAspect(tracer());
+// }
+//
+// @Bean
+// public Tracer tracer() {
+// // 创建 SkywalkingTracer 对象
+// SkywalkingTracer tracer = new SkywalkingTracer();
+// // 设置为 GlobalTracer 的追踪器
+// GlobalTracer.registerIfAbsent(tracer);
+// return tracer;
+// }
/**
* 创建 TraceFilter 过滤器,响应 header 设置 traceId
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
index ab2992184f..96872b6438 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.incrementer.*;
import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
@@ -42,6 +43,7 @@ public class YudaoMybatisAutoConfiguration {
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 分页插件
+ mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); // 拦截没有指定条件的 update 和 delete 语句
return mybatisPlusInterceptor;
}
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java
index 3c35999109..6596bb0eef 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java
@@ -19,8 +19,7 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
- if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
- BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
+ if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO baseDO) {
LocalDateTime current = LocalDateTime.now();
// 创建时间为空,则以当前时间为插入时间
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
index c62f0a0300..280f8da349 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
@@ -1,10 +1,10 @@
package cn.iocoder.yudao.framework.jackson.config;
-import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
+import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
@@ -13,39 +13,65 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
-import java.util.List;
-@AutoConfiguration
+@AutoConfiguration(after = JacksonAutoConfiguration.class)
@Slf4j
public class YudaoJacksonAutoConfiguration {
+ /**
+ * 从 Builder 源头定制(关键:使用 *ByType,避免 handledType 要求)
+ */
+ @Bean
+ public Jackson2ObjectMapperBuilderCustomizer ldtEpochMillisCustomizer() {
+ return builder -> builder
+ // Long -> Number
+ .serializerByType(Long.class, NumberSerializer.INSTANCE)
+ .serializerByType(Long.TYPE, NumberSerializer.INSTANCE)
+ // LocalDate / LocalTime
+ .serializerByType(LocalDate.class, LocalDateSerializer.INSTANCE)
+ .deserializerByType(LocalDate.class, LocalDateDeserializer.INSTANCE)
+ .serializerByType(LocalTime.class, LocalTimeSerializer.INSTANCE)
+ .deserializerByType(LocalTime.class, LocalTimeDeserializer.INSTANCE)
+ // LocalDateTime < - > EpochMillis
+ .serializerByType(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
+ .deserializerByType(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
+ }
+
+ /**
+ * 以 Bean 形式暴露 Module(Boot 会自动注册到所有 ObjectMapper)
+ */
+ @Bean
+ public Module timestampSupportModuleBean() {
+ SimpleModule m = new SimpleModule("TimestampSupportModule");
+ // Long -> Number,避免前端精度丢失
+ m.addSerializer(Long.class, NumberSerializer.INSTANCE);
+ m.addSerializer(Long.TYPE, NumberSerializer.INSTANCE);
+ // LocalDate / LocalTime
+ m.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE);
+ m.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE);
+ m.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE);
+ m.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE);
+ // LocalDateTime < - > EpochMillis
+ m.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE);
+ m.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
+ return m;
+ }
+
+ /**
+ * 初始化全局 JsonUtils,直接使用主 ObjectMapper
+ */
@Bean
@SuppressWarnings("InstantiationOfUtilityClass")
- public JsonUtils jsonUtils(List objectMappers) {
- // 1.1 创建 SimpleModule 对象
- SimpleModule simpleModule = new SimpleModule();
- simpleModule
- // 新增 Long 类型序列化规则,数值超过 2^53-1,在 JS 会出现精度丢失问题,因此 Long 自动序列化为字符串类型
- .addSerializer(Long.class, NumberSerializer.INSTANCE)
- .addSerializer(Long.TYPE, NumberSerializer.INSTANCE)
- .addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE)
- .addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE)
- .addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE)
- .addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE)
- // 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳
- .addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
- .addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
- // 1.2 注册到 objectMapper
- objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule));
-
- // 2. 设置 objectMapper 到 JsonUtils
- JsonUtils.init(CollUtil.getFirst(objectMappers));
- log.info("[init][初始化 JsonUtils 成功]");
+ public JsonUtils jsonUtils(ObjectMapper objectMapper) {
+ JsonUtils.init(objectMapper);
+ log.debug("[init][初始化 JsonUtils 成功]");
return new JsonUtils();
}
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
index 3f3a871a13..5147999ad6 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
@@ -184,8 +184,7 @@ public class GlobalExceptionHandler {
@ExceptionHandler(HttpMessageNotReadableException.class)
public CommonResult> methodArgumentTypeInvalidFormatExceptionHandler(HttpMessageNotReadableException ex) {
log.warn("[methodArgumentTypeInvalidFormatExceptionHandler]", ex);
- if (ex.getCause() instanceof InvalidFormatException) {
- InvalidFormatException invalidFormatException = (InvalidFormatException) ex.getCause();
+ if (ex.getCause() instanceof InvalidFormatException invalidFormatException) {
return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", invalidFormatException.getValue()));
}
if (StrUtil.startWith(ex.getMessage(), "Required request body is missing")) {
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
index b4aa301676..d45cfaa8b1 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
@@ -146,10 +146,9 @@ public class WebFrameworkUtils {
public static HttpServletRequest getRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
- if (!(requestAttributes instanceof ServletRequestAttributes)) {
+ if (!(requestAttributes instanceof ServletRequestAttributes servletRequestAttributes)) {
return null;
}
- ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
return servletRequestAttributes.getRequest();
}
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEvent.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEvent.java
index 5522d01b38..1340e89f80 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEvent.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEvent.java
@@ -28,6 +28,11 @@ public class BpmProcessInstanceStatusEvent extends ApplicationEvent {
*/
@NotNull(message = "流程实例的状态不能为空")
private Integer status;
+ /**
+ * 流程实例结束的原因
+ */
+ private String reason;
+
/**
* 流程实例对应的业务标识
* 例如说,请假
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
index c82414b532..460115286b 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
@@ -119,8 +119,9 @@ public interface BpmProcessInstanceConvert {
@Mapping(source = "from.id", target = "to.id", ignore = true)
void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to);
- default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance, Integer status) {
- return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status)
+ default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance,
+ Integer status, String reason) {
+ return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status).setReason(reason)
.setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey());
}
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
index b4a871e145..877d47e88d 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
@@ -960,7 +960,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
// 3. 发送流程实例的状态事件
processInstanceEventPublisher.sendProcessInstanceResultEvent(
- BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status));
+ BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status, reason));
// 4. 流程后置通知
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
index e175807503..fee8a4851f 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
@@ -166,6 +166,10 @@ public class CouponServiceImpl implements CouponService {
public void invalidateCouponsByAdmin(List giveCouponIds, Long userId) {
// 循环收回
for (Long couponId : giveCouponIds) {
+ // couponId 为空或 0 则跳过
+ if (null == couponId || couponId <= 0) {
+ continue;
+ }
try {
getSelf().invalidateCoupon(couponId, userId);
} catch (Exception e) {
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/core/PictureWordCaptchaServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/core/PictureWordCaptchaServiceImpl.java
index ed15a0277b..e5f7741907 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/core/PictureWordCaptchaServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/core/PictureWordCaptchaServiceImpl.java
@@ -8,8 +8,8 @@ import com.anji.captcha.service.impl.CaptchaServiceFactory;
import com.anji.captcha.util.AESUtil;
import com.anji.captcha.util.ImageUtils;
import com.anji.captcha.util.RandomUtils;
-import org.apache.commons.lang3.StringUtils;
import cn.hutool.core.util.RandomUtil;
+import org.apache.commons.lang3.Strings;
import java.awt.*;
import java.awt.geom.AffineTransform;
@@ -82,7 +82,7 @@ public class PictureWordCaptchaServiceImpl extends AbstractCaptchaService {
// 用户输入的验证码(CaptchaVO 中 没有预留字段,暂时用 pointJson 无需加解密)
String userCode = captchaVO.getPointJson();
- if (!StringUtils.equalsIgnoreCase(code, userCode)) {
+ if (!Strings.CI.equals(code, userCode)) {
afterValidateFail(captchaVO);
return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_COORDINATE_ERROR);
}
@@ -209,4 +209,4 @@ public class PictureWordCaptchaServiceImpl extends AbstractCaptchaService {
return RandomUtil.randomString(CHARACTERS, length);
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/justauth/core/AuthRequestFactory.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/justauth/core/AuthRequestFactory.java
index 4ae8b78c6c..53ceabcec6 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/justauth/core/AuthRequestFactory.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/justauth/core/AuthRequestFactory.java
@@ -77,8 +77,8 @@ public class AuthRequestFactory {
extendList = extend.getConfig()
.keySet()
.stream()
- .filter(x -> names.contains(x.toUpperCase()))
.map(String::toUpperCase)
+ .filter(names::contains)
.collect(Collectors.toList());
}
@@ -318,4 +318,4 @@ public class AuthRequestFactory {
.proxy(new Proxy(Proxy.Type.valueOf(proxyConfig.getType()), new InetSocketAddress(proxyConfig.getHostname(), proxyConfig.getPort())))
.build());
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java
index d4ed95d9b2..538efb966b 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java
@@ -114,12 +114,12 @@ public class AliyunSmsClient extends AbstractSmsClient {
@VisibleForTesting
Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
- switch (templateStatus) {
- case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
- case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
- case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
- default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
- }
+ return switch (templateStatus) {
+ case 0 -> SmsTemplateAuditStatusEnum.CHECKING.getStatus();
+ case 1 -> SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
+ case 2 -> SmsTemplateAuditStatusEnum.FAIL.getStatus();
+ default -> throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
+ };
}
/**
@@ -153,8 +153,8 @@ public class AliyunSmsClient extends AbstractSmsClient {
StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起
StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔
headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-")
- || entry.getKey().equalsIgnoreCase("host")
- || entry.getKey().equalsIgnoreCase("content-type"))
+ || "host".equalsIgnoreCase(entry.getKey())
+ || "content-type".equalsIgnoreCase(entry.getKey()))
.sorted(Map.Entry.comparingByKey()).forEach(entry -> {
String lowerKey = entry.getKey().toLowerCase();
canonicalHeaders.append(lowerKey).append(":").append(String.valueOf(entry.getValue()).trim()).append("\n");
@@ -189,10 +189,10 @@ public class AliyunSmsClient extends AbstractSmsClient {
@SneakyThrows
private static String percentCode(String str) {
Assert.notNull(str, "str 不能为空");
- return URLEncoder.encode(str, StandardCharsets.UTF_8.name())
+ return URLEncoder.encode(str, StandardCharsets.UTF_8)
.replace("+", "%20") // 加号 "+" 被替换为 "%20"
.replace("*", "%2A") // 星号 "*" 被替换为 "%2A"
.replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
index 94e589de5e..22d159a8ce 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
+import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
@@ -97,6 +98,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
}
@Override
+ @DataPermission(enable = false)
public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
// 校验验证码
validateCaptcha(reqVO);
diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImplTest.java
index 52c722831f..944086671b 100644
--- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImplTest.java
+++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImplTest.java
@@ -16,7 +16,6 @@ import java.util.List;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
-import static java.util.Collections.emptyList;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@@ -135,13 +134,6 @@ public class OAuth2GrantServiceImplTest extends BaseMockitoUnitTest {
refreshToken, clientId));
}
- @Test
- public void testGrantClientCredentials() {
- assertThrows(UnsupportedOperationException.class,
- () -> oauth2GrantService.grantClientCredentials(randomString(), emptyList()),
- "暂时不支持 client_credentials 授权模式");
- }
-
@Test
public void testRevokeToken_clientIdError() {
// 准备参数
diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImplTest.java
index 0aad4446a1..36b69c75dd 100644
--- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImplTest.java
+++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImplTest.java
@@ -236,6 +236,7 @@ public class OAuth2TokenServiceImplTest extends BaseDbAndRedisUnitTest {
public void testCheckAccessToken_refreshToken() {
// mock 数据(访问令牌)
OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class)
+ .setUserId(0L)
.setExpiresTime(LocalDateTime.now().plusDays(1));
oauth2RefreshTokenMapper.insert(refreshTokenDO);
// 准备参数