mirror of
https://github.com/YunaiV/ruoyi-vue-pro.git
synced 2026-03-30 01:34:46 +00:00
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/ai
This commit is contained in:
30
README.md
30
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 | - |
|
||||
|
||||
## 🐷 演示图
|
||||
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -37,12 +37,12 @@
|
||||
<java.version>17</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
|
||||
<maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
|
||||
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
|
||||
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
|
||||
<flatten-maven-plugin.version>1.7.2</flatten-maven-plugin.version>
|
||||
<!-- maven-surefire-plugin 暂时无法通过 bom 的依赖读取(兼容老版本 IDEA 2024 及以前版本) -->
|
||||
<lombok.version>1.18.38</lombok.version>
|
||||
<spring.boot.version>3.5.4</spring.boot.version>
|
||||
<spring.boot.version>3.5.5</spring.boot.version>
|
||||
<mapstruct.version>1.6.3</mapstruct.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@@ -15,53 +15,54 @@
|
||||
|
||||
<properties>
|
||||
<revision>2025.08-SNAPSHOT</revision>
|
||||
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
|
||||
<flatten-maven-plugin.version>1.7.2</flatten-maven-plugin.version>
|
||||
<!-- 统一依赖管理 -->
|
||||
<spring.boot.version>3.5.4</spring.boot.version>
|
||||
<spring.boot.version>3.5.5</spring.boot.version>
|
||||
<!-- Web 相关 -->
|
||||
<springdoc.version>2.8.9</springdoc.version>
|
||||
<springdoc.version>2.8.11</springdoc.version>
|
||||
<knife4j.version>4.5.0</knife4j.version>
|
||||
<!-- DB 相关 -->
|
||||
<druid.version>1.2.24</druid.version>
|
||||
<druid.version>1.2.27</druid.version>
|
||||
<mybatis.version>3.5.19</mybatis.version>
|
||||
<mybatis-plus.version>3.5.12</mybatis-plus.version>
|
||||
<mybatis-plus-join.version>1.5.4</mybatis-plus-join.version>
|
||||
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
||||
<easy-trans.version>3.0.6</easy-trans.version>
|
||||
<redisson.version>3.41.0</redisson.version>
|
||||
<redisson.version>3.51.0</redisson.version>
|
||||
<dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
|
||||
<kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
|
||||
<opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
|
||||
<taos.version>3.3.3</taos.version>
|
||||
<taos.version>3.7.3</taos.version>
|
||||
<!-- 消息队列 -->
|
||||
<rocketmq-spring.version>2.3.2</rocketmq-spring.version>
|
||||
<rocketmq-spring.version>2.3.4</rocketmq-spring.version>
|
||||
<!-- 服务保障相关 -->
|
||||
<lock4j.version>2.2.7</lock4j.version>
|
||||
<!-- 监控相关 -->
|
||||
<skywalking.version>9.0.0</skywalking.version>
|
||||
<skywalking.version>9.5.0</skywalking.version>
|
||||
<spring-boot-admin.version>3.5.2</spring-boot-admin.version>
|
||||
<opentracing.version>0.33.0</opentracing.version>
|
||||
<!-- Test 测试相关 -->
|
||||
<podam.version>8.0.2.RELEASE</podam.version>
|
||||
<jedis-mock.version>1.1.8</jedis-mock.version>
|
||||
<jedis-mock.version>1.1.11</jedis-mock.version>
|
||||
<mockito-inline.version>5.2.0</mockito-inline.version>
|
||||
<!-- Bpm 工作流相关 -->
|
||||
<flowable.version>7.0.1</flowable.version>
|
||||
<!-- 工具类相关 -->
|
||||
<anji-plus-captcha.version>1.4.0</anji-plus-captcha.version>
|
||||
<jsoup.version>1.18.3</jsoup.version>
|
||||
<jsoup.version>1.21.2</jsoup.version>
|
||||
<lombok.version>1.18.38</lombok.version>
|
||||
<mapstruct.version>1.6.3</mapstruct.version>
|
||||
<hutool-5.version>5.8.35</hutool-5.version>
|
||||
<hutool-6.version>6.0.0-M19</hutool-6.version>
|
||||
<fastexcel.version>1.2.0</fastexcel.version>
|
||||
<hutool-5.version>5.8.40</hutool-5.version>
|
||||
<hutool-6.version>6.0.0-M22</hutool-6.version>
|
||||
<fastexcel.version>1.3.0</fastexcel.version>
|
||||
<velocity.version>2.4.1</velocity.version>
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<guava.version>33.4.8-jre</guava.version>
|
||||
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
|
||||
<commons-net.version>3.11.1</commons-net.version>
|
||||
<commons-lang3.version>3.18.0</commons-lang3.version>
|
||||
<jsch.version>0.1.55</jsch.version>
|
||||
<tika-core.version>3.1.0</tika-core.version>
|
||||
<tika-core.version>3.2.2</tika-core.version>
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
<bizlog-sdk.version>3.0.6</bizlog-sdk.version>
|
||||
<netty.version>4.2.4.Final</netty.version>
|
||||
@@ -74,7 +75,7 @@
|
||||
<justauth-starter.version>1.4.0</justauth-starter.version>
|
||||
<jimureport.version>2.0.0</jimureport.version>
|
||||
<jimubi.version>1.9.5</jimubi.version>
|
||||
<weixin-java.version>4.7.5.B</weixin-java.version>
|
||||
<weixin-java.version>4.7.7-20250808.182223</weixin-java.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -524,13 +525,18 @@
|
||||
<artifactId>commons-net</artifactId> <!-- 解决 ftp 连接 -->
|
||||
<version>${commons-net.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch</artifactId> <!-- 解决 sftp 连接 -->
|
||||
<version>${jsch.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version> <!-- 解决 CVE-2025-48924 漏洞 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.anji-plus</groupId>
|
||||
<artifactId>captcha-spring-boot-starter</artifactId> <!-- 验证码,一般用于登录使用 -->
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
// 创建时间为空,则以当前时间为插入时间
|
||||
|
||||
@@ -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<ObjectMapper> 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@ public class BpmProcessInstanceStatusEvent extends ApplicationEvent {
|
||||
*/
|
||||
@NotNull(message = "流程实例的状态不能为空")
|
||||
private Integer status;
|
||||
/**
|
||||
* 流程实例结束的原因
|
||||
*/
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 流程实例对应的业务标识
|
||||
* 例如说,请假
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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())) {
|
||||
|
||||
@@ -166,6 +166,10 @@ public class CouponServiceImpl implements CouponService {
|
||||
public void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId) {
|
||||
// 循环收回
|
||||
for (Long couponId : giveCouponIds) {
|
||||
// couponId 为空或 0 则跳过
|
||||
if (null == couponId || couponId <= 0) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
getSelf().invalidateCoupon(couponId, userId);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" 被替换为 "~"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
// 准备参数
|
||||
|
||||
@@ -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);
|
||||
// 准备参数
|
||||
|
||||
Reference in New Issue
Block a user