mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-11-12 06:57:10 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0388b5dc8 | |||
| e7566d284b | |||
| c17668c2d1 | |||
| 65cfe91770 | |||
| dca715709f | |||
| a110bd9789 | |||
| b0f5506424 | |||
| 6809600858 | |||
| d31d8d209a |
34
CHANGELOG.md
34
CHANGELOG.md
@@ -1,3 +1,37 @@
|
||||
## [v2.3.0](https://github.com/continew-org/continew-starter/compare/v2.2.0...v2.3.0) (2024-07-18)
|
||||
|
||||
### ✨ 新特性
|
||||
|
||||
- 【core】新增 JSR 303 校验器自动配置(从 web 模块迁移) ([6809600](https://github.com/continew-org/continew-starter/commit/6809600858ed597567f78581187f6d88a2ea899e))
|
||||
- 新增 Snail Job 依赖版本 ([d31d8d2](https://github.com/continew-org/continew-starter/commit/d31d8d209a66884d046763bb8497b2c58cf88506))
|
||||
|
||||
### 🐛 问题修复
|
||||
|
||||
- 【extension/crud】修复 DictField 映射错误 ([65cfe91](https://github.com/continew-org/continew-starter/commit/65cfe917709320edd9db2ae55390afe64077e3d3))
|
||||
- 【extension/crud】修复 Name for argument of type [java.lang.Long] not specified, and parameter name information not available via reflection. 错误 ([c17668c](https://github.com/continew-org/continew-starter/commit/c17668c2d1a9440dd0260fd7d8b2a28f104bbce6))
|
||||
- 【web】修复文件上传异常单位显示错误 ([e7566d2](https://github.com/continew-org/continew-starter/commit/e7566d284b53b47577ade59c0b7e9262f9b43758))
|
||||
|
||||
### 💎 功能优化
|
||||
|
||||
- 【core】优化 JSR 303 校验方法 ([b0f5506](https://github.com/continew-org/continew-starter/commit/b0f55064242615717789b3d62880e482ea72a23a))
|
||||
- 【extension/crud】调整 BaseService 相关泛型类型加载为懒加载 ([dca7157](https://github.com/continew-org/continew-starter/commit/dca715709faa9fbd61194ea4177c91475b768694))
|
||||
|
||||
### 📦 依赖升级
|
||||
|
||||
- SpringBoot 3.1.11 => 3.2.7(TaskExecutor => ThreadPoolTaskExecutor)
|
||||
- MyBatisPlus 3.5.5 => 3.5.7(数据权限处理器调整)
|
||||
- MyBatisFlex 1.8.9 => 1.9.3
|
||||
- dynamic-datasource 4.3.0 => 4.3.1
|
||||
- JetCache 2.7.5 => 2.7.6
|
||||
- Redisson 3.30.0 => 3.32.0
|
||||
- CosID 2.6.8 => 2.9.1
|
||||
- EasyExcel 3.3.4 => 4.0.1
|
||||
- XFileStorage 2.1.0 => 2.2.0
|
||||
- Crane4j 2.8.0 => 2.9.0
|
||||
- Hutool 5.8.27 => 5.8.29
|
||||
- AWS S3 1.12.720 => 1.12.761
|
||||
- IP2Region 3.1.11 => 3.2.6
|
||||
|
||||
## [v2.2.0](https://github.com/continew-org/continew-starter/compare/v2.1.1...v2.2.0) (2024-06-30)
|
||||
|
||||
### ✨ 新特性
|
||||
|
||||
104
README.md
104
README.md
@@ -13,7 +13,7 @@
|
||||
<img src="https://sonarcloud.io/api/project_badges/measure?project=Charles7c_continew-starter&metric=alert_status" alt="Sonar Status" />
|
||||
</a>
|
||||
<a href="https://spring.io/projects/spring-boot" target="_blank">
|
||||
<img src="https://img.shields.io/badge/Spring Boot-3.1.11-%236CB52D.svg?logo=Spring-Boot" alt="Spring Boot" />
|
||||
<img src="https://img.shields.io/badge/Spring Boot-3.2.7-%236CB52D.svg?logo=Spring-Boot" alt="Spring Boot" />
|
||||
</a>
|
||||
<a href="https://github.com/continew-org/continew-starter" target="_blank">
|
||||
<img src="https://img.shields.io/badge/Open JDK-17-%236CB52D.svg?logo=OpenJDK&logoColor=FFF" alt="Open JDK" />
|
||||
@@ -140,96 +140,96 @@ continew-starter.web:
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| --------------------- | ------------------------------------ |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| continew-starter-core | 核心模块:包含线程池、项目等自动配置 | <a href="https://spring.io/projects/spring-boot" target="_blank">Spring Boot</a>:3.1.11<br /><a href="https://www.hutool.cn/" target="_blank">Hutool</a>:5.8.25<br />mica-ip2region:3.1.7 |
|
||||
| continew-starter-core | 核心模块:包含线程池、项目等自动配置 | <a href="https://spring.io/projects/spring-boot" target="_blank">Spring Boot</a>:3.1.11<br /><a href="https://www.hutool.cn/" target="_blank">Hutool</a>:5.8.29<br />mica-ip2region:3.2.6 |
|
||||
|
||||
### JSON模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| ----------------------------- | -------------------- | --------------- |
|
||||
| continew-starter-json-jackson | Jackson 序列化等配置 | Jackson:2.15.3 |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ----------------------------- | -------------------- |
|
||||
| continew-starter-json-jackson | Jackson 序列化等配置 |
|
||||
|
||||
### 接口文档
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| ------------------------ | ---------------- | ------------------------------------------------------------ |
|
||||
| continew-starter-api-doc | Knife4j 自动配置 | <a href="https://doc.xiaominfo.com/" target="_blank">Knife4j</a>:4.5.0 |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ------------------------ | ---------------- |
|
||||
| continew-starter-api-doc | Knife4j 自动配置 |
|
||||
|
||||
### 安全模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
|------------------------------------|-----------| -------- |
|
||||
| continew-starter-security-password | 密码编码器 | |
|
||||
| continew-starter-security-mask | JSON 脱敏 | |
|
||||
| continew-starter-security-crypto | 数据库字段加/解密 | |
|
||||
| continew-starter-security-limiter | 限流器 | |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ---------------------------------- | ----------------- |
|
||||
| continew-starter-security-password | 密码编码器 |
|
||||
| continew-starter-security-mask | JSON 脱敏 |
|
||||
| continew-starter-security-crypto | 数据库字段加/解密 |
|
||||
| continew-starter-security-limiter | 限流器 |
|
||||
|
||||
### Web模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| -------------------- | ---------------------------------- | ------------------------------------------------------------ |
|
||||
| continew-starter-web | 跨域、全局异常、错误处理等自动配置 | <a href="https://undertow.io/" target="_blank">Undertow</a>:2.3.10.Final<br />TLog:1.5.1 |
|
||||
| 模块名称 | 模块说明 |
|
||||
| -------------------- | ---------------------------------- |
|
||||
| continew-starter-web | 跨域、全局异常、错误处理等自动配置 |
|
||||
|
||||
### 日志模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| ---------------------------------- | ----------------------------------------- | -------- |
|
||||
| continew-starter-log-core | 日志核心模块 | |
|
||||
| continew-starter-log-httptrace-pro | Spring Boot Actuator HttpTrace 重置增强版 | |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ---------------------------------- | ----------------------------------------- |
|
||||
| continew-starter-log-core | 日志核心模块 |
|
||||
| continew-starter-log-httptrace-pro | Spring Boot Actuator HttpTrace 重置增强版 |
|
||||
|
||||
### 存储模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| ------------------------------ | -------- | -------- |
|
||||
| continew-starter-storage-local | 本地存储 | |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ------------------------------ | -------- |
|
||||
| continew-starter-storage-local | 本地存储 |
|
||||
|
||||
### 文件处理模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| --------------------------- | -------------- |------------------------------------------------------------------------------------------|
|
||||
| continew-starter-file-excel | Excel 相关配置 | <a href="https://easyexcel.opensource.alibaba.com/" target="_blank">Easy Excel</a>:3.3.4 |
|
||||
| 模块名称 | 模块说明 |
|
||||
| --------------------------- | -------------- |
|
||||
| continew-starter-file-excel | Excel 相关配置 |
|
||||
|
||||
### 验证码模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| --------------------------------- | ---------- | ------------------- |
|
||||
| continew-starter-captcha-graphic | 图形验证码 | Easy Captcha:1.6.2 |
|
||||
| continew-starter-captcha-behavior | 行为验证码 | AJ-Captcha:1.3.0 |
|
||||
| 模块名称 | 模块说明 |
|
||||
| --------------------------------- | ---------- |
|
||||
| continew-starter-captcha-graphic | 图形验证码 |
|
||||
| continew-starter-captcha-behavior | 行为验证码 |
|
||||
|
||||
### 缓存模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| ---------------------------------- | --------------------- |--------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| continew-starter-cache-redisson | Redisson 自动配置 | <a href="https://github.com/redisson/redisson/wiki/Redisson%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D" target="_blank">Redisson</a>:3.30.0 |
|
||||
| continew-starter-cache-springcache | Spring Cache 自动配置 | |
|
||||
| continew-starter-cache-jetcache | JetCache 自动配置 | |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ---------------------------------- | --------------------- |
|
||||
| continew-starter-cache-redisson | Redisson 自动配置 |
|
||||
| continew-starter-cache-springcache | Spring Cache 自动配置 |
|
||||
| continew-starter-cache-jetcache | JetCache 自动配置 |
|
||||
|
||||
### 数据访问模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
|------------------------------------|-------------------| ----------------------------------------------------------- |
|
||||
| continew-starter-data-core | 数据访问核心模块 | |
|
||||
| continew-starter-data-mybatis-plus | MyBatis Plus 自动配置 | <a href="https://baomidou.com/" target="_blank">MyBatis Plus</a>:3.5.5<br /><a href="https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611" target="_blank">dynamic-datasource-spring-boot-starter</a>:4.3.0<br /><a href="https://github.com/p6spy/p6spy" target="_blank">P6Spy</a>:3.9.1 |
|
||||
| continew-starter-data-mybatis-flex | MyBatis Flex 自动配置 | |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ---------------------------------- | --------------------- |
|
||||
| continew-starter-data-core | 数据访问核心模块 |
|
||||
| continew-starter-data-mybatis-plus | MyBatis Plus 自动配置 |
|
||||
| continew-starter-data-mybatis-flex | MyBatis Flex 自动配置 |
|
||||
|
||||
### 认证模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| ------------------------------ | ----------------- |--------------------------------------------------------------------------|
|
||||
| continew-starter-auth-satoken | SaToken 自动配置 | <a href="https://sa-token.dev33.cn/" target="_blank">Sa-Token</a>:1.38.0 |
|
||||
| continew-starter-auth-justauth | JustAuth 自动配置 | <a href="https://justauth.cn/" target="_blank">Just Auth</a>:1.16.6 |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ------------------------------ | ----------------- |
|
||||
| continew-starter-auth-satoken | SaToken 自动配置 |
|
||||
| continew-starter-auth-justauth | JustAuth 自动配置 |
|
||||
|
||||
### 消息模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
|--------------------------------------|-----------| ------------------------------------------------------------ |
|
||||
| continew-starter-messaging-mail | 邮件 | Jakarta Mail:1.1.0 |
|
||||
| continew-starter-messaging-websocket | WebSocket | |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ------------------------------------ | --------- |
|
||||
| continew-starter-messaging-mail | 邮件 |
|
||||
| continew-starter-messaging-websocket | WebSocket |
|
||||
|
||||
### 扩展模块
|
||||
|
||||
| 模块名称 | 模块说明 | 依赖版本 |
|
||||
| ------------------------------- | --------------------------------------------- | -------- |
|
||||
| continew-starter-extension-crud | 扩展模块:BaseController 自定义 CRUD API 封装 | |
|
||||
| 模块名称 | 模块说明 |
|
||||
| ------------------------------- | --------------------------------------------- |
|
||||
| continew-starter-extension-crud | 扩展模块:BaseController 自定义 CRUD API 封装 |
|
||||
|
||||
## 贡献代码
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.core.autoconfigure;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.validation.Validator;
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* JSR 303 校验器自动配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class ValidatorAutoConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ValidatorAutoConfiguration.class);
|
||||
|
||||
/**
|
||||
* Validator 失败立即返回模式配置
|
||||
*
|
||||
* <p>
|
||||
* 默认情况下会校验完所有字段,然后才抛出异常。
|
||||
* </p>
|
||||
*/
|
||||
@Bean
|
||||
public Validator validator(MessageSource messageSource) {
|
||||
try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
|
||||
// 国际化
|
||||
factoryBean.setValidationMessageSource(messageSource);
|
||||
factoryBean.setProviderClass(HibernateValidator.class);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("hibernate.validator.fail_fast", "true");
|
||||
factoryBean.setValidationProperties(properties);
|
||||
factoryBean.afterPropertiesSet();
|
||||
return factoryBean.getValidator();
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Validator' completed initialization.");
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,8 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.task.TaskExecutorCustomizer;
|
||||
import org.springframework.boot.task.TaskSchedulerCustomizer;
|
||||
import org.springframework.boot.task.ThreadPoolTaskExecutorCustomizer;
|
||||
import org.springframework.boot.task.ThreadPoolTaskSchedulerCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
@@ -53,7 +53,7 @@ public class ThreadPoolAutoConfiguration {
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "spring.task.execution.extension", name = PropertiesConstants.ENABLED, matchIfMissing = true)
|
||||
public TaskExecutorCustomizer taskExecutorCustomizer(ThreadPoolExtensionProperties properties) {
|
||||
public ThreadPoolTaskExecutorCustomizer threadPoolTaskExecutorCustomizer(ThreadPoolExtensionProperties properties) {
|
||||
return executor -> {
|
||||
// 核心(最小)线程数
|
||||
executor.setCorePoolSize(corePoolSize);
|
||||
@@ -74,7 +74,7 @@ public class ThreadPoolAutoConfiguration {
|
||||
@ConditionalOnProperty(prefix = "spring.task.scheduling.extension", name = PropertiesConstants.ENABLED, matchIfMissing = true)
|
||||
public static class TaskSchedulerConfiguration {
|
||||
@Bean
|
||||
public TaskSchedulerCustomizer taskSchedulerCustomizer(ThreadPoolExtensionProperties properties) {
|
||||
public ThreadPoolTaskSchedulerCustomizer threadPoolTaskSchedulerCustomizer(ThreadPoolExtensionProperties properties) {
|
||||
return executor -> {
|
||||
executor.setRejectedExecutionHandler(properties.getScheduling()
|
||||
.getRejectedPolicy()
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.core.util;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
/**
|
||||
* 国际化工具类
|
||||
*
|
||||
* @author Jasmine
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class MessageSourceUtils {
|
||||
|
||||
private static final MessageSource MESSAGE_SOURCE = SpringUtil.getBean(MessageSource.class);
|
||||
private static final Object[] EMPTY_ARGS = {};
|
||||
|
||||
private MessageSourceUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据消息编码获取
|
||||
*
|
||||
* @param code 消息编码
|
||||
* @return 国际化后的消息
|
||||
*/
|
||||
public static String getMessage(String code) {
|
||||
return getMessage(code, EMPTY_ARGS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据消息编码获取
|
||||
*
|
||||
* @param code 消息编码
|
||||
* @param args 参数
|
||||
* @return 国际化后的消息
|
||||
*/
|
||||
public static String getMessage(String code, Object... args) {
|
||||
return getMessage(code, code, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据消息编码获取
|
||||
*
|
||||
* @param code 消息编码
|
||||
* @param defaultMessage 默认消息
|
||||
* @return 国际化后的消息
|
||||
*/
|
||||
public static String getMessage(String code, String defaultMessage) {
|
||||
return getMessage(code, defaultMessage, EMPTY_ARGS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据消息编码获取
|
||||
*
|
||||
* @param code 消息编码
|
||||
* @param defaultMessage 默认消息
|
||||
* @param args 参数
|
||||
* @return 国际化后的消息
|
||||
*/
|
||||
public static String getMessage(String code, String defaultMessage, Object... args) {
|
||||
try {
|
||||
return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
|
||||
} catch (Exception e) {
|
||||
return defaultMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,14 +16,9 @@
|
||||
|
||||
package top.continew.starter.core.util.validate;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import top.continew.starter.core.exception.BadRequestException;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
@@ -178,21 +173,4 @@ public class ValidationUtils extends Validator {
|
||||
public static void throwIf(BooleanSupplier conditionSupplier, String template, Object... params) {
|
||||
throwIf(conditionSupplier, CharSequenceUtil.format(template, params), EXCEPTION_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSR 303 校验
|
||||
*
|
||||
* @param obj 被校验对象
|
||||
* @param groups 分组
|
||||
*/
|
||||
public static void validate(Object obj, Class<?>... groups) {
|
||||
jakarta.validation.Validator validator = SpringUtil.getBean(jakarta.validation.Validator.class);
|
||||
Set<ConstraintViolation<Object>> violations = validator.validate(obj, groups);
|
||||
if (CollUtil.isEmpty(violations)) {
|
||||
return;
|
||||
}
|
||||
throw ReflectUtil.newInstance(EXCEPTION_TYPE, violations.stream()
|
||||
.map(ConstraintViolation::getMessage)
|
||||
.findFirst());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,13 @@ package top.continew.starter.core.util.validate;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
@@ -32,6 +36,8 @@ import java.util.function.BooleanSupplier;
|
||||
*/
|
||||
public class Validator {
|
||||
private static final Logger log = LoggerFactory.getLogger(Validator.class);
|
||||
private static final jakarta.validation.Validator VALIDATOR = SpringUtil
|
||||
.getBean(jakarta.validation.Validator.class);
|
||||
|
||||
protected Validator() {
|
||||
}
|
||||
@@ -195,4 +201,18 @@ public class Validator {
|
||||
throw ReflectUtil.newInstance(exceptionType, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSR 303 校验
|
||||
*
|
||||
* @param obj 被校验对象
|
||||
* @param groups 分组
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public static void validate(Object obj, Class<?>... groups) {
|
||||
Set<ConstraintViolation<Object>> violations = VALIDATOR.validate(obj, groups);
|
||||
if (!violations.isEmpty()) {
|
||||
throw new ConstraintViolationException(violations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
top.continew.starter.core.autoconfigure.project.ProjectAutoConfiguration
|
||||
top.continew.starter.core.autoconfigure.ValidatorAutoConfiguration
|
||||
top.continew.starter.core.autoconfigure.threadpool.ThreadPoolAutoConfiguration
|
||||
top.continew.starter.core.autoconfigure.threadpool.AsyncAutoConfiguration
|
||||
@@ -30,9 +30,7 @@ import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.select.PlainSelect;
|
||||
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
|
||||
import net.sf.jsqlparser.statement.select.SubSelect;
|
||||
import net.sf.jsqlparser.statement.select.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
@@ -124,9 +122,9 @@ public class DataPermissionHandlerImpl implements DataPermissionHandler {
|
||||
private Expression buildDeptAndChildExpression(DataPermission dataPermission,
|
||||
DataPermissionCurrentUser currentUser,
|
||||
Expression expression) {
|
||||
SubSelect subSelect = new SubSelect();
|
||||
ParenthesedSelect subSelect = new ParenthesedSelect();
|
||||
PlainSelect select = new PlainSelect();
|
||||
select.setSelectItems(Collections.singletonList(new SelectExpressionItem(new Column(dataPermission.id()))));
|
||||
select.setSelectItems(Collections.singletonList(new SelectItem<>(new Column(dataPermission.id()))));
|
||||
select.setFromItem(new Table(dataPermission.deptTableAlias()));
|
||||
EqualsTo equalsTo = new EqualsTo();
|
||||
equalsTo.setLeftExpression(new Column(dataPermission.id()));
|
||||
@@ -135,7 +133,7 @@ public class DataPermissionHandlerImpl implements DataPermissionHandler {
|
||||
function.setName("find_in_set");
|
||||
function.setParameters(new ExpressionList(new LongValue(currentUser.getDeptId()), new Column("ancestors")));
|
||||
select.setWhere(new OrExpression(equalsTo, function));
|
||||
subSelect.setSelectBody(select);
|
||||
subSelect.setSelect(select);
|
||||
// 构建父查询
|
||||
InExpression inExpression = new InExpression();
|
||||
inExpression.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.deptId()));
|
||||
@@ -201,15 +199,15 @@ public class DataPermissionHandlerImpl implements DataPermissionHandler {
|
||||
private Expression buildCustomExpression(DataPermission dataPermission,
|
||||
DataPermissionCurrentUser.CurrentUserRole role,
|
||||
Expression expression) {
|
||||
SubSelect subSelect = new SubSelect();
|
||||
ParenthesedSelect subSelect = new ParenthesedSelect();
|
||||
PlainSelect select = new PlainSelect();
|
||||
select.setSelectItems(Collections.singletonList(new SelectExpressionItem(new Column(dataPermission.deptId()))));
|
||||
select.setSelectItems(Collections.singletonList(new SelectItem<>(new Column(dataPermission.deptId()))));
|
||||
select.setFromItem(new Table(dataPermission.roleDeptTableAlias()));
|
||||
EqualsTo equalsTo = new EqualsTo();
|
||||
equalsTo.setLeftExpression(new Column(dataPermission.roleId()));
|
||||
equalsTo.setRightExpression(new LongValue(role.getRoleId()));
|
||||
select.setWhere(equalsTo);
|
||||
subSelect.setSelectBody(select);
|
||||
subSelect.setSelect(select);
|
||||
// 构建父查询
|
||||
InExpression inExpression = new InExpression();
|
||||
inExpression.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.deptId()));
|
||||
|
||||
@@ -36,13 +36,25 @@ import java.util.List;
|
||||
*/
|
||||
public class ServiceImpl<M extends BaseMapper<T>, T> extends com.baomidou.mybatisplus.extension.service.impl.ServiceImpl<M, T> implements IService<T> {
|
||||
|
||||
protected final List<Field> entityFields = ReflectUtils.getNonStaticFields(this.entityClass);
|
||||
private List<Field> entityFields;
|
||||
|
||||
@Override
|
||||
public T getById(Serializable id) {
|
||||
return this.getById(id, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前实体类型字段
|
||||
*
|
||||
* @return 当前实体类型字段列表
|
||||
*/
|
||||
public List<Field> getEntityFields() {
|
||||
if (this.entityFields == null) {
|
||||
this.entityFields = ReflectUtils.getNonStaticFields(this.getEntityClass());
|
||||
}
|
||||
return this.entityFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 ID 查询
|
||||
*
|
||||
@@ -53,7 +65,7 @@ public class ServiceImpl<M extends BaseMapper<T>, T> extends com.baomidou.mybati
|
||||
protected T getById(Serializable id, boolean isCheckExists) {
|
||||
T entity = baseMapper.selectById(id);
|
||||
if (isCheckExists) {
|
||||
CheckUtils.throwIfNotExists(entity, ClassUtil.getClassName(entityClass, true), "ID", id);
|
||||
CheckUtils.throwIfNotExists(entity, ClassUtil.getClassName(this.getEntityClass(), true), "ID", id);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>3.1.11</version>
|
||||
<version>3.2.7</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
@@ -43,46 +43,63 @@
|
||||
|
||||
<properties>
|
||||
<!-- 项目版本号 -->
|
||||
<revision>2.2.0</revision>
|
||||
<revision>2.3.0</revision>
|
||||
<snail-job.version>1.1.0</snail-job.version>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<just-auth.version>1.16.6</just-auth.version>
|
||||
<mybatis-plus.version>3.5.5</mybatis-plus.version>
|
||||
<mybatis-flex.version>1.8.9</mybatis-flex.version>
|
||||
<dynamic-datasource.version>4.3.0</dynamic-datasource.version>
|
||||
<mybatis-plus.version>3.5.7</mybatis-plus.version>
|
||||
<mybatis-flex.version>1.9.3</mybatis-flex.version>
|
||||
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
||||
<p6spy.version>3.9.1</p6spy.version>
|
||||
<jetcache.version>2.7.5</jetcache.version>
|
||||
<redisson.version>3.30.0</redisson.version>
|
||||
<cosid.version>2.6.8</cosid.version>
|
||||
<jetcache.version>2.7.6</jetcache.version>
|
||||
<redisson.version>3.32.0</redisson.version>
|
||||
<cosid.version>2.9.1</cosid.version>
|
||||
<sms4j.version>3.2.1</sms4j.version>
|
||||
<aj-captcha.version>1.3.0</aj-captcha.version>
|
||||
<easy-captcha.version>1.6.2</easy-captcha.version>
|
||||
<easy-excel.version>3.3.4</easy-excel.version>
|
||||
<easy-excel.version>4.0.1</easy-excel.version>
|
||||
<nashorn.version>15.4</nashorn.version>
|
||||
<x-file-storage.version>2.1.0</x-file-storage.version>
|
||||
<aws-s3.version>1.12.720</aws-s3.version>
|
||||
<crane4j.version>2.8.0</crane4j.version>
|
||||
<x-file-storage.version>2.2.0</x-file-storage.version>
|
||||
<aws-s3.version>1.12.761</aws-s3.version>
|
||||
<crane4j.version>2.9.0</crane4j.version>
|
||||
<knife4j.version>4.5.0</knife4j.version>
|
||||
<tlog.version>1.5.2</tlog.version>
|
||||
<snakeyaml.version>2.2</snakeyaml.version>
|
||||
<okhttp.version>4.12.0</okhttp.version>
|
||||
<ttl.version>2.14.5</ttl.version>
|
||||
<ip2region.version>3.1.11</ip2region.version>
|
||||
<hutool.version>5.8.27</hutool.version>
|
||||
<ip2region.version>3.2.6</ip2region.version>
|
||||
<hutool.version>5.8.29</hutool.version>
|
||||
<!-- Maven Plugin Versions -->
|
||||
<flatten.version>1.6.0</flatten.version>
|
||||
<spotless.version>2.43.0</spotless.version>
|
||||
<sonar.version>3.9.1.2184</sonar.version>
|
||||
<sonar.version>3.11.0.3922</sonar.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- SnailJob(灵活,可靠和快速的分布式任务重试和分布式任务调度平台) -->
|
||||
<dependency>
|
||||
<groupId>com.aizuda</groupId>
|
||||
<artifactId>snail-job-client-starter</artifactId>
|
||||
<version>${snail-job.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aizuda</groupId>
|
||||
<artifactId>snail-job-client-retry-core</artifactId>
|
||||
<version>${snail-job.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aizuda</groupId>
|
||||
<artifactId>snail-job-client-job-core</artifactId>
|
||||
<version>${snail-job.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token(轻量级 Java 权限认证框架,让鉴权变得简单、优雅) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<version>${sa-token.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 整合 JWT -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
@@ -152,14 +169,12 @@
|
||||
<artifactId>jetcache-autoconfigure</artifactId>
|
||||
<version>${jetcache.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JetCache 注解 -->
|
||||
<dependency>
|
||||
<groupId>com.alicp.jetcache</groupId>
|
||||
<artifactId>jetcache-anno</artifactId>
|
||||
<version>${jetcache.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JetCache Redisson 适配 -->
|
||||
<dependency>
|
||||
<groupId>com.alicp.jetcache</groupId>
|
||||
|
||||
@@ -110,7 +110,7 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@ResponseBody
|
||||
@GetMapping("/{id}")
|
||||
public R<D> get(@PathVariable Long id) {
|
||||
public R<D> get(@PathVariable("id") Long id) {
|
||||
this.checkPermission(Api.LIST);
|
||||
return R.ok(baseService.get(id));
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@ResponseBody
|
||||
@PutMapping("/{id}")
|
||||
public R<Void> update(@Validated(ValidateGroup.Crud.Update.class) @RequestBody C req, @PathVariable Long id) {
|
||||
public R<Void> update(@Validated(ValidateGroup.Crud.Update.class) @RequestBody C req, @PathVariable("id") Long id) {
|
||||
this.checkPermission(Api.UPDATE);
|
||||
baseService.update(req, id);
|
||||
return R.ok("修改成功");
|
||||
@@ -156,7 +156,7 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
@Parameter(name = "ids", description = "ID 列表", example = "1,2", in = ParameterIn.PATH)
|
||||
@ResponseBody
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> delete(@PathVariable List<Long> ids) {
|
||||
public R<Void> delete(@PathVariable("ids") List<Long> ids) {
|
||||
this.checkPermission(Api.DELETE);
|
||||
baseService.delete(ids);
|
||||
return R.ok("删除成功");
|
||||
|
||||
@@ -110,7 +110,7 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@ResponseBody
|
||||
@GetMapping("/{id}")
|
||||
public R<D> get(@PathVariable Long id) {
|
||||
public R<D> get(@PathVariable("id") Long id) {
|
||||
this.checkPermission(Api.LIST);
|
||||
return R.ok(baseService.get(id));
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@ResponseBody
|
||||
@PutMapping("/{id}")
|
||||
public R<Void> update(@Validated(ValidateGroup.Crud.Update.class) @RequestBody C req, @PathVariable Long id) {
|
||||
public R<Void> update(@Validated(ValidateGroup.Crud.Update.class) @RequestBody C req, @PathVariable("id") Long id) {
|
||||
this.checkPermission(Api.UPDATE);
|
||||
baseService.update(req, id);
|
||||
return R.ok("修改成功");
|
||||
@@ -156,7 +156,7 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
@Parameter(name = "ids", description = "ID 列表", example = "1,2", in = ParameterIn.PATH)
|
||||
@ResponseBody
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> delete(@PathVariable List<Long> ids) {
|
||||
public R<Void> delete(@PathVariable("ids") List<Long> ids) {
|
||||
this.checkPermission(Api.DELETE);
|
||||
baseService.delete(ids);
|
||||
return R.ok("删除成功");
|
||||
|
||||
@@ -68,17 +68,16 @@ import java.util.*;
|
||||
*/
|
||||
public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdDO, L, D, Q, C> extends ServiceImpl<M, T> implements BaseService<L, D, Q, C> {
|
||||
|
||||
private final Class<?>[] typeArgumentCache = ClassUtils.getTypeArguments(this.getClass());
|
||||
protected final Class<L> listClass = this.currentListClass();
|
||||
protected final Class<D> detailClass = this.currentDetailClass();
|
||||
protected final Class<Q> queryClass = this.currentQueryClass();
|
||||
private final List<Field> queryFields = ReflectUtils.getNonStaticFields(this.queryClass);
|
||||
private Class<L> listClass;
|
||||
private Class<D> detailClass;
|
||||
private Class<Q> queryClass;
|
||||
private List<Field> queryFields;
|
||||
|
||||
@Override
|
||||
public PageResp<L> page(Q query, PageQuery pageQuery) {
|
||||
QueryWrapper<T> queryWrapper = this.buildQueryWrapper(query);
|
||||
IPage<T> page = baseMapper.selectPage(pageQuery.toPage(), queryWrapper);
|
||||
PageResp<L> pageResp = PageResp.build(page, listClass);
|
||||
PageResp<L> pageResp = PageResp.build(page, this.getListClass());
|
||||
pageResp.getList().forEach(this::fill);
|
||||
return pageResp;
|
||||
}
|
||||
@@ -91,7 +90,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
}
|
||||
// 如果构建简单树结构,则不包含基本树结构之外的扩展字段
|
||||
TreeNodeConfig treeNodeConfig = TreeUtils.DEFAULT_CONFIG;
|
||||
TreeField treeField = listClass.getDeclaredAnnotation(TreeField.class);
|
||||
TreeField treeField = this.getListClass().getDeclaredAnnotation(TreeField.class);
|
||||
if (!isSimple) {
|
||||
// 根据 @TreeField 配置生成树结构配置
|
||||
treeNodeConfig = TreeUtils.genTreeNodeConfig(treeField);
|
||||
@@ -104,7 +103,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey())));
|
||||
tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.weightKey())));
|
||||
if (!isSimple) {
|
||||
List<Field> fieldList = ReflectUtils.getNonStaticFields(listClass);
|
||||
List<Field> fieldList = ReflectUtils.getNonStaticFields(this.getListClass());
|
||||
fieldList.removeIf(f -> CharSequenceUtil.equalsAnyIgnoreCase(f.getName(), treeField.value(), treeField
|
||||
.parentIdKey(), treeField.nameKey(), treeField.weightKey(), treeField.childrenKey()));
|
||||
fieldList.forEach(f -> tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f
|
||||
@@ -115,7 +114,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
|
||||
@Override
|
||||
public List<L> list(Q query, SortQuery sortQuery) {
|
||||
List<L> list = this.list(query, sortQuery, listClass);
|
||||
List<L> list = this.list(query, sortQuery, this.getListClass());
|
||||
list.forEach(this::fill);
|
||||
return list;
|
||||
}
|
||||
@@ -123,7 +122,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
@Override
|
||||
public D get(Long id) {
|
||||
T entity = super.getById(id, false);
|
||||
D detail = BeanUtil.toBean(entity, detailClass);
|
||||
D detail = BeanUtil.toBean(entity, this.getDetailClass());
|
||||
this.fill(detail);
|
||||
return detail;
|
||||
}
|
||||
@@ -132,15 +131,15 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
public List<LabelValueResp> listDict(Q query, SortQuery sortQuery) {
|
||||
QueryWrapper<T> queryWrapper = this.buildQueryWrapper(query);
|
||||
this.sort(queryWrapper, sortQuery);
|
||||
DictField dictField = entityClass.getDeclaredAnnotation(DictField.class);
|
||||
DictField dictField = super.getEntityClass().getDeclaredAnnotation(DictField.class);
|
||||
CheckUtils.throwIfNull(dictField, "请添加并配置 @DictField 字典结构信息");
|
||||
// 指定查询字典字段
|
||||
queryWrapper.select(dictField.labelKey(), dictField.valueKey());
|
||||
List<T> entityList = baseMapper.selectList(queryWrapper);
|
||||
// 解析映射
|
||||
Map<String, String> fieldMapping = MapUtil.newHashMap(2);
|
||||
fieldMapping.put(dictField.labelKey(), "label");
|
||||
fieldMapping.put(dictField.valueKey(), "value");
|
||||
fieldMapping.put(CharSequenceUtil.toCamelCase(dictField.labelKey()), "label");
|
||||
fieldMapping.put(CharSequenceUtil.toCamelCase(dictField.valueKey()), "value");
|
||||
return BeanUtil.copyToList(entityList, LabelValueResp.class, CopyOptions.create()
|
||||
.setFieldMapping(fieldMapping));
|
||||
}
|
||||
@@ -149,7 +148,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long add(C req) {
|
||||
this.beforeAdd(req);
|
||||
T entity = BeanUtil.copyProperties(req, entityClass);
|
||||
T entity = BeanUtil.copyProperties(req, super.getEntityClass());
|
||||
baseMapper.insert(entity);
|
||||
this.afterAdd(req, entity);
|
||||
return entity.getId();
|
||||
@@ -169,15 +168,63 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(List<Long> ids) {
|
||||
this.beforeDelete(ids);
|
||||
baseMapper.deleteBatchIds(ids);
|
||||
baseMapper.deleteByIds(ids);
|
||||
this.afterDelete(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void export(Q query, SortQuery sortQuery, HttpServletResponse response) {
|
||||
List<D> list = this.list(query, sortQuery, detailClass);
|
||||
List<D> list = this.list(query, sortQuery, this.getDetailClass());
|
||||
list.forEach(this::fill);
|
||||
ExcelUtils.export(list, "导出数据", detailClass, response);
|
||||
ExcelUtils.export(list, "导出数据", this.getDetailClass(), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前列表信息类型
|
||||
*
|
||||
* @return 当前列表信息类型
|
||||
*/
|
||||
public Class<L> getListClass() {
|
||||
if (this.listClass == null) {
|
||||
this.listClass = (Class<L>)ClassUtils.getTypeArguments(this.getClass())[2];
|
||||
}
|
||||
return this.listClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前详情信息类型
|
||||
*
|
||||
* @return 当前详情信息类型
|
||||
*/
|
||||
public Class<D> getDetailClass() {
|
||||
if (this.detailClass == null) {
|
||||
this.detailClass = (Class<D>)ClassUtils.getTypeArguments(this.getClass())[3];
|
||||
}
|
||||
return this.detailClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前查询条件类型
|
||||
*
|
||||
* @return 当前查询条件类型
|
||||
*/
|
||||
public Class<Q> getQueryClass() {
|
||||
if (this.queryClass == null) {
|
||||
this.queryClass = (Class<Q>)ClassUtils.getTypeArguments(this.getClass())[4];
|
||||
}
|
||||
return this.queryClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前查询条件类型字段
|
||||
*
|
||||
* @return 当前查询条件类型字段列表
|
||||
*/
|
||||
public List<Field> getQueryFields() {
|
||||
if (this.queryFields == null) {
|
||||
this.queryFields = ReflectUtils.getNonStaticFields(this.getQueryClass());
|
||||
}
|
||||
return queryFields;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +240,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
// 设置排序
|
||||
this.sort(queryWrapper, sortQuery);
|
||||
List<T> entityList = baseMapper.selectList(queryWrapper);
|
||||
if (entityClass == targetClass) {
|
||||
if (super.getEntityClass() == targetClass) {
|
||||
return (List<E>)entityList;
|
||||
}
|
||||
return BeanUtil.copyToList(entityList, targetClass);
|
||||
@@ -217,7 +264,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
} else {
|
||||
checkProperty = property;
|
||||
}
|
||||
Optional<Field> optional = entityFields.stream()
|
||||
Optional<Field> optional = super.getEntityFields().stream()
|
||||
.filter(field -> checkProperty.equals(field.getName()))
|
||||
.findFirst();
|
||||
ValidationUtils.throwIf(optional.isEmpty(), "无效的排序字段 [{}]", property);
|
||||
@@ -248,7 +295,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
protected QueryWrapper<T> buildQueryWrapper(Q query) {
|
||||
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
|
||||
// 解析并拼接查询条件
|
||||
return QueryWrapperHelper.build(query, queryFields, queryWrapper);
|
||||
return QueryWrapperHelper.build(query, this.getQueryFields(), queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,31 +354,4 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
protected void afterDelete(List<Long> ids) {
|
||||
/* 删除后置处理 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前列表信息类型
|
||||
*
|
||||
* @return 当前列表信息类型
|
||||
*/
|
||||
protected Class<L> currentListClass() {
|
||||
return (Class<L>)this.typeArgumentCache[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前详情信息类型
|
||||
*
|
||||
* @return 当前详情信息类型
|
||||
*/
|
||||
protected Class<D> currentDetailClass() {
|
||||
return (Class<D>)this.typeArgumentCache[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前查询条件类型
|
||||
*
|
||||
* @return 当前查询条件类型
|
||||
*/
|
||||
protected Class<Q> currentQueryClass() {
|
||||
return (Class<Q>)this.typeArgumentCache[4];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import top.continew.starter.core.exception.GlobalException;
|
||||
import top.continew.starter.core.exception.ResultInfoInterface;
|
||||
import top.continew.starter.web.autoconfigure.i18n.I18nProperties;
|
||||
import top.continew.starter.web.model.R;
|
||||
import top.continew.starter.web.util.MessageSourceUtils;
|
||||
import top.continew.starter.core.util.MessageSourceUtils;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
@@ -130,14 +130,14 @@ public class GlobalExceptionHandler {
|
||||
msg = msg.concat(cause.getMessage().toLowerCase());
|
||||
}
|
||||
if (msg.contains("size") && msg.contains("exceed")) {
|
||||
sizeLimit = CharSequenceUtil.subBetween(msg, "maximum (", ")");
|
||||
sizeLimit = CharSequenceUtil.subBetween(msg, "the maximum size ", " for");
|
||||
} else if (msg.contains("larger than")) {
|
||||
sizeLimit = CharSequenceUtil.subAfter(msg, "larger than ", true);
|
||||
} else {
|
||||
return defaultFail;
|
||||
}
|
||||
|
||||
String errorMsg = "请上传小于 %sMB 的文件".formatted(NumberUtil.parseLong(sizeLimit) / 1024 / 1024);
|
||||
String errorMsg = "请上传小于 %sKB 的文件".formatted(NumberUtil.parseLong(sizeLimit) / 1024);
|
||||
log.warn("请求地址 [{}],上传文件失败,文件大小超过限制。", request.getRequestURI(), e);
|
||||
return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg);
|
||||
}
|
||||
|
||||
@@ -17,20 +17,13 @@
|
||||
package top.continew.starter.web.autoconfigure.exception;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;
|
||||
import top.continew.starter.web.autoconfigure.i18n.I18nProperties;
|
||||
|
||||
/**
|
||||
@@ -47,25 +40,6 @@ public class GlobalExceptionHandlerAutoConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandlerAutoConfiguration.class);
|
||||
|
||||
/**
|
||||
* Validator 失败立即返回模式配置
|
||||
*
|
||||
* <p>
|
||||
* 默认情况下会校验完所有字段,然后才抛出异常。
|
||||
* </p>
|
||||
*/
|
||||
@Bean
|
||||
public Validator validator(AutowireCapableBeanFactory beanFactory) {
|
||||
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
|
||||
.configure()
|
||||
.failFast(true)
|
||||
.constraintValidatorFactory(new SpringConstraintValidatorFactory(beanFactory))
|
||||
.buildValidatorFactory();
|
||||
try (validatorFactory) {
|
||||
return validatorFactory.getValidator();
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Web-Global Exception Handler' completed initialization.");
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.web.util;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
/**
|
||||
* @author Jasmine
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class MessageSourceUtils {
|
||||
|
||||
private static final MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
|
||||
|
||||
private static final Object[] emptyArray = new Object[] {};
|
||||
|
||||
public static String getMessage(String key) {
|
||||
return getMessage(key, emptyArray);
|
||||
}
|
||||
|
||||
public static String getMessage(String key, String defaultMessage) {
|
||||
return getMessage(key, defaultMessage, emptyArray);
|
||||
}
|
||||
|
||||
public static String getMessage(String msgKey, Object... args) {
|
||||
return getMessage(msgKey, msgKey, args);
|
||||
}
|
||||
|
||||
public static String getMessage(String msgKey, String defaultMessage, Object... args) {
|
||||
try {
|
||||
return messageSource.getMessage(msgKey, args, LocaleContextHolder.getLocale());
|
||||
} catch (Exception e) {
|
||||
return defaultMessage;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user