mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-11-13 04:57:13 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c72259028f | |||
| 5f6822742f | |||
| aa463dff37 | |||
| 4fe067a889 | |||
| 0b342d5c73 | |||
| 31e1d52ea4 | |||
| 279d72b724 | |||
| 80c0700934 | |||
|
|
b9779e8944 | ||
| a6c9d33024 | |||
| eb2cac54f7 | |||
| 13f606f631 | |||
| 0ea8f77d8a |
38
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
38
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -6,6 +6,26 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
感谢您使用 ContiNew Starter!请您花些时间填写这份 Bug 报告。
|
感谢您使用 ContiNew Starter!请您花些时间填写这份 Bug 报告。
|
||||||
|
- type: checkboxes
|
||||||
|
id: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: 请您确认
|
||||||
|
description: 在提交 Issue 之前,请确保执行过以下操作。
|
||||||
|
options:
|
||||||
|
- label: 尝试[最新版本](https://central.sonatype.com/artifact/top.continew/continew-starter/versions),仍有相同问题
|
||||||
|
required: true
|
||||||
|
- label: 阅读[使用指南](https://continew.top/starter/intro/what-is.html)
|
||||||
|
required: true
|
||||||
|
- label: 查找[常见问题](https://continew.top/faq.html)
|
||||||
|
required: true
|
||||||
|
- label: 根据报错信息(自行翻译英文)百度或 Google 一下
|
||||||
|
required: true
|
||||||
|
- label: 阅读源码并在 IDE 中进行断点调试
|
||||||
|
required: false
|
||||||
|
- label: 搜索是否有其他人提交过类似的 Issue,如果对应 Issue 尚未解决,您可以先订阅关注该 Issue(为了方便后来者查找问题解决方法,请尽量避免创建重复的 Issue)
|
||||||
|
required: true
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: bug-description
|
id: bug-description
|
||||||
attributes:
|
attributes:
|
||||||
@@ -43,21 +63,3 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: 额外补充
|
label: 额外补充
|
||||||
description: 添加您的完整报错信息或屏幕截图,以及一切能帮助定位问题的信息。
|
description: 添加您的完整报错信息或屏幕截图,以及一切能帮助定位问题的信息。
|
||||||
- type: checkboxes
|
|
||||||
id: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: 确认
|
|
||||||
description: 在提交 Issue 之前,请确保执行过以下操作。
|
|
||||||
options:
|
|
||||||
- label: 尝试[最新版本](https://central.sonatype.com/artifact/top.continew/continew-starter/versions),仍有相同问题
|
|
||||||
required: true
|
|
||||||
- label: 阅读[使用指南](https://continew.top/starter/intro/what-is.html)
|
|
||||||
required: true
|
|
||||||
- label: 查找[常见问题](https://continew.top/faq.html)
|
|
||||||
required: true
|
|
||||||
- label: 根据报错信息(自行翻译英文)百度或 Google 一下
|
|
||||||
required: true
|
|
||||||
- label: 阅读源码并在 IDE 中进行断点调试
|
|
||||||
required: false
|
|
||||||
- label: 搜索是否有其他人提交过类似的 Issue,如果对应 Issue 尚未解决,您可以先订阅关注该 Issue(为了方便后来者查找问题解决方法,请尽量避免创建重复的 Issue)
|
|
||||||
required: true
|
|
||||||
34
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
34
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -5,6 +5,24 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
感谢您使用 ContiNew Starter!请您花些时间填写这份 Feature 调查。
|
感谢您使用 ContiNew Starter!请您花些时间填写这份 Feature 调查。
|
||||||
|
- type: checkboxes
|
||||||
|
id: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: 请您确认
|
||||||
|
description: 在提交 Feature 之前,请确保执行过以下操作。
|
||||||
|
options:
|
||||||
|
- label: 阅读[使用指南](https://continew.top/starter/intro/what-is.html)
|
||||||
|
required: true
|
||||||
|
- label: 查找[常见问题](https://continew.top/faq.html)
|
||||||
|
required: true
|
||||||
|
- label: 查看[需求墙](https://continew.top/require.html)计划
|
||||||
|
required: true
|
||||||
|
- label: 搜索是否有其他人提交过类似的 Feature,如果对应 Feature 尚未完成,您可以先订阅关注该 Feature(为了方便后来者查找问题解决方法,请尽量避免创建重复的 Feature)
|
||||||
|
required: true
|
||||||
|
- label: 您是否愿意为您提出的 Feature 提交 PR?
|
||||||
|
required: false
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: feature-description
|
id: feature-description
|
||||||
attributes:
|
attributes:
|
||||||
@@ -30,19 +48,3 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: 额外补充
|
label: 额外补充
|
||||||
description: 添加您在其他框架或场景遇见的效果截图或链接,以及一切能帮助理解 Feature 的信息。
|
description: 添加您在其他框架或场景遇见的效果截图或链接,以及一切能帮助理解 Feature 的信息。
|
||||||
- type: checkboxes
|
|
||||||
id: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: 确认
|
|
||||||
description: 在提交 Feature 之前,请确保执行过以下操作。
|
|
||||||
options:
|
|
||||||
- label: 阅读[使用指南](https://continew.top/starter/intro/what-is.html)
|
|
||||||
required: true
|
|
||||||
- label: 查找[常见问题](https://continew.top/faq.html)
|
|
||||||
required: true
|
|
||||||
- label: 查看[需求墙](https://continew.top/require.html)计划
|
|
||||||
required: true
|
|
||||||
- label: 搜索是否有其他人提交过类似的 Feature,如果对应 Feature 尚未完成,您可以先订阅关注该 Feature(为了方便后来者查找问题解决方法,请尽量避免创建重复的 Feature)
|
|
||||||
required: true
|
|
||||||
- label: 您是否愿意为您提出的 Feature 提交 PR?
|
|
||||||
required: false
|
|
||||||
34
CHANGELOG.md
34
CHANGELOG.md
@@ -1,3 +1,37 @@
|
|||||||
|
## [v2.8.2](https://github.com/continew-org/continew-starter/compare/v2.8.1...v2.8.2) (2025-01-09)
|
||||||
|
|
||||||
|
### ✨ 新特性
|
||||||
|
|
||||||
|
- 【core】SpringUtils 新增获取代理对象方法 ([5f68227](https://github.com/continew-org/continew-starter/commit/5f6822742fd0f032bcc351155f0b966d24b05346))
|
||||||
|
|
||||||
|
### 💎 功能优化
|
||||||
|
|
||||||
|
- 【extension/crud】移除 CommonUserService、ContainerPool(已移动到 Admin 项目内) ([0b342d5](https://github.com/continew-org/continew-starter/commit/0b342d5c73e95b809337b939b4e1e957374bad85))
|
||||||
|
|
||||||
|
### 🐛 问题修复
|
||||||
|
|
||||||
|
- 【log】修复日志记录时所属模块和描述取值优先级失效的问题 ([4fe067a](https://github.com/continew-org/continew-starter/commit/4fe067a889f00617f03caf7ae3598466560dce33))
|
||||||
|
|
||||||
|
### 📦 依赖升级
|
||||||
|
|
||||||
|
- graceful-response 5.0.4-boot3 => 5.0.5-boot3(修复父类参数校验异常) ([aa463df](https://github.com/continew-org/continew-starter/commit/aa463dff37b658d1cb2a69e68f54790e03c4103d))
|
||||||
|
|
||||||
|
## [v2.8.1](https://github.com/continew-org/continew-starter/compare/v2.8.0...v2.8.1) (2025-01-06)
|
||||||
|
|
||||||
|
### ✨ 新特性
|
||||||
|
|
||||||
|
- 【core】BaseEnum 新增 getByValue、getByDescription、isValidValue 方法 ([279d72b](https://github.com/continew-org/continew-starter/commit/279d72b7242bf996f9b88d38ed0ea7aa0a0d1c46))
|
||||||
|
|
||||||
|
### 💎 功能优化
|
||||||
|
|
||||||
|
- 【extension/crud】移除 BaseResp、BaseDetailResp(已移动到 Admin 项目内) ([eb2cac5](https://github.com/continew-org/continew-starter/commit/eb2cac54f75b2850f2957b32190d12e63377c185))
|
||||||
|
- 【log】优化日志处理器解析 description、module 方法 ([a6c9d33](https://github.com/continew-org/continew-starter/commit/a6c9d33024ea70bb3dbe11981cbc9a3f9027bcd2))
|
||||||
|
- 解决 Sonar 问题,替换部分过期 API ([80c0700](https://github.com/continew-org/continew-starter/commit/80c070093498abb8dff5529d177e1e2519577bf0))
|
||||||
|
|
||||||
|
### 🐛 问题修复
|
||||||
|
|
||||||
|
- 【file/excel】优化 BaseEnum 转换器 (GitHub#10@Solution-Lin) ([b9779e8](https://github.com/continew-org/continew-starter/commit/b9779e894464ec534bebdd230a7239b6d1964ddb))
|
||||||
|
|
||||||
## [v2.8.0](https://github.com/continew-org/continew-starter/compare/v2.7.5...v2.8.0) (2024-12-25)
|
## [v2.8.0](https://github.com/continew-org/continew-starter/compare/v2.7.5...v2.8.0) (2024-12-25)
|
||||||
|
|
||||||
### ✨ 新特性
|
### ✨ 新特性
|
||||||
|
|||||||
@@ -26,10 +26,10 @@
|
|||||||
<img src="https://img.shields.io/github/forks/continew-org/continew-starter?style=social" alt="GitHub Forks" />
|
<img src="https://img.shields.io/github/forks/continew-org/continew-starter?style=social" alt="GitHub Forks" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://gitee.com/continew/continew-starter" title="Gitee Stars" target="_blank">
|
<a href="https://gitee.com/continew/continew-starter" title="Gitee Stars" target="_blank">
|
||||||
<img src="https://gitee.com/continew/continew-starter/badge/star.svg?theme=white" alt="Gitee Stars" />
|
<img src="https://gitee.com/continew/continew-starter/badge/star.svg?theme=dark" alt="Gitee Stars" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://gitee.com/continew/continew-starter" title="Gitee Forks" target="_blank">
|
<a href="https://gitee.com/continew/continew-starter" title="Gitee Forks" target="_blank">
|
||||||
<img src="https://gitee.com/continew/continew-starter/badge/fork.svg?theme=white" alt="Gitee Forks" />
|
<img src="https://gitee.com/continew/continew-starter/badge/fork.svg?theme=dark" alt="Gitee Forks" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://gitcode.com/continew/continew-starter" title="GitCode Stars" target="_blank">
|
<a href="https://gitcode.com/continew/continew-starter" title="GitCode Stars" target="_blank">
|
||||||
<img src="https://gitcode.com/continew/continew-starter/star/badge.svg" alt="GitCode Stars" />
|
<img src="https://gitcode.com/continew/continew-starter/star/badge.svg" alt="GitCode Stars" />
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import org.springdoc.core.service.SecurityService;
|
|||||||
import org.springdoc.core.utils.PropertyResolverUtils;
|
import org.springdoc.core.utils.PropertyResolverUtils;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
@@ -152,7 +151,7 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
if (this.openAPI.getPaths() == null) {
|
if (this.openAPI.getPaths() == null) {
|
||||||
this.openAPI.setPaths(new Paths());
|
this.openAPI.setPaths(new Paths());
|
||||||
}
|
}
|
||||||
if (!CollectionUtils.isEmpty(this.openAPI.getServers())) {
|
if (CollUtil.isNotEmpty(this.openAPI.getServers())) {
|
||||||
this.isServersPresent = true;
|
this.isServersPresent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,7 +175,7 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale);
|
buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale);
|
||||||
buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale);
|
buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale);
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(tagsStr)) {
|
if (CollUtil.isNotEmpty(tagsStr)) {
|
||||||
tagsStr = tagsStr.stream()
|
tagsStr = tagsStr.stream()
|
||||||
.map(str -> propertyResolverUtils.resolve(str, locale))
|
.map(str -> propertyResolverUtils.resolve(str, locale))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
@@ -190,8 +189,8 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(tagsStr)) {
|
if (CollUtil.isNotEmpty(tagsStr)) {
|
||||||
if (CollectionUtils.isEmpty(operation.getTags())) {
|
if (CollUtil.isEmpty(operation.getTags())) {
|
||||||
operation.setTags(new ArrayList<>(tagsStr));
|
operation.setTags(new ArrayList<>(tagsStr));
|
||||||
} else {
|
} else {
|
||||||
Set<String> operationTagsSet = new HashSet<>(operation.getTags());
|
Set<String> operationTagsSet = new HashSet<>(operation.getTags());
|
||||||
@@ -225,10 +224,10 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(tags)) {
|
if (CollUtil.isNotEmpty(tags)) {
|
||||||
// Existing tags
|
// Existing tags
|
||||||
List<Tag> openApiTags = openAPI.getTags();
|
List<Tag> openApiTags = openAPI.getTags();
|
||||||
if (!CollectionUtils.isEmpty(openApiTags)) {
|
if (CollUtil.isNotEmpty(openApiTags)) {
|
||||||
tags.addAll(openApiTags);
|
tags.addAll(openApiTags);
|
||||||
}
|
}
|
||||||
openAPI.setTags(new ArrayList<>(tags));
|
openAPI.setTags(new ArrayList<>(tags));
|
||||||
@@ -256,7 +255,7 @@ public class OpenApiHandler extends OpenAPIService {
|
|||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
methodTags.addAll(AnnotatedElementUtils
|
methodTags.addAll(AnnotatedElementUtils
|
||||||
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class));
|
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class));
|
||||||
if (!CollectionUtils.isEmpty(methodTags)) {
|
if (CollUtil.isNotEmpty(methodTags)) {
|
||||||
tagsStr.addAll(toSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale)));
|
tagsStr.addAll(toSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale)));
|
||||||
List<io.swagger.v3.oas.annotations.tags.Tag> allTags = new ArrayList<>(methodTags);
|
List<io.swagger.v3.oas.annotations.tags.Tag> allTags = new ArrayList<>(methodTags);
|
||||||
addTags(allTags, tags, locale);
|
addTags(allTags, tags, locale);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package top.continew.starter.cache.redisson.util;
|
|||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import org.redisson.api.*;
|
import org.redisson.api.*;
|
||||||
|
import org.redisson.api.options.KeysScanOptions;
|
||||||
import top.continew.starter.core.constant.StringConstants;
|
import top.continew.starter.core.constant.StringConstants;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -191,7 +192,9 @@ public class RedisUtils {
|
|||||||
* @return 缓存列表
|
* @return 缓存列表
|
||||||
*/
|
*/
|
||||||
public static Collection<String> keys(String pattern) {
|
public static Collection<String> keys(String pattern) {
|
||||||
return CLIENT.getKeys().getKeysStreamByPattern(pattern).toList();
|
KeysScanOptions options = KeysScanOptions.defaults();
|
||||||
|
options.pattern(pattern);
|
||||||
|
return CLIENT.getKeys().getKeysStream(options).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,8 +368,21 @@ public class RedisUtils {
|
|||||||
* @return true:成功;false:失败
|
* @return true:成功;false:失败
|
||||||
*/
|
*/
|
||||||
public static boolean rateLimit(String key, RateType rateType, int rate, int rateInterval) {
|
public static boolean rateLimit(String key, RateType rateType, int rate, int rateInterval) {
|
||||||
|
return rateLimit(key, rateType, rate, Duration.ofSeconds(rateInterval));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @param rateType 限流类型(OVERALL:全局限流;PER_CLIENT:单机限流)
|
||||||
|
* @param rate 速率(指定时间间隔产生的令牌数)
|
||||||
|
* @param rateInterval 速率间隔(时间间隔)
|
||||||
|
* @return true:成功;false:失败
|
||||||
|
*/
|
||||||
|
public static boolean rateLimit(String key, RateType rateType, int rate, Duration rateInterval) {
|
||||||
RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
|
RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
|
||||||
rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);
|
rateLimiter.trySetRate(rateType, rate, rateInterval);
|
||||||
return rateLimiter.tryAcquire(1);
|
return rateLimiter.tryAcquire(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ public class AsyncAutoConfiguration implements AsyncConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||||
return (throwable, method, objects) -> {
|
return (throwable, method, objects) -> {
|
||||||
throwable.printStackTrace();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("Exception message: ")
|
sb.append("Exception message: ")
|
||||||
.append(throwable.getMessage())
|
.append(throwable.getMessage())
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package top.continew.starter.core.enums;
|
package top.continew.starter.core.enums;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 枚举接口
|
* 枚举接口
|
||||||
@@ -49,4 +50,50 @@ public interface BaseEnum<T extends Serializable> {
|
|||||||
default String getColor() {
|
default String getColor() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据枚举值获取
|
||||||
|
*
|
||||||
|
* @param value 枚举值
|
||||||
|
* @param clazz 枚举类
|
||||||
|
* @return 枚举对象
|
||||||
|
* @since 2.8.1
|
||||||
|
*/
|
||||||
|
static <E extends Enum<E> & BaseEnum, T> E getByValue(T value, Class<E> clazz) {
|
||||||
|
for (E e : clazz.getEnumConstants()) {
|
||||||
|
if (Objects.equals(e.getValue(), value)) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据枚举描述获取
|
||||||
|
*
|
||||||
|
* @param description 枚举描述
|
||||||
|
* @param clazz 枚举类
|
||||||
|
* @return 枚举对象
|
||||||
|
* @since 2.8.1
|
||||||
|
*/
|
||||||
|
static <E extends Enum<E> & BaseEnum> E getByDescription(String description, Class<?> clazz) {
|
||||||
|
for (Object e : clazz.getEnumConstants()) {
|
||||||
|
if (e instanceof BaseEnum<?> baseEnum && Objects.equals(baseEnum.getDescription(), description)) {
|
||||||
|
return (E)baseEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断枚举值是否有效
|
||||||
|
*
|
||||||
|
* @param value 枚举值
|
||||||
|
* @param clazz 枚举类
|
||||||
|
* @return 是否有效
|
||||||
|
* @since 2.8.1
|
||||||
|
*/
|
||||||
|
static <E extends Enum<E> & BaseEnum, T> boolean isValidValue(T value, Class<E> clazz) {
|
||||||
|
return getByValue(value, clazz) != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,21 +14,30 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package top.continew.starter.extension.crud.constant;
|
package top.continew.starter.core.util;
|
||||||
|
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据源容器相关常量(Crane4j 数据填充组件使用)
|
* Spring 工具类
|
||||||
*
|
*
|
||||||
* @author Charles7c
|
* @author Charles7c
|
||||||
* @since 1.2.0
|
* @since 2.8.2
|
||||||
*/
|
*/
|
||||||
public class ContainerPool {
|
public class SpringUtils {
|
||||||
|
|
||||||
|
private SpringUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户昵称
|
* 获取代理对象
|
||||||
|
*
|
||||||
|
* @param target 目标对象
|
||||||
|
* @param <T> 目标对象类型
|
||||||
|
* @return 代理对象
|
||||||
|
* @since 2.8.2
|
||||||
*/
|
*/
|
||||||
public static final String USER_NICKNAME = "UserNickname";
|
public static <T> T getProxy(T target) {
|
||||||
|
return (T)SpringUtil.getBean(target.getClass());
|
||||||
protected ContainerPool() {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,12 +183,11 @@ public class QueryWrapperHelper {
|
|||||||
* @param queryType 查询类型
|
* @param queryType 查询类型
|
||||||
* @param columnName 列名
|
* @param columnName 列名
|
||||||
* @param fieldValue 字段值
|
* @param fieldValue 字段值
|
||||||
* @param <R> 查询数据类型
|
|
||||||
*/
|
*/
|
||||||
private static <R> void parse(QueryType queryType,
|
private static void parse(QueryType queryType,
|
||||||
String columnName,
|
String columnName,
|
||||||
Object fieldValue,
|
Object fieldValue,
|
||||||
List<Consumer<QueryWrapper>> consumers) {
|
List<Consumer<QueryWrapper>> consumers) {
|
||||||
switch (queryType) {
|
switch (queryType) {
|
||||||
case EQ -> consumers.add(q -> q.eq(columnName, fieldValue));
|
case EQ -> consumers.add(q -> q.eq(columnName, fieldValue));
|
||||||
case NE -> consumers.add(q -> q.ne(columnName, fieldValue));
|
case NE -> consumers.add(q -> q.ne(columnName, fieldValue));
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<!-- 项目版本号 -->
|
<!-- 项目版本号 -->
|
||||||
<revision>2.8.0</revision>
|
<revision>2.8.2</revision>
|
||||||
<snail-job.version>1.2.0</snail-job.version>
|
<snail-job.version>1.2.0</snail-job.version>
|
||||||
<sa-token.version>1.39.0</sa-token.version>
|
<sa-token.version>1.39.0</sa-token.version>
|
||||||
<just-auth.version>1.16.7</just-auth.version>
|
<just-auth.version>1.16.7</just-auth.version>
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
<nashorn.version>15.5</nashorn.version>
|
<nashorn.version>15.5</nashorn.version>
|
||||||
<x-file-storage.version>2.2.1</x-file-storage.version>
|
<x-file-storage.version>2.2.1</x-file-storage.version>
|
||||||
<aws-s3.version>1.12.780</aws-s3.version>
|
<aws-s3.version>1.12.780</aws-s3.version>
|
||||||
<graceful-response.version>5.0.4-boot3</graceful-response.version>
|
<graceful-response.version>5.0.5-boot3</graceful-response.version>
|
||||||
<crane4j.version>2.9.0</crane4j.version>
|
<crane4j.version>2.9.0</crane4j.version>
|
||||||
<knife4j.version>4.5.0</knife4j.version>
|
<knife4j.version>4.5.0</knife4j.version>
|
||||||
<tlog.version>1.5.2</tlog.version>
|
<tlog.version>1.5.2</tlog.version>
|
||||||
|
|||||||
@@ -1,86 +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.extension.crud.model.resp;
|
|
||||||
|
|
||||||
import cn.crane4j.annotation.Assemble;
|
|
||||||
import cn.crane4j.annotation.Mapping;
|
|
||||||
import cn.crane4j.annotation.condition.ConditionOnPropertyNotNull;
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import top.continew.starter.extension.crud.constant.ContainerPool;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 详情响应基类
|
|
||||||
*
|
|
||||||
* @author Charles7c
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class BaseDetailResp extends BaseResp {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改人
|
|
||||||
*/
|
|
||||||
@JsonIgnore
|
|
||||||
@ConditionOnPropertyNotNull
|
|
||||||
@Assemble(container = ContainerPool.USER_NICKNAME, props = @Mapping(ref = "updateUserString"))
|
|
||||||
private Long updateUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改人
|
|
||||||
*/
|
|
||||||
@Schema(description = "修改人", example = "李四")
|
|
||||||
@ExcelProperty(value = "修改人", order = Integer.MAX_VALUE - 2)
|
|
||||||
private String updateUserString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改时间
|
|
||||||
*/
|
|
||||||
@Schema(description = "修改时间", example = "2023-08-08 08:08:08", type = "string")
|
|
||||||
@ExcelProperty(value = "修改时间", order = Integer.MAX_VALUE - 1)
|
|
||||||
private LocalDateTime updateTime;
|
|
||||||
|
|
||||||
public Long getUpdateUser() {
|
|
||||||
return updateUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdateUser(Long updateUser) {
|
|
||||||
this.updateUser = updateUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUpdateUserString() {
|
|
||||||
return updateUserString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdateUserString(String updateUserString) {
|
|
||||||
this.updateUserString = updateUserString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDateTime getUpdateTime() {
|
|
||||||
return updateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdateTime(LocalDateTime updateTime) {
|
|
||||||
this.updateTime = updateTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,116 +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.extension.crud.model.resp;
|
|
||||||
|
|
||||||
import cn.crane4j.annotation.Assemble;
|
|
||||||
import cn.crane4j.annotation.Mapping;
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import top.continew.starter.extension.crud.constant.ContainerPool;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 响应参数基类
|
|
||||||
*
|
|
||||||
* @author Charles7c
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class BaseResp implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ID
|
|
||||||
*/
|
|
||||||
@Schema(description = "ID", example = "1")
|
|
||||||
@ExcelProperty(value = "ID", order = 1)
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建人
|
|
||||||
*/
|
|
||||||
@JsonIgnore
|
|
||||||
@Assemble(container = ContainerPool.USER_NICKNAME, props = @Mapping(ref = "createUserString"))
|
|
||||||
private Long createUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建人
|
|
||||||
*/
|
|
||||||
@Schema(description = "创建人", example = "超级管理员")
|
|
||||||
@ExcelProperty(value = "创建人", order = Integer.MAX_VALUE - 4)
|
|
||||||
private String createUserString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建时间
|
|
||||||
*/
|
|
||||||
@Schema(description = "创建时间", example = "2023-08-08 08:08:08", type = "string")
|
|
||||||
@ExcelProperty(value = "创建时间", order = Integer.MAX_VALUE - 3)
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否禁用修改
|
|
||||||
*/
|
|
||||||
@Schema(description = "是否禁用修改", example = "true")
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
private Boolean disabled;
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getCreateUser() {
|
|
||||||
return createUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreateUser(Long createUser) {
|
|
||||||
this.createUser = createUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCreateUserString() {
|
|
||||||
return createUserString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreateUserString(String createUserString) {
|
|
||||||
this.createUserString = createUserString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDateTime getCreateTime() {
|
|
||||||
return createTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreateTime(LocalDateTime createTime) {
|
|
||||||
this.createTime = createTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getDisabled() {
|
|
||||||
return disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisabled(Boolean disabled) {
|
|
||||||
this.disabled = disabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +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.extension.crud.service;
|
|
||||||
|
|
||||||
import cn.crane4j.annotation.ContainerMethod;
|
|
||||||
import cn.crane4j.annotation.MappingType;
|
|
||||||
import top.continew.starter.extension.crud.constant.ContainerPool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 公共用户业务接口
|
|
||||||
*
|
|
||||||
* @author Charles7c
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public interface CommonUserService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 ID 查询昵称
|
|
||||||
*
|
|
||||||
* @param id ID
|
|
||||||
* @return 昵称
|
|
||||||
*/
|
|
||||||
@ContainerMethod(namespace = ContainerPool.USER_NICKNAME, type = MappingType.ORDER_OF_KEYS)
|
|
||||||
String getNicknameById(Long id);
|
|
||||||
}
|
|
||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package top.continew.starter.file.excel.converter;
|
package top.continew.starter.file.excel.converter;
|
||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.util.ClassUtil;
|
|
||||||
import com.alibaba.excel.converters.Converter;
|
import com.alibaba.excel.converters.Converter;
|
||||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||||
@@ -34,7 +32,7 @@ import top.continew.starter.core.enums.BaseEnum;
|
|||||||
* @see BaseEnum
|
* @see BaseEnum
|
||||||
* @since 1.2.0
|
* @since 1.2.0
|
||||||
*/
|
*/
|
||||||
public class ExcelBaseEnumConverter implements Converter<BaseEnum<Integer>> {
|
public class ExcelBaseEnumConverter implements Converter<BaseEnum<?>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<BaseEnum> supportJavaTypeKey() {
|
public Class<BaseEnum> supportJavaTypeKey() {
|
||||||
@@ -50,17 +48,17 @@ public class ExcelBaseEnumConverter implements Converter<BaseEnum<Integer>> {
|
|||||||
* 转换为 Java 数据(读取 Excel)
|
* 转换为 Java 数据(读取 Excel)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BaseEnum convertToJavaData(ReadCellData<?> cellData,
|
public BaseEnum<?> convertToJavaData(ReadCellData<?> cellData,
|
||||||
ExcelContentProperty contentProperty,
|
ExcelContentProperty contentProperty,
|
||||||
GlobalConfiguration globalConfiguration) {
|
GlobalConfiguration globalConfiguration) {
|
||||||
return this.getEnum(BaseEnum.class, Convert.toStr(cellData.getData()));
|
return BaseEnum.getByDescription(cellData.getStringValue(), contentProperty.getField().getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为 Excel 数据(写入 Excel)
|
* 转换为 Excel 数据(写入 Excel)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public WriteCellData<String> convertToExcelData(BaseEnum<Integer> value,
|
public WriteCellData<String> convertToExcelData(BaseEnum<?> value,
|
||||||
ExcelContentProperty contentProperty,
|
ExcelContentProperty contentProperty,
|
||||||
GlobalConfiguration globalConfiguration) {
|
GlobalConfiguration globalConfiguration) {
|
||||||
if (null == value) {
|
if (null == value) {
|
||||||
@@ -68,24 +66,4 @@ public class ExcelBaseEnumConverter implements Converter<BaseEnum<Integer>> {
|
|||||||
}
|
}
|
||||||
return new WriteCellData<>(value.getDescription());
|
return new WriteCellData<>(value.getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过 value 获取枚举对象,获取不到时为 {@code null}
|
|
||||||
*
|
|
||||||
* @param enumType 枚举类型
|
|
||||||
* @param description 描述
|
|
||||||
* @return 对应枚举 ,获取不到时为 {@code null}
|
|
||||||
*/
|
|
||||||
private BaseEnum<Integer> getEnum(Class<?> enumType, String description) {
|
|
||||||
Object[] enumConstants = enumType.getEnumConstants();
|
|
||||||
for (Object enumConstant : enumConstants) {
|
|
||||||
if (ClassUtil.isAssignable(BaseEnum.class, enumType)) {
|
|
||||||
BaseEnum<Integer> baseEnum = (BaseEnum<Integer>)enumConstant;
|
|
||||||
if (baseEnum.getDescription().equals(description)) {
|
|
||||||
return baseEnum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,7 @@
|
|||||||
|
|
||||||
package top.continew.starter.log.handler;
|
package top.continew.starter.log.handler;
|
||||||
|
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
|
||||||
import top.continew.starter.log.AbstractLogHandler;
|
import top.continew.starter.log.AbstractLogHandler;
|
||||||
import top.continew.starter.log.model.LogRecord;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日志处理器-AOP 版实现
|
* 日志处理器-AOP 版实现
|
||||||
@@ -29,20 +25,4 @@ import java.lang.reflect.Method;
|
|||||||
* @since 2.8.0
|
* @since 2.8.0
|
||||||
*/
|
*/
|
||||||
public class AopLogHandler extends AbstractLogHandler {
|
public class AopLogHandler extends AbstractLogHandler {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logDescription(LogRecord logRecord, Method targetMethod) {
|
|
||||||
super.logDescription(logRecord, targetMethod);
|
|
||||||
if (CharSequenceUtil.isBlank(logRecord.getDescription())) {
|
|
||||||
logRecord.setDescription("请在该接口方法上指定日志描述");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logModule(LogRecord logRecord, Method targetMethod, Class<?> targetClass) {
|
|
||||||
super.logModule(logRecord, targetMethod, targetClass);
|
|
||||||
if (CharSequenceUtil.isBlank(logRecord.getModule())) {
|
|
||||||
logRecord.setModule("请在该接口类上指定所属模块");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,4 +11,12 @@
|
|||||||
|
|
||||||
<artifactId>continew-starter-log-core</artifactId>
|
<artifactId>continew-starter-log-core</artifactId>
|
||||||
<description>ContiNew Starter 日志模块 - 核心模块</description>
|
<description>ContiNew Starter 日志模块 - 核心模块</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Swagger 注解 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger.core.v3</groupId>
|
||||||
|
<artifactId>swagger-annotations-jakarta</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -18,8 +18,11 @@ package top.continew.starter.log;
|
|||||||
|
|
||||||
import cn.hutool.core.annotation.AnnotationUtil;
|
import cn.hutool.core.annotation.AnnotationUtil;
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import top.continew.starter.core.validation.ValidationUtils;
|
||||||
import top.continew.starter.log.annotation.Log;
|
import top.continew.starter.log.annotation.Log;
|
||||||
import top.continew.starter.log.enums.Include;
|
import top.continew.starter.log.enums.Include;
|
||||||
import top.continew.starter.log.http.servlet.RecordableServletHttpRequest;
|
import top.continew.starter.log.http.servlet.RecordableServletHttpRequest;
|
||||||
@@ -84,7 +87,15 @@ public abstract class AbstractLogHandler implements LogHandler {
|
|||||||
// 例如:@Log("新增部门") -> 新增部门
|
// 例如:@Log("新增部门") -> 新增部门
|
||||||
if (null != methodLog && CharSequenceUtil.isNotBlank(methodLog.value())) {
|
if (null != methodLog && CharSequenceUtil.isNotBlank(methodLog.value())) {
|
||||||
logRecord.setDescription(methodLog.value());
|
logRecord.setDescription(methodLog.value());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// 例如:@Operation(summary="新增部门") -> 新增部门
|
||||||
|
Operation methodOperation = AnnotationUtil.getAnnotation(targetMethod, Operation.class);
|
||||||
|
if (null != methodOperation) {
|
||||||
|
logRecord.setDescription(CharSequenceUtil.blankToDefault(methodOperation
|
||||||
|
.summary(), "请在该接口方法的 @Operation 上添加 summary 来指定日志描述"));
|
||||||
|
}
|
||||||
|
ValidationUtils.throwIfBlank(logRecord.getDescription(), "请在该接口方法上添加 @Log 来指定日志描述");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,7 +117,15 @@ public abstract class AbstractLogHandler implements LogHandler {
|
|||||||
Log classLog = AnnotationUtil.getAnnotation(targetClass, Log.class);
|
Log classLog = AnnotationUtil.getAnnotation(targetClass, Log.class);
|
||||||
if (null != classLog && CharSequenceUtil.isNotBlank(classLog.module())) {
|
if (null != classLog && CharSequenceUtil.isNotBlank(classLog.module())) {
|
||||||
logRecord.setModule(classLog.module());
|
logRecord.setModule(classLog.module());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// 例如:@Tag(name = "部门管理") -> 部门管理
|
||||||
|
Tag classTag = AnnotationUtil.getAnnotation(targetClass, Tag.class);
|
||||||
|
if (null != classTag) {
|
||||||
|
String name = classTag.name();
|
||||||
|
logRecord.setModule(CharSequenceUtil.blankToDefault(name, "请在该接口类的 @Tag 上添加 name 来指定所属模块"));
|
||||||
|
}
|
||||||
|
ValidationUtils.throwIfBlank(logRecord.getModule(), "请在该接口方法或接口类上添加 @Log 来指定所属模块");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -13,12 +13,6 @@
|
|||||||
<description>ContiNew Starter 日志模块 - 基于拦截器实现(Spring Boot Actuator HttpTrace 增强版)</description>
|
<description>ContiNew Starter 日志模块 - 基于拦截器实现(Spring Boot Actuator HttpTrace 增强版)</description>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Swagger 注解 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.swagger.core.v3</groupId>
|
|
||||||
<artifactId>swagger-annotations-jakarta</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- TTL(线程间传递 ThreadLocal,异步执行时上下文传递的解决方案) -->
|
<!-- TTL(线程间传递 ThreadLocal,异步执行时上下文传递的解决方案) -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
|
|||||||
@@ -16,14 +16,7 @@
|
|||||||
|
|
||||||
package top.continew.starter.log.handler;
|
package top.continew.starter.log.handler;
|
||||||
|
|
||||||
import cn.hutool.core.annotation.AnnotationUtil;
|
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import top.continew.starter.log.AbstractLogHandler;
|
import top.continew.starter.log.AbstractLogHandler;
|
||||||
import top.continew.starter.log.model.LogRecord;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日志处理器-拦截器版实现
|
* 日志处理器-拦截器版实现
|
||||||
@@ -32,31 +25,4 @@ import java.lang.reflect.Method;
|
|||||||
* @since 2.8.0
|
* @since 2.8.0
|
||||||
*/
|
*/
|
||||||
public class InterceptorLogHandler extends AbstractLogHandler {
|
public class InterceptorLogHandler extends AbstractLogHandler {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logDescription(LogRecord logRecord, Method targetMethod) {
|
|
||||||
super.logDescription(logRecord, targetMethod);
|
|
||||||
if (CharSequenceUtil.isNotBlank(logRecord.getDescription())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 例如:@Operation(summary="新增部门") -> 新增部门
|
|
||||||
Operation methodOperation = AnnotationUtil.getAnnotation(targetMethod, Operation.class);
|
|
||||||
if (null != methodOperation) {
|
|
||||||
logRecord.setDescription(CharSequenceUtil.blankToDefault(methodOperation.summary(), "请在该接口方法上指定日志描述"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logModule(LogRecord logRecord, Method targetMethod, Class<?> targetClass) {
|
|
||||||
super.logModule(logRecord, targetMethod, targetClass);
|
|
||||||
if (CharSequenceUtil.isNotBlank(logRecord.getModule())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 例如:@Tag(name = "部门管理") -> 部门管理
|
|
||||||
Tag classTag = AnnotationUtil.getAnnotation(targetClass, Tag.class);
|
|
||||||
if (null != classTag) {
|
|
||||||
String name = classTag.name();
|
|
||||||
logRecord.setModule(CharSequenceUtil.blankToDefault(name, "请在该接口类上指定所属模块"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ public enum Algorithm {
|
|||||||
DES(DesEncryptor.class),
|
DES(DesEncryptor.class),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PBEWithMD5AndDES
|
* PBE With MD5 And DES
|
||||||
*/
|
*/
|
||||||
PBEWithMD5AndDES(PbeWithMd5AndDesEncryptor.class),
|
PBE_WITH_MD5_AND_DES(PbeWithMd5AndDesEncryptor.class),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RSA
|
* RSA
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
package top.continew.starter.security.limiter.annotation;
|
package top.continew.starter.security.limiter.annotation;
|
||||||
|
|
||||||
import org.redisson.api.RateIntervalUnit;
|
|
||||||
import top.continew.starter.security.limiter.enums.LimitType;
|
import top.continew.starter.security.limiter.enums.LimitType;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 限流注解
|
* 限流注解
|
||||||
@@ -60,7 +60,7 @@ public @interface RateLimiter {
|
|||||||
/**
|
/**
|
||||||
* 速率间隔时间单位(默认:毫秒)
|
* 速率间隔时间单位(默认:毫秒)
|
||||||
*/
|
*/
|
||||||
RateIntervalUnit unit() default RateIntervalUnit.MILLISECONDS;
|
TimeUnit unit() default TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提示信息
|
* 提示信息
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import top.continew.starter.security.limiter.exception.RateLimiterException;
|
|||||||
import top.continew.starter.web.util.SpringWebUtils;
|
import top.continew.starter.web.util.SpringWebUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -129,12 +130,11 @@ public class RateLimiterAspect {
|
|||||||
// 限流器配置
|
// 限流器配置
|
||||||
RateType rateType = rateLimiter.type() == LimitType.CLUSTER ? RateType.PER_CLIENT : RateType.OVERALL;
|
RateType rateType = rateLimiter.type() == LimitType.CLUSTER ? RateType.PER_CLIENT : RateType.OVERALL;
|
||||||
int rate = rateLimiter.rate();
|
int rate = rateLimiter.rate();
|
||||||
int rateInterval = rateLimiter.interval();
|
Duration rateInterval = Duration.ofMillis(rateLimiter.unit().toMillis(rateLimiter.interval()));
|
||||||
RateIntervalUnit rateIntervalUnit = rateLimiter.unit();
|
|
||||||
// 判断是否需要更新限流器
|
// 判断是否需要更新限流器
|
||||||
if (this.isConfigurationUpdateNeeded(rRateLimiter, rateType, rate, rateInterval, rateIntervalUnit)) {
|
if (this.isConfigurationUpdateNeeded(rRateLimiter, rateType, rate, rateInterval)) {
|
||||||
// 更新限流器
|
// 更新限流器
|
||||||
rRateLimiter.setRate(rateType, rate, rateInterval, rateIntervalUnit);
|
rRateLimiter.setRate(rateType, rate, rateInterval);
|
||||||
}
|
}
|
||||||
// 尝试获取令牌
|
// 尝试获取令牌
|
||||||
return !rRateLimiter.tryAcquire();
|
return !rRateLimiter.tryAcquire();
|
||||||
@@ -181,20 +181,18 @@ public class RateLimiterAspect {
|
|||||||
/**
|
/**
|
||||||
* 判断是否需要更新限流器配置
|
* 判断是否需要更新限流器配置
|
||||||
*
|
*
|
||||||
* @param rRateLimiter 限流器
|
* @param rRateLimiter 限流器
|
||||||
* @param rateType 限流类型(OVERALL:全局限流;PER_CLIENT:单机限流)
|
* @param rateType 限流类型(OVERALL:全局限流;PER_CLIENT:单机限流)
|
||||||
* @param rate 速率(指定时间间隔产生的令牌数)
|
* @param rate 速率(指定时间间隔产生的令牌数)
|
||||||
* @param rateInterval 速率间隔
|
* @param rateInterval 速率间隔
|
||||||
* @param rateIntervalUnit 时间单位
|
|
||||||
* @return 是否需要更新配置
|
* @return 是否需要更新配置
|
||||||
*/
|
*/
|
||||||
private boolean isConfigurationUpdateNeeded(RRateLimiter rRateLimiter,
|
private boolean isConfigurationUpdateNeeded(RRateLimiter rRateLimiter,
|
||||||
RateType rateType,
|
RateType rateType,
|
||||||
long rate,
|
long rate,
|
||||||
long rateInterval,
|
Duration rateInterval) {
|
||||||
RateIntervalUnit rateIntervalUnit) {
|
|
||||||
RateLimiterConfig config = rRateLimiter.getConfig();
|
RateLimiterConfig config = rRateLimiter.getConfig();
|
||||||
return !Objects.equals(config.getRateType(), rateType) || !Objects.equals(config.getRate(), rate) || !Objects
|
return !Objects.equals(config.getRateType(), rateType) || !Objects.equals(config.getRate(), rate) || !Objects
|
||||||
.equals(config.getRateInterval(), rateIntervalUnit.toMillis(rateInterval));
|
.equals(config.getRateInterval(), rateInterval.toMillis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public enum MaskType implements IMaskStrategy {
|
|||||||
CUSTOM {
|
CUSTOM {
|
||||||
@Override
|
@Override
|
||||||
public String mask(String str, char character, int left, int right) {
|
public String mask(String str, char character, int left, int right) {
|
||||||
return CharSequenceUtil.replace(str, left, str.length() - right, character);
|
return CharSequenceUtil.replaceByCodePoint(str, left, str.length() - right, character);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ public enum MaskType implements IMaskStrategy {
|
|||||||
MOBILE_PHONE {
|
MOBILE_PHONE {
|
||||||
@Override
|
@Override
|
||||||
public String mask(String str, char character, int left, int right) {
|
public String mask(String str, char character, int left, int right) {
|
||||||
return CharSequenceUtil.replace(str, 3, str.length() - 4, character);
|
return CharSequenceUtil.replaceByCodePoint(str, 3, str.length() - 4, character);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ public enum MaskType implements IMaskStrategy {
|
|||||||
FIXED_PHONE {
|
FIXED_PHONE {
|
||||||
@Override
|
@Override
|
||||||
public String mask(String str, char character, int left, int right) {
|
public String mask(String str, char character, int left, int right) {
|
||||||
return CharSequenceUtil.replace(str, 4, str.length() - 2, character);
|
return CharSequenceUtil.replaceByCodePoint(str, 4, str.length() - 2, character);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ public enum MaskType implements IMaskStrategy {
|
|||||||
if (index <= 1) {
|
if (index <= 1) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
return CharSequenceUtil.replace(str, 1, index, character);
|
return CharSequenceUtil.replaceByCodePoint(str, 1, index, character);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ public enum MaskType implements IMaskStrategy {
|
|||||||
ID_CARD {
|
ID_CARD {
|
||||||
@Override
|
@Override
|
||||||
public String mask(String str, char character, int left, int right) {
|
public String mask(String str, char character, int left, int right) {
|
||||||
return CharSequenceUtil.replace(str, 1, str.length() - 2, character);
|
return CharSequenceUtil.replaceByCodePoint(str, 1, str.length() - 2, character);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -140,11 +140,11 @@ public enum MaskType implements IMaskStrategy {
|
|||||||
// 普通车牌
|
// 普通车牌
|
||||||
int length = str.length();
|
int length = str.length();
|
||||||
if (length == 7) {
|
if (length == 7) {
|
||||||
return CharSequenceUtil.replace(str, 3, 6, character);
|
return CharSequenceUtil.replaceByCodePoint(str, 3, 6, character);
|
||||||
}
|
}
|
||||||
// 新能源车牌
|
// 新能源车牌
|
||||||
if (length == 8) {
|
if (length == 8) {
|
||||||
return CharSequenceUtil.replace(str, 3, 7, character);
|
return CharSequenceUtil.replaceByCodePoint(str, 3, 7, character);
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ public enum MaskType implements IMaskStrategy {
|
|||||||
CHINESE_NAME {
|
CHINESE_NAME {
|
||||||
@Override
|
@Override
|
||||||
public String mask(String str, char character, int left, int right) {
|
public String mask(String str, char character, int left, int right) {
|
||||||
return CharSequenceUtil.replace(str, 1, str.length(), character);
|
return CharSequenceUtil.replaceByCodePoint(str, 1, str.length(), character);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ public enum MaskType implements IMaskStrategy {
|
|||||||
@Override
|
@Override
|
||||||
public String mask(String str, char character, int left, int right) {
|
public String mask(String str, char character, int left, int right) {
|
||||||
int length = str.length();
|
int length = str.length();
|
||||||
return CharSequenceUtil.replace(str, length - 8, length, character);
|
return CharSequenceUtil.replaceByCodePoint(str, length - 8, length, character);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package top.continew.starter.web.autoconfigure.xss;
|
package top.continew.starter.web.autoconfigure.xss;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import jakarta.servlet.*;
|
import jakarta.servlet.*;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -55,14 +55,14 @@ public class XssFilter implements Filter {
|
|||||||
if (servletRequest instanceof HttpServletRequest request && xssProperties.isEnabled()) {
|
if (servletRequest instanceof HttpServletRequest request && xssProperties.isEnabled()) {
|
||||||
// 放行路由:忽略 XSS 过滤
|
// 放行路由:忽略 XSS 过滤
|
||||||
List<String> excludePatterns = xssProperties.getExcludePatterns();
|
List<String> excludePatterns = xssProperties.getExcludePatterns();
|
||||||
if (CollectionUtil.isNotEmpty(excludePatterns) && SpringWebUtils.isMatch(request
|
if (CollUtil.isNotEmpty(excludePatterns) && SpringWebUtils.isMatch(request
|
||||||
.getServletPath(), excludePatterns)) {
|
.getServletPath(), excludePatterns)) {
|
||||||
filterChain.doFilter(request, servletResponse);
|
filterChain.doFilter(request, servletResponse);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 拦截路由:执行 XSS 过滤
|
// 拦截路由:执行 XSS 过滤
|
||||||
List<String> includePatterns = xssProperties.getIncludePatterns();
|
List<String> includePatterns = xssProperties.getIncludePatterns();
|
||||||
if (CollectionUtil.isNotEmpty(includePatterns)) {
|
if (CollUtil.isNotEmpty(includePatterns)) {
|
||||||
if (SpringWebUtils.isMatch(request.getServletPath(), includePatterns)) {
|
if (SpringWebUtils.isMatch(request.getServletPath(), includePatterns)) {
|
||||||
filterChain.doFilter(new XssServletRequestWrapper(request, xssProperties), servletResponse);
|
filterChain.doFilter(new XssServletRequestWrapper(request, xssProperties), servletResponse);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package top.continew.starter.web.autoconfigure.xss;
|
package top.continew.starter.web.autoconfigure.xss;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
@@ -110,7 +110,7 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
// 转义
|
// 转义
|
||||||
if (XssMode.ESCAPE.equals(mode)) {
|
if (XssMode.ESCAPE.equals(mode)) {
|
||||||
List<String> reStr = ReUtil.findAllGroup0(HtmlUtil.RE_HTML_MARK, content);
|
List<String> reStr = ReUtil.findAllGroup0(HtmlUtil.RE_HTML_MARK, content);
|
||||||
if (CollectionUtil.isEmpty(reStr)) {
|
if (CollUtil.isEmpty(reStr)) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
for (String s : reStr) {
|
for (String s : reStr) {
|
||||||
|
|||||||
Reference in New Issue
Block a user