Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 95e4f5ad4b | |||
| 52ebda0a42 | |||
| 868376fc42 | |||
| 2a1b90c6cb | |||
| 667bf66489 | |||
| 6a965e1618 | |||
| deb4029f01 | |||
| dc22a9b669 | |||
| 57bea22e44 | |||
| 15854b40ac |
+4
@@ -77,4 +77,8 @@ public interface OAuth2GranterConstant {
|
||||
*/
|
||||
String REGISTER = "register";
|
||||
|
||||
/**
|
||||
* mk oauth模式
|
||||
*/
|
||||
String MK = "mk";
|
||||
}
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
package org.springblade.core.oauth2.endpoint;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
|
||||
import org.springblade.core.oauth2.exception.ExceptionCode;
|
||||
import org.springblade.core.oauth2.granter.TokenGranter;
|
||||
import org.springblade.core.oauth2.granter.TokenGranterFactory;
|
||||
import org.springblade.core.oauth2.handler.TokenHandler;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Token;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
|
||||
import org.springblade.core.tool.support.Kv;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.springblade.core.oauth2.constant.OAuth2GranterConstant.MK;
|
||||
import static org.springblade.core.oauth2.constant.OAuth2ParameterConstant.USERNAME;
|
||||
|
||||
|
||||
/**
|
||||
* mk oauth认证端点
|
||||
* @author bfhuange
|
||||
* @date 2024/9/13
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "跳转mk认证", description = "跳转mk认证端点")
|
||||
public abstract class AbstractOAuth2MKEndpoint {
|
||||
|
||||
private final TokenGranterFactory granterFactory;
|
||||
private final TokenHandler tokenHandler;
|
||||
|
||||
/**
|
||||
* 返回登录页面
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/oauth/mk/login")
|
||||
public ResponseEntity<String> login(HttpServletRequest request, HttpServletResponse response) {
|
||||
String referer = request.getHeader("referer");
|
||||
if (!checkRefererUrl(referer)) {
|
||||
// 校验来源地址
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN)
|
||||
.body("非法来源地址");
|
||||
}
|
||||
// 返回登录页面
|
||||
return ResponseEntity.ok(generateLoginUrl(referer));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过mk授权码换取本系统token
|
||||
* @param mkCode
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/oauth/mk/token")
|
||||
public ResponseEntity<Kv> token(String mkCode) {
|
||||
log.info("mk 登录回调 mkCode:{}", mkCode);
|
||||
if (!StringUtils.hasText(mkCode)) {
|
||||
// 根据无效的mk code的错误代码抛出异常
|
||||
OAuth2ExceptionUtil.throwFromCode(ExceptionCode.INVALID_MK_CODE.getCode());
|
||||
}
|
||||
|
||||
// 将mk code 转换成erp的账号/手机号
|
||||
String account = getAccountByMkCode(mkCode);
|
||||
if (account == null) {
|
||||
OAuth2ExceptionUtil.throwFromCode(ExceptionCode.MK_ACCOUNT_NOT_FIND.getCode());
|
||||
}
|
||||
// 创建 OAuth2 请求对象并构建参数
|
||||
OAuth2Request request = OAuth2Request.create();
|
||||
// 默认管理组
|
||||
request.setTenantId(OAuth2TokenConstant.DEFAULT_TENANT_ID);
|
||||
// 只设置账号
|
||||
request.getParameterArgs().set(USERNAME, account);
|
||||
// 根据MK oauth的授权类型创建对应的 TokenGranter
|
||||
TokenGranter tokenGranter = granterFactory.create(MK);
|
||||
// 使用 TokenGranter 获取用户信息
|
||||
OAuth2User user = tokenGranter.user(request);
|
||||
// 创建令牌
|
||||
OAuth2Token token = tokenGranter.token(user, request);
|
||||
|
||||
// 对令牌进行增强处理
|
||||
OAuth2Token enhanceToken = tokenHandler.enhance(user, token, request);
|
||||
|
||||
// 返回增强后的令牌
|
||||
return ResponseEntity.ok(enhanceToken.getArgs());
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出消息
|
||||
* @param response
|
||||
* @param message
|
||||
*/
|
||||
protected void writeMessage(HttpServletResponse response, String message) {
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
|
||||
try(PrintWriter writer = response.getWriter()) {
|
||||
log.warn(message);
|
||||
writer.println(message);
|
||||
} catch (IOException e) {
|
||||
log.error(message + "异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成登录地址
|
||||
* @param refererUrl
|
||||
* @return
|
||||
*/
|
||||
protected abstract String generateLoginUrl(String refererUrl);
|
||||
|
||||
/**
|
||||
* 根据mk授权码获取账号
|
||||
* @param mkCode
|
||||
* @return
|
||||
*/
|
||||
protected abstract String getAccountByMkCode(String mkCode);
|
||||
|
||||
/**
|
||||
* 校验来源url,返回false,不跳转登录页面
|
||||
* @param refererUrl
|
||||
* @return
|
||||
*/
|
||||
protected abstract boolean checkRefererUrl(String refererUrl);
|
||||
}
|
||||
+20
@@ -74,6 +74,11 @@ public enum ExceptionCode implements Oauth2ExceptionCode {
|
||||
*/
|
||||
UNAUTHORIZED_USER(OAuth2ErrorCode.UNAUTHORIZED_USER, "认证信息错误或无效"),
|
||||
|
||||
/**
|
||||
* 用户未授权 - 账号或密码不正确。
|
||||
*/
|
||||
ACCOUNT_OR_PASSWORD_ERROR(OAuth2ErrorCode.ACCOUNT_OR_PASSWORD_ERROR, "账号或密码不正确"),
|
||||
|
||||
/**
|
||||
* 用户租户未授权 - 指定的用户租户未授权。
|
||||
*/
|
||||
@@ -84,6 +89,21 @@ public enum ExceptionCode implements Oauth2ExceptionCode {
|
||||
*/
|
||||
INVALID_REFRESH_TOKEN(OAuth2ErrorCode.INVALID_REFRESH_TOKEN, "令牌刷新错误或无效"),
|
||||
|
||||
/**
|
||||
* 用户未授权 - 无效的mk code
|
||||
*/
|
||||
INVALID_MK_CODE(OAuth2ErrorCode.INVALID_MK_CODE, "无效的mk code"),
|
||||
|
||||
/**
|
||||
* 用户未授权 - 获取mk账号错误
|
||||
*/
|
||||
MK_ACCOUNT_NOT_FIND(OAuth2ErrorCode.MK_ACCOUNT_FETCH_ERROR, "获取MK账号错误"),
|
||||
|
||||
/**
|
||||
* 用户未授权 - mk账号未同步本系统
|
||||
*/
|
||||
MK_ACCOUNT_NOT_SYNC_SYSTEM(OAuth2ErrorCode.MK_ACCOUNT_NOT_SYNC_SYSTEM, "MK账号【%s】未同步到本系统"),
|
||||
|
||||
/**
|
||||
* 客户端不存在 - 指定的客户端ID不存在或无效。
|
||||
*/
|
||||
|
||||
+16
@@ -59,10 +59,26 @@ public interface OAuth2ErrorCode {
|
||||
* 用户租户未授权 - 指定的用户租户未授权。
|
||||
*/
|
||||
int UNAUTHORIZED_USER_TENANT = 2006;
|
||||
/**
|
||||
* 账号或密码不正确
|
||||
*/
|
||||
int ACCOUNT_OR_PASSWORD_ERROR = 2007;
|
||||
/**
|
||||
* 令牌刷新错误或无效 - 刷新令牌认证信息错误或无效。
|
||||
*/
|
||||
int INVALID_REFRESH_TOKEN = 2010;
|
||||
/**
|
||||
* 无效的mk code
|
||||
*/
|
||||
int INVALID_MK_CODE = 2020;
|
||||
/**
|
||||
* 获取mk账号错误
|
||||
*/
|
||||
int MK_ACCOUNT_FETCH_ERROR = 2021;
|
||||
/**
|
||||
* mk账号未同步本系统
|
||||
*/
|
||||
int MK_ACCOUNT_NOT_SYNC_SYSTEM = 2022;
|
||||
/**
|
||||
* 客户端不存在 - 指定的客户端ID不存在或无效。
|
||||
*/
|
||||
|
||||
+3
-1
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
package org.springblade.core.oauth2.granter;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.launch.constant.TokenConstant;
|
||||
@@ -66,8 +67,9 @@ public abstract class AbstractTokenGranter implements TokenGranter {
|
||||
* 认证失败原因:密码匹配失败
|
||||
*/
|
||||
private static final String REASON_PASSWORD_MISMATCH = "密码匹配失败";
|
||||
|
||||
@Getter
|
||||
private final OAuth2ClientService clientService;
|
||||
@Getter
|
||||
private final OAuth2UserService userService;
|
||||
private final PasswordHandler passwordHandler;
|
||||
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package org.springblade.core.oauth2.granter;
|
||||
|
||||
import org.springblade.core.oauth2.exception.ExceptionCode;
|
||||
import org.springblade.core.oauth2.exception.OAuth2ErrorCode;
|
||||
import org.springblade.core.oauth2.exception.OAuth2Exception;
|
||||
import org.springblade.core.oauth2.handler.PasswordHandler;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2Client;
|
||||
import org.springblade.core.oauth2.service.OAuth2ClientService;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* PasswordTokenGranter
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Component
|
||||
public class MKTokenGranter extends AbstractTokenGranter {
|
||||
/**
|
||||
* MK client id
|
||||
*/
|
||||
private static final String MK_CLIENT_ID = "mk-oauth";
|
||||
|
||||
public MKTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler) {
|
||||
super(clientService, userService, passwordHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return MK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User user(OAuth2Request request) {
|
||||
OAuth2User user = this.getUser(request);
|
||||
return Optional.ofNullable(this.enhancer)
|
||||
.map(enhancer -> enhancer.enhance(user, request))
|
||||
.orElse(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Client client(OAuth2Request request) {
|
||||
// 直接使用固定的client id
|
||||
return getClientService().loadByClientId(MK_CLIENT_ID);
|
||||
}
|
||||
|
||||
private OAuth2User getUser(OAuth2Request request) {
|
||||
// 获取用户信息
|
||||
OAuth2User user = getUserService().loadByUsername(request.getUsername(), request);
|
||||
|
||||
// 用户不存在
|
||||
if (user == null) {
|
||||
String message = String.format(ExceptionCode.MK_ACCOUNT_NOT_SYNC_SYSTEM.getMessage(), request.getUsername());
|
||||
throw new OAuth2Exception(ExceptionCode.MK_ACCOUNT_NOT_SYNC_SYSTEM, message);
|
||||
}
|
||||
|
||||
// 校验用户信息
|
||||
if (!getUserService().validateUser(Objects.requireNonNull(user))) {
|
||||
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
|
||||
}
|
||||
|
||||
// 无需校验用户密码
|
||||
|
||||
//MK登进来检查是否是默认密码
|
||||
//MK登录跳过强制修改密码
|
||||
// user.setDefaultPwdFlag(false);
|
||||
|
||||
// 设置客户端信息
|
||||
user.setClient(client(request));
|
||||
|
||||
// 返回用户信息
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -115,6 +115,7 @@ public class TokenGranterFactory {
|
||||
case WECHAT_APPLET -> properties.getGranter().getWechatApplet();
|
||||
case SOCIAL -> properties.getGranter().getSocial();
|
||||
case REGISTER -> properties.getGranter().getRegister();
|
||||
case MK -> properties.getGranter().getMk();
|
||||
default -> true;
|
||||
};
|
||||
}
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ public abstract class AbstractAuthorizationHandler implements AuthorizationHandl
|
||||
*/
|
||||
@Override
|
||||
public OAuth2Validation authValidation(OAuth2User user, OAuth2Request request) {
|
||||
if (request.isClientCredentials() || request.isImplicit() || request.isSocial()) {
|
||||
if (request.isClientCredentials() || request.isImplicit() || request.isSocial() || request.isMk()) {
|
||||
return new OAuth2Validation();
|
||||
}
|
||||
if (Func.hasEmpty(user, user.getUserId())) {
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public class OAuth2AuthorizationHandler extends AbstractAuthorizationHandler {
|
||||
*/
|
||||
@Override
|
||||
public void authFailure(OAuth2User user, OAuth2Request request, OAuth2Validation validation) {
|
||||
|
||||
log.error("用户:{},认证失败,失败原因:{}", user.getAccount(), validation.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
@@ -65,6 +65,11 @@ public class OAuth2Properties {
|
||||
*/
|
||||
private String privateKey;
|
||||
|
||||
/**
|
||||
* sm4密钥
|
||||
*/
|
||||
private String sm4SecretKey;
|
||||
|
||||
/**
|
||||
* 授权模式
|
||||
*/
|
||||
@@ -117,6 +122,10 @@ public class OAuth2Properties {
|
||||
* 是否开启注册模式
|
||||
*/
|
||||
private Boolean register = true;
|
||||
/**
|
||||
* 是否开启 mk oauth模式
|
||||
*/
|
||||
private Boolean mk = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
@@ -410,6 +410,14 @@ public class OAuth2Request {
|
||||
return SOCIAL.equals(getGrantType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否mk oauth模式
|
||||
* @return
|
||||
*/
|
||||
public Boolean isMk() {
|
||||
return MK.equals(getGrantType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置租户ID
|
||||
*
|
||||
|
||||
+10
@@ -56,6 +56,9 @@ public class OAuth2ExceptionUtil {
|
||||
OAUTH2_EXCEPTION.put(
|
||||
ExceptionCode.INVALID_USER, () -> new UserInvalidException(ExceptionCode.INVALID_USER.getMessage(), new Throwable())
|
||||
);
|
||||
OAUTH2_EXCEPTION.put(
|
||||
ExceptionCode.ACCOUNT_OR_PASSWORD_ERROR, () -> new UserInvalidException(ExceptionCode.ACCOUNT_OR_PASSWORD_ERROR.getMessage())
|
||||
);
|
||||
OAUTH2_EXCEPTION.put(
|
||||
ExceptionCode.UNAUTHORIZED_USER, () -> new UserUnauthorizedException(ExceptionCode.UNAUTHORIZED_USER.getMessage(), new Throwable())
|
||||
);
|
||||
@@ -95,6 +98,13 @@ public class OAuth2ExceptionUtil {
|
||||
OAUTH2_EXCEPTION.put(
|
||||
ExceptionCode.TEMPORARILY_UNAVAILABLE, () -> new OAuth2Exception(ExceptionCode.TEMPORARILY_UNAVAILABLE, ExceptionCode.TEMPORARILY_UNAVAILABLE.getMessage(), new Throwable())
|
||||
);
|
||||
put(ExceptionCode.INVALID_MK_CODE);
|
||||
put(ExceptionCode.MK_ACCOUNT_NOT_FIND);
|
||||
put(ExceptionCode.MK_ACCOUNT_NOT_SYNC_SYSTEM);
|
||||
}
|
||||
|
||||
private static void put(ExceptionCode exceptionCode) {
|
||||
OAUTH2_EXCEPTION.put(exceptionCode, () -> new OAuth2Exception(exceptionCode, exceptionCode.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-3
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
package org.springblade.core.cloud.feign;
|
||||
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import feign.FeignException;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -85,8 +86,8 @@ public class BladeFeignFallback<T> implements MethodInterceptor {
|
||||
return JSON.parseObject(body, returnType);
|
||||
}
|
||||
}
|
||||
// 暂时不支持 flux,rx,异步等,返回值不是 R,直接返回 null。
|
||||
if (R.class != returnType) {
|
||||
// 暂时不支持 flux,rx,异步等,返回值不是 R(或其子类,如 FR),直接返回 null。
|
||||
if (!R.class.isAssignableFrom(returnType)) {
|
||||
return null;
|
||||
}
|
||||
// 非 FeignException
|
||||
@@ -103,7 +104,9 @@ public class BladeFeignFallback<T> implements MethodInterceptor {
|
||||
JsonNode resultNode = JsonUtil.readTree(content);
|
||||
// 判断是否 R 格式 返回体
|
||||
if (resultNode.has(CODE)) {
|
||||
return JsonUtil.getInstance().convertValue(resultNode, R.class);
|
||||
// 支持 R 及其子类(如 FR)的泛型反序列化,保留服务端失败原因
|
||||
JavaType javaType = JsonUtil.getInstance().getTypeFactory().constructType(method.getGenericReturnType());
|
||||
return JsonUtil.getInstance().convertValue(resultNode, javaType);
|
||||
}
|
||||
return R.fail(resultNode.toString());
|
||||
}
|
||||
|
||||
+9
@@ -25,10 +25,12 @@
|
||||
*/
|
||||
package org.springblade.core.cloud.feign;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
import org.springblade.core.secure.BladeUser;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.constant.BladeConstant;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.core.tool.utils.ThreadLocalUtil;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
||||
@@ -57,6 +59,13 @@ public class BladeFeignRequestInterceptor implements RequestInterceptor {
|
||||
values.forEach(value -> requestTemplate.header(key, value))
|
||||
);
|
||||
}
|
||||
if (!requestTemplate.headers().containsKey(BladeConstant.TRACE_ID_HEADER)) {
|
||||
// 不包含traceId请求头,且traceId不为空,则添加
|
||||
String traceId = MDC.get(BladeConstant.MDC_TRACE_ID_KEY);
|
||||
if (StringUtil.isNotBlank(traceId)) {
|
||||
requestTemplate.header(BladeConstant.TRACE_ID_HEADER, traceId);
|
||||
}
|
||||
}
|
||||
// 如果是 API Key 认证则跳过设置
|
||||
if (AuthUtil.isApiKeyRequest()) {
|
||||
return;
|
||||
|
||||
+5
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
package org.springblade.core.context;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
import org.springblade.core.tool.utils.ThreadLocalUtil;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -37,6 +38,7 @@ import java.util.concurrent.Callable;
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Slf4j
|
||||
public class BladeCallableWrapper<V> implements Callable<V> {
|
||||
private final Callable<V> delegate;
|
||||
private final Map<String, Object> tlMap;
|
||||
@@ -62,6 +64,9 @@ public class BladeCallableWrapper<V> implements Callable<V> {
|
||||
}
|
||||
try {
|
||||
return delegate.call();
|
||||
} catch (Exception e) {
|
||||
log.error("异步任务执行异常", e);
|
||||
throw e;
|
||||
} finally {
|
||||
tlMap.clear();
|
||||
if (mdcMap != null) {
|
||||
|
||||
+5
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
package org.springblade.core.context;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
import org.springblade.core.tool.utils.ThreadLocalUtil;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -36,6 +37,7 @@ import java.util.Map;
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Slf4j
|
||||
public class BladeRunnableWrapper implements Runnable {
|
||||
private final Runnable delegate;
|
||||
private final Map<String, Object> tlMap;
|
||||
@@ -61,6 +63,9 @@ public class BladeRunnableWrapper implements Runnable {
|
||||
}
|
||||
try {
|
||||
delegate.run();
|
||||
} catch (Exception e) {
|
||||
log.error("异步任务执行异常", e);
|
||||
throw e;
|
||||
} finally {
|
||||
tlMap.clear();
|
||||
if (mdcMap != null) {
|
||||
|
||||
@@ -51,11 +51,11 @@
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
<!-- Oracle -->
|
||||
<dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>com.oracle</groupId>
|
||||
<artifactId>ojdbc7</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc17</artifactId>
|
||||
@@ -80,11 +80,11 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!--YashanDB-->
|
||||
<dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>com.yashandb.jdbc</groupId>
|
||||
<artifactId>yasdb-jdbc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
<!--KingbaseES-->
|
||||
<dependency>
|
||||
<groupId>cn.com.kingbase</groupId>
|
||||
|
||||
@@ -46,6 +46,20 @@ import java.util.*;
|
||||
*/
|
||||
public class BladeApplication {
|
||||
|
||||
/**
|
||||
* 是否注入 Blade 默认的 Nacos spring.config.import。
|
||||
*/
|
||||
public static final String NACOS_IMPORT_ENABLED_PROPERTY = "blade.launcher.nacos.import.enabled";
|
||||
|
||||
/**
|
||||
* 是否注入 LauncherService 中的 Nacos 系统属性配置。
|
||||
*/
|
||||
public static final String NACOS_CONFIG_ENABLED_PROPERTY = "blade.launcher.nacos.config.enabled";
|
||||
|
||||
private static final String NACOS_IMPORT_ENABLED_ENV = "BLADE_LAUNCHER_NACOS_IMPORT_ENABLED";
|
||||
|
||||
private static final String NACOS_CONFIG_ENABLED_ENV = "BLADE_LAUNCHER_NACOS_CONFIG_ENABLED";
|
||||
|
||||
/**
|
||||
* 启动SpringBoot应用,不使用自定义SpringApplicationBuilder
|
||||
*
|
||||
@@ -120,6 +134,40 @@ public class BladeApplication {
|
||||
return StringUtils.hasText(osName) && !(AppConstant.OS_NAME_LINUX.equalsIgnoreCase(osName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用 Blade 默认的 Nacos 配置导入。
|
||||
*
|
||||
* @return true 表示启用
|
||||
*/
|
||||
public static boolean isNacosImportEnabled() {
|
||||
return getBoolean(NACOS_IMPORT_ENABLED_PROPERTY, NACOS_IMPORT_ENABLED_ENV, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用 LauncherService 中的 Nacos 系统属性配置。
|
||||
*
|
||||
* @return true 表示启用
|
||||
*/
|
||||
public static boolean isNacosConfigEnabled() {
|
||||
return getBoolean(NACOS_CONFIG_ENABLED_PROPERTY, NACOS_CONFIG_ENABLED_ENV, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭 Blade 启动阶段的 Nacos 默认配置注入,改由应用自身配置文件声明。
|
||||
*/
|
||||
public static void disableNacosLaunchConfig() {
|
||||
System.setProperty(NACOS_IMPORT_ENABLED_PROPERTY, Boolean.FALSE.toString());
|
||||
System.setProperty(NACOS_CONFIG_ENABLED_PROPERTY, Boolean.FALSE.toString());
|
||||
}
|
||||
|
||||
private static boolean getBoolean(String propertyName, String envName, boolean defaultValue) {
|
||||
String value = System.getProperty(propertyName);
|
||||
if (!StringUtils.hasText(value)) {
|
||||
value = System.getenv(envName);
|
||||
}
|
||||
return StringUtils.hasText(value) ? Boolean.parseBoolean(value) : defaultValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 配置环境变量
|
||||
@@ -199,7 +247,9 @@ public class BladeApplication {
|
||||
defaultProperties.setProperty("spring.sleuth.sampler.percentage", "1.0");
|
||||
defaultProperties.setProperty("spring.cloud.alibaba.seata.tx-service-group", appName.concat(NacosConstant.NACOS_GROUP_SUFFIX));
|
||||
defaultProperties.setProperty("nacos.logging.default.config.enabled", "false");
|
||||
if (isNacosImportEnabled()) {
|
||||
defaultProperties.setProperty("spring.config.import", String.join(",", NacosConstant.dataId(), NacosConstant.dataId(profile), NacosConstant.dataId(appName, profile)));
|
||||
}
|
||||
return defaultProperties;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,6 +127,17 @@ public interface AppConstant {
|
||||
*/
|
||||
String APPLICATION_DEMO_NAME = APPLICATION_NAME_PREFIX + "demo";
|
||||
|
||||
/**
|
||||
* 文件模块模块名称
|
||||
*/
|
||||
String APPLICATION_FILE_NAME =APPLICATION_NAME_PREFIX +"file";
|
||||
|
||||
/**
|
||||
* 三方服务模块名称
|
||||
*/
|
||||
String APPLICATION_OPENAPI_NAME =APPLICATION_NAME_PREFIX +"openapi";
|
||||
|
||||
|
||||
/**
|
||||
* 开发环境
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
package org.springblade.core.tool.api;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.springblade.core.tool.constant.BladeConstant;
|
||||
import org.springblade.core.tool.utils.ObjectUtil;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* feign 统一API响应结果封装
|
||||
* @author bfhuange
|
||||
* @since 2024/11/28
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Schema(description = "返回信息")
|
||||
@NoArgsConstructor
|
||||
public class FR<T> extends R<T> {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonSerialize(nullsUsing = NullSerializer.class)
|
||||
@Schema(description = "承载数据")
|
||||
private T data;
|
||||
|
||||
private FR(IResultCode resultCode) {
|
||||
this(resultCode, null, resultCode.getMessage());
|
||||
}
|
||||
|
||||
private FR(IResultCode resultCode, String msg) {
|
||||
this(resultCode, null, msg);
|
||||
}
|
||||
|
||||
private FR(IResultCode resultCode, T data) {
|
||||
this(resultCode, data, resultCode.getMessage());
|
||||
}
|
||||
|
||||
private FR(IResultCode resultCode, T data, String msg) {
|
||||
this(resultCode.getCode(), data, msg);
|
||||
}
|
||||
|
||||
private FR(int code, T data, String msg) {
|
||||
super(code, data, msg);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
super.setData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断返回是否为成功
|
||||
*
|
||||
* @param result Result
|
||||
* @return 是否成功
|
||||
*/
|
||||
public static boolean isSuccess(@Nullable FR<?> result) {
|
||||
return Optional.ofNullable(result)
|
||||
.map(x -> ObjectUtil.nullSafeEquals(ResultCode.SUCCESS.getCode(), x.getCode()))
|
||||
.orElse(Boolean.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断返回是否为成功
|
||||
*
|
||||
* @param result Result
|
||||
* @return 是否成功
|
||||
*/
|
||||
public static boolean isNotSuccess(@Nullable FR<?> result) {
|
||||
return !FR.isSuccess(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param data 数据
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> data(T data) {
|
||||
return data(data, BladeConstant.DEFAULT_SUCCESS_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param data 数据
|
||||
* @param msg 消息
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> data(T data, String msg) {
|
||||
return data(HttpServletResponse.SC_OK, data, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param data 数据
|
||||
* @param msg 消息
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> data(int code, T data, String msg) {
|
||||
return new FR<>(code, data, data == null ? BladeConstant.DEFAULT_NULL_MESSAGE : msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param msg 消息
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> success(String msg) {
|
||||
return new FR<>(ResultCode.SUCCESS, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param resultCode 业务代码
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> success(IResultCode resultCode) {
|
||||
return new FR<>(resultCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param resultCode 业务代码
|
||||
* @param msg 消息
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> success(IResultCode resultCode, String msg) {
|
||||
return new FR<>(resultCode, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param msg 消息
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> fail(String msg) {
|
||||
return new FR<>(ResultCode.FAILURE, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 消息
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> fail(int code, String msg) {
|
||||
return new FR<>(code, null, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param resultCode 业务代码
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> fail(IResultCode resultCode) {
|
||||
return new FR<>(resultCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param resultCode 业务代码
|
||||
* @param msg 消息
|
||||
* @param <T> T 泛型标记
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> fail(IResultCode resultCode, String msg) {
|
||||
return new FR<>(resultCode, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param flag 成功状态
|
||||
* @return R
|
||||
*/
|
||||
public static <T> FR<T> status(boolean flag) {
|
||||
return flag ? success(BladeConstant.DEFAULT_SUCCESS_MESSAGE) : fail(BladeConstant.DEFAULT_FAILURE_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从r复制
|
||||
* @param result
|
||||
* @return
|
||||
* @param <T>
|
||||
*/
|
||||
public static <T> FR<T> copy(R<T> result) {
|
||||
return new FR<>(result.getCode(), result.getData(), result.getMsg());
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class R<T> implements Serializable {
|
||||
this(resultCode.getCode(), data, msg);
|
||||
}
|
||||
|
||||
private R(int code, T data, String msg) {
|
||||
protected R(int code, T data, String msg) {
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
this.msg = msg;
|
||||
|
||||
@@ -171,4 +171,18 @@ public interface BladeConstant {
|
||||
*/
|
||||
String DEFAULT_UNAUTHORIZED_MESSAGE = "签名认证失败";
|
||||
|
||||
/**
|
||||
* mdc trace id key
|
||||
*/
|
||||
String MDC_TRACE_ID_KEY = "traceId";
|
||||
|
||||
/**
|
||||
* trace id header
|
||||
*/
|
||||
String TRACE_ID_HEADER = "bs-trace-id";
|
||||
|
||||
/**
|
||||
* 默认线程池名称
|
||||
*/
|
||||
String DEFAULT_THREAD_EXECUTOR_NAME = "dtpExecutor1";
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springblade.core.log.utils.LogTraceUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
|
||||
/**
|
||||
* 为异步方法添加traceId
|
||||
@@ -45,11 +46,17 @@ public class LogTraceAspect {
|
||||
|
||||
@Around("logPointCut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
boolean clean = false;
|
||||
try {
|
||||
if (StringUtil.isBlank(LogTraceUtil.getTraceIdFromMDC())) {
|
||||
LogTraceUtil.insert();
|
||||
clean = true;
|
||||
}
|
||||
return point.proceed();
|
||||
} finally {
|
||||
if (clean) {
|
||||
LogTraceUtil.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-3
@@ -25,9 +25,13 @@
|
||||
*/
|
||||
package org.springblade.core.log.filter;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springblade.core.log.utils.LogTraceUtil;
|
||||
|
||||
import jakarta.servlet.*;
|
||||
import org.springblade.core.tool.constant.BladeConstant;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@@ -43,15 +47,20 @@ public class LogTraceFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
boolean flag = LogTraceUtil.insert();
|
||||
String traceId = null;
|
||||
if (request instanceof HttpServletRequest httpServletRequest) {
|
||||
traceId = httpServletRequest.getHeader(BladeConstant.TRACE_ID_HEADER);
|
||||
}
|
||||
traceId = LogTraceUtil.insert(traceId);
|
||||
try {
|
||||
if (response instanceof HttpServletResponse httpServletResponse) {
|
||||
httpServletResponse.addHeader(BladeConstant.TRACE_ID_HEADER, traceId);
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
} finally {
|
||||
if (flag) {
|
||||
LogTraceUtil.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
@@ -0,0 +1,471 @@
|
||||
package org.springblade.core.log.utils;
|
||||
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.tool.api.IResultCode;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author bfhuange
|
||||
* @date 2024/8/27
|
||||
**/
|
||||
public class AssertUtils {
|
||||
|
||||
/**
|
||||
* 对象非空
|
||||
* @param object
|
||||
* @param message
|
||||
*/
|
||||
public static void notNull(Object object, String message) throws ServiceException {
|
||||
if (object == null) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象非空
|
||||
* @param object
|
||||
* @param resultCode
|
||||
*/
|
||||
public static void notNull(Object object, IResultCode resultCode) throws ServiceException {
|
||||
if (object == null) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map非空
|
||||
* @param map
|
||||
* @param message
|
||||
*/
|
||||
public static void notEmpty(Map<?, ?> map, String message) throws ServiceException {
|
||||
if (CollectionUtils.isEmpty(map)) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map非空
|
||||
* @param map
|
||||
* @param resultCode
|
||||
*/
|
||||
public static void notEmpty(Map<?, ?> map, IResultCode resultCode) throws ServiceException {
|
||||
if (CollectionUtils.isEmpty(map)) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表非空
|
||||
* @param collection
|
||||
* @param message
|
||||
*/
|
||||
public static void notEmpty(Collection<?> collection, String message) throws ServiceException {
|
||||
if (CollectionUtils.isEmpty(collection)) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表非空
|
||||
* @param collection
|
||||
* @param resultCode
|
||||
*/
|
||||
public static void notEmpty(Collection<?> collection, IResultCode resultCode) throws ServiceException {
|
||||
if (CollectionUtils.isEmpty(collection)) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组非空
|
||||
* @param array
|
||||
* @param message
|
||||
*/
|
||||
public static void notEmpty(Object[] array, String message) throws ServiceException {
|
||||
if (ObjectUtils.isEmpty(array)) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组非空
|
||||
* @param array
|
||||
* @param resultCode
|
||||
*/
|
||||
public static void notEmpty(Object[] array, IResultCode resultCode) throws ServiceException {
|
||||
if (ObjectUtils.isEmpty(array)) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串非空
|
||||
* @param value
|
||||
* @param message
|
||||
*/
|
||||
public static void notEmpty(String value, String message) throws ServiceException {
|
||||
if (StringUtil.hasLength(value)) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串非空
|
||||
* @param value
|
||||
* @param resultCode
|
||||
*/
|
||||
public static void notEmpty(String value, IResultCode resultCode) throws ServiceException {
|
||||
if (StringUtil.hasLength(value)) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串去除空格非空
|
||||
* @param value
|
||||
* @param message
|
||||
*/
|
||||
public static void notBlank(String value, String message) throws ServiceException {
|
||||
if (StringUtil.isBlank(value)) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串去除空格非空
|
||||
* @param value
|
||||
* @param resultCode
|
||||
*/
|
||||
public static void notBlank(String value, IResultCode resultCode) throws ServiceException {
|
||||
if (StringUtil.isBlank(value)) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取重复数据
|
||||
* @param dataList
|
||||
* @return
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static List<String> getRepeatData(List<String> dataList) throws ServiceException {
|
||||
if(CollectionUtils.isEmpty(dataList)) {
|
||||
return null;
|
||||
}
|
||||
//判断是否有重复数据
|
||||
List<String> distinctDataList = dataList.stream().distinct().toList();
|
||||
if(dataList.size() == distinctDataList.size()) {
|
||||
return null;
|
||||
}
|
||||
List<String> repeatList = new ArrayList<>();
|
||||
Map<String,Long> dataMap = dataList.stream().collect(Collectors.groupingBy(p -> p,Collectors.counting()));
|
||||
//处理重复数据
|
||||
for(Map.Entry<String,Long> entry:dataMap.entrySet()) {
|
||||
if(entry.getValue() > 1) {
|
||||
repeatList.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
return repeatList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据不允许重复
|
||||
* @param dataList
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notRepeat(List<String> dataList,String message) throws ServiceException {
|
||||
//获取重复数据
|
||||
List<String> repeatList = getRepeatData(dataList);
|
||||
//若有重复数据,则校验不通过处理
|
||||
if(!CollectionUtils.isEmpty(repeatList)) {
|
||||
String repeatData = String.join(",",repeatList);
|
||||
throw new ServiceException(String.format(message,repeatData));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串相等校验
|
||||
* @param str1
|
||||
* @param str2
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void equals(String str1, String str2, String message) throws ServiceException {
|
||||
if (!StringUtil.equals(str1,str2)) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串相等校验
|
||||
* @param str1
|
||||
* @param str2
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void equals(String str1, String str2, IResultCode resultCode) throws ServiceException {
|
||||
if (!StringUtil.equals(str1,str2)) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字相等校验
|
||||
* @param num1
|
||||
* @param num2
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void equals(BigDecimal num1, BigDecimal num2, String message) throws ServiceException {
|
||||
if (num1.compareTo(num2) != 0) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字相等校验
|
||||
* @param num1
|
||||
* @param num2
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void equals(BigDecimal num1, BigDecimal num2, IResultCode resultCode) throws ServiceException {
|
||||
if (num1.compareTo(num2) != 0) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字不大于校验
|
||||
* @param num1
|
||||
* @param num2
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notGreaterThan(BigDecimal num1, BigDecimal num2, String message) throws ServiceException {
|
||||
if(num1.compareTo(num2) > 0) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字不大于校验
|
||||
* @param num1
|
||||
* @param num2
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notGreaterThan(BigDecimal num1, BigDecimal num2, IResultCode resultCode) throws ServiceException {
|
||||
if(num1.compareTo(num2) > 0) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字不大于校验
|
||||
* @param num1
|
||||
* @param num2
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notGreaterThan(Integer num1, Integer num2, String message) throws ServiceException {
|
||||
if(num1 > num2) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字不大于校验
|
||||
* @param num1
|
||||
* @param num2
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notGreaterThan(Integer num1, Integer num2, IResultCode resultCode) throws ServiceException {
|
||||
if(num1 > num2) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字不小于校验
|
||||
* @param num1
|
||||
* @param num2
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notLessThan(BigDecimal num1, BigDecimal num2, String message) throws ServiceException {
|
||||
if(num1.compareTo(num2) < 0) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字不小于校验
|
||||
* @param num1
|
||||
* @param num2
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notLessThan(BigDecimal num1, BigDecimal num2, IResultCode resultCode) throws ServiceException {
|
||||
if(num1.compareTo(num2) < 0) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 表达式为真判断校验
|
||||
* @param expression
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void isTrue(boolean expression, String message) throws ServiceException {
|
||||
if(!expression) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 表达式为真判断校验
|
||||
* @param expression
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void isTrue(boolean expression, IResultCode resultCode) throws ServiceException {
|
||||
if(!expression) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 表达式判断为假校验
|
||||
* @param expression
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void isFalse(boolean expression, String message) throws ServiceException {
|
||||
if(expression) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 表达式判断为假校验
|
||||
* @param expression
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void isFalse(boolean expression, IResultCode resultCode) throws ServiceException {
|
||||
if(expression) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串不相等校验
|
||||
* @param str1
|
||||
* @param str2
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notEquals(String str1, String str2, String message) throws ServiceException {
|
||||
if (StringUtil.equals(str1,str2)) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串不相等校验
|
||||
* @param str1
|
||||
* @param str2
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void notEquals(String str1, String str2, IResultCode resultCode) throws ServiceException {
|
||||
if (StringUtil.equals(str1,str2)) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象为空
|
||||
* @param object
|
||||
* @param message
|
||||
*/
|
||||
public static void isNull(Object object, String message) throws ServiceException {
|
||||
if (object != null) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象为空
|
||||
* @param object
|
||||
* @param resultCode
|
||||
*/
|
||||
public static void isNull(Object object, IResultCode resultCode) throws ServiceException {
|
||||
if (object != null) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象为数值
|
||||
* @param value
|
||||
* @param message
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void isInteger(String value,String message) throws ServiceException {
|
||||
try {
|
||||
Integer.valueOf(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象为数值
|
||||
* @param value
|
||||
* @param resultCode
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public static void isInteger(String value,IResultCode resultCode) throws ServiceException {
|
||||
try {
|
||||
Integer.valueOf(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表为空
|
||||
* @param collection
|
||||
* @param message
|
||||
*/
|
||||
public static void isEmpty(Collection<?> collection, String message) throws ServiceException {
|
||||
if (!CollectionUtils.isEmpty(collection)) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表为空
|
||||
* @param collection
|
||||
* @param resultCode
|
||||
*/
|
||||
public static void isEmpty(Collection<?> collection, IResultCode resultCode) throws ServiceException {
|
||||
if (!CollectionUtils.isEmpty(collection)) {
|
||||
throw new ServiceException(resultCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
package org.springblade.core.log.utils;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
import org.springblade.core.tool.constant.BladeConstant;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
|
||||
/**
|
||||
@@ -34,7 +35,6 @@ import org.springblade.core.tool.utils.StringUtil;
|
||||
* @author Chill
|
||||
*/
|
||||
public class LogTraceUtil {
|
||||
private static final String UNIQUE_ID = "traceId";
|
||||
|
||||
/**
|
||||
* 获取日志追踪id格式
|
||||
@@ -43,23 +43,39 @@ public class LogTraceUtil {
|
||||
return StringUtil.randomUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从mdc获取日志追踪id
|
||||
* @return
|
||||
*/
|
||||
public static String getTraceIdFromMDC() {
|
||||
return MDC.get(BladeConstant.MDC_TRACE_ID_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入traceId
|
||||
*/
|
||||
public static boolean insert() {
|
||||
MDC.put(UNIQUE_ID, getTraceId());
|
||||
return true;
|
||||
public static String insert() {
|
||||
return LogTraceUtil.insert(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除traceId
|
||||
*/
|
||||
public static boolean remove() {
|
||||
MDC.remove(UNIQUE_ID);
|
||||
MDC.remove(BladeConstant.MDC_TRACE_ID_KEY);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String getTraceIdFromMDC() {
|
||||
return MDC.get(UNIQUE_ID);
|
||||
/**
|
||||
* 插入traceId
|
||||
* @param traceId
|
||||
* @return
|
||||
*/
|
||||
public static String insert(String traceId) {
|
||||
if (traceId == null) {
|
||||
traceId = getTraceId();
|
||||
}
|
||||
MDC.put(BladeConstant.MDC_TRACE_ID_KEY, traceId);
|
||||
return traceId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<conversionRule conversionWord="wEx" class="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
|
||||
<!-- 彩色日志格式 -->
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr([%X{traceId:-N/A}]){yellow} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %clr([%line]){green} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<conversionRule conversionWord="wEx" class="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
|
||||
<!-- 彩色日志格式 -->
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr([%X{traceId:-N/A}]){yellow} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %clr([%line]){green} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<conversionRule conversionWord="wEx" class="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
|
||||
<!-- 彩色日志格式 -->
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr([%X{traceId:-N/A}]){yellow} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %clr([%line]){green} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
package org.springblade.core.redis.lock;
|
||||
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springblade.core.tool.function.CheckedSupplier;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -97,4 +98,10 @@ public interface RedisLockClient {
|
||||
return lock(lockName, LockType.REENTRANT, waitTime, leaseTime, TimeUnit.SECONDS, supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 RedissonClient
|
||||
*
|
||||
* @return RedissonClient
|
||||
*/
|
||||
RedissonClient getRedissonClient();
|
||||
}
|
||||
|
||||
+5
@@ -85,4 +85,9 @@ public class RedisLockClientImpl implements RedisLockClient {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedissonClient getRedissonClient() {
|
||||
return redissonClient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>BladeX-Tool</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>blade-starter-threadpool</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>${project.parent.version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.dynamictp</groupId>
|
||||
<artifactId>dynamic-tp-spring-cloud-starter-nacos</artifactId>
|
||||
<version>1.1.9.1-3.x</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-auto</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 org.springblade.core.threadpool.config;
|
||||
|
||||
import org.dromara.dynamictp.core.executor.DtpExecutor;
|
||||
import org.dromara.dynamictp.core.executor.OrderedDtpExecutor;
|
||||
import org.dromara.dynamictp.core.support.DynamicTp;
|
||||
import org.dromara.dynamictp.core.support.ThreadPoolBuilder;
|
||||
import org.dromara.dynamictp.core.support.ThreadPoolCreator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.dromara.dynamictp.common.em.QueueTypeEnum.MEMORY_SAFE_LINKED_BLOCKING_QUEUE;
|
||||
import static org.dromara.dynamictp.common.em.RejectedTypeEnum.CALLER_RUNS_POLICY;
|
||||
|
||||
/**
|
||||
* @author Redick01
|
||||
*/
|
||||
|
||||
// @Configuration
|
||||
public class ThreadPoolConfiguration {
|
||||
|
||||
/**
|
||||
* 通过{@link DynamicTp} 注解定义普通juc线程池,会享受到该框架增强能力,注解名称优先级高于方法名
|
||||
*
|
||||
* @return 线程池实例
|
||||
*/
|
||||
@DynamicTp("jucThreadPoolExecutor")
|
||||
@Bean
|
||||
public ThreadPoolExecutor jucThreadPoolExecutor() {
|
||||
return (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link DynamicTp} 注解定义spring线程池,会享受到该框架增强能力,注解名称优先级高于方法名
|
||||
*
|
||||
* @return 线程池实例
|
||||
*/
|
||||
@DynamicTp("threadPoolTaskExecutor")
|
||||
@Bean
|
||||
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
|
||||
return new ThreadPoolTaskExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link ThreadPoolCreator} 快速创建一些简单配置的线程池,使用默认参数
|
||||
* tips: 建议直接在配置中心配置就行,不用@Bean声明
|
||||
*
|
||||
* @return 线程池实例
|
||||
*/
|
||||
@Bean
|
||||
public DtpExecutor dtpExecutor0() {
|
||||
return ThreadPoolCreator.createDynamicFast("dtpExecutor0");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link ThreadPoolBuilder} 设置详细参数创建动态线程池
|
||||
* tips: 建议直接在配置中心配置就行,不用@Bean声明
|
||||
* @return 线程池实例
|
||||
*/
|
||||
@Bean
|
||||
public ThreadPoolExecutor dtpExecutor1() {
|
||||
return ThreadPoolBuilder.newBuilder()
|
||||
.threadPoolName("dtpExecutor1")
|
||||
.threadFactory("test-dtp-common")
|
||||
.corePoolSize(10)
|
||||
.maximumPoolSize(15)
|
||||
.keepAliveTime(40)
|
||||
.timeUnit(TimeUnit.SECONDS)
|
||||
.workQueue(MEMORY_SAFE_LINKED_BLOCKING_QUEUE.getName(), 2000)
|
||||
.buildDynamic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link ThreadPoolBuilder} 设置详细参数创建动态线程池
|
||||
* eager,参考tomcat线程池设计,适用于处理io密集型任务场景,具体参数可以看代码注释
|
||||
* tips: 建议直接在配置中心配置就行,不用@Bean声明
|
||||
* @return 线程池实例
|
||||
*/
|
||||
@Bean
|
||||
public DtpExecutor eagerDtpExecutor() {
|
||||
return ThreadPoolBuilder.newBuilder()
|
||||
.threadPoolName("eagerDtpExecutor")
|
||||
.threadFactory("test-eager")
|
||||
.corePoolSize(2)
|
||||
.maximumPoolSize(4)
|
||||
.queueCapacity(2000)
|
||||
.eager()
|
||||
.buildDynamic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link ThreadPoolBuilder} 设置详细参数创建动态线程池
|
||||
* ordered,适用于处理有序任务场景,任务要实现Ordered接口,具体参数可以看代码注释
|
||||
* tips: 建议直接在配置中心配置就行,不用@Bean声明
|
||||
* @return 线程池实例
|
||||
*/
|
||||
@Bean
|
||||
public OrderedDtpExecutor orderedDtpExecutor() {
|
||||
return ThreadPoolBuilder.newBuilder()
|
||||
.threadPoolName("orderedDtpExecutor")
|
||||
.threadFactory("test-ordered")
|
||||
.corePoolSize(4)
|
||||
.maximumPoolSize(4)
|
||||
.queueCapacity(2000)
|
||||
.buildOrdered();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link ThreadPoolBuilder} 设置详细参数创建线程池
|
||||
* scheduled,适用于处理定时任务场景,具体参数可以看代码注释
|
||||
* tips: 建议直接在配置中心配置就行,不用@Bean声明
|
||||
* @return 线程池实例
|
||||
*/
|
||||
@Bean
|
||||
public ScheduledExecutorService scheduledDtpExecutor() {
|
||||
return ThreadPoolBuilder.newBuilder()
|
||||
.threadPoolName("scheduledDtpExecutor")
|
||||
.corePoolSize(2)
|
||||
.threadFactory("test-scheduled")
|
||||
.rejectedExecutionHandler(CALLER_RUNS_POLICY.getName())
|
||||
.buildScheduled();
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 org.springblade.core.threadpool.wrapper;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.dynamictp.core.support.task.wrapper.TaskWrapper;
|
||||
import org.springblade.core.auto.service.AutoService;
|
||||
|
||||
/**
|
||||
* CustomTaskWrapper related
|
||||
*
|
||||
* @author yanhom
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@AutoService(TaskWrapper.class)
|
||||
@Slf4j
|
||||
public class CustomTaskWrapper implements TaskWrapper {
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "custom";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable wrap(Runnable runnable) {
|
||||
return new MyRunnable(runnable);
|
||||
}
|
||||
|
||||
public static class MyRunnable implements Runnable {
|
||||
|
||||
private final Runnable runnable;
|
||||
|
||||
public MyRunnable(Runnable runnable) {
|
||||
this.runnable = runnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
log.info("before run");
|
||||
runnable.run();
|
||||
log.info("after run");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
# 动态线程池配置文件,建议单独开一个文件放到配置中心,字段详解看readme介绍
|
||||
spring:
|
||||
dynamic:
|
||||
tp:
|
||||
enabled: true
|
||||
enabledBanner: true # 是否开启banner打印,默认true
|
||||
enabledCollect: false # 是否开启监控指标采集,默认false
|
||||
collectorTypes: micrometer,logging # 监控数据采集器类型(logging | micrometer | internal_logging),默认micrometer
|
||||
logPath: ${user.home}/dynamic-tp/logs # 监控日志数据路径,默认 ${user.home}/logs
|
||||
monitorInterval: 5 # 监控时间间隔(报警判断、指标采集),默认5s
|
||||
platforms: # 通知报警平台配置
|
||||
- platform: wechat
|
||||
urlKey: 3a7500-1287-4bd-a798-c5c3d8b69c # 替换
|
||||
receivers: test1,test2 # 接受人企微名称
|
||||
- platform: ding
|
||||
urlKey: f80dad441fcd655438f4a08dcd6a # 替换
|
||||
secret: SECb5441fa6f375d5b9d21 # 替换,非sign模式可以没有此值
|
||||
receivers: 15810119805 # 钉钉账号手机号
|
||||
- platform: lark
|
||||
urlKey: 0d944ae7-b24a-40 # 替换
|
||||
receivers: test1,test2 # 接受人飞书名称/openid
|
||||
tomcatTp: # tomcat web server线程池配置
|
||||
corePoolSize: 100
|
||||
maximumPoolSize: 400
|
||||
keepAliveTime: 60
|
||||
jettyTp: # jetty web server线程池配置
|
||||
corePoolSize: 100
|
||||
maximumPoolSize: 400
|
||||
undertowTp: # undertow web server线程池配置
|
||||
corePoolSize: 100
|
||||
maximumPoolSize: 400
|
||||
keepAliveTime: 60
|
||||
hystrixTp: # hystrix 线程池配置
|
||||
- threadPoolName: hystrix1
|
||||
corePoolSize: 100
|
||||
maximumPoolSize: 400
|
||||
keepAliveTime: 60
|
||||
dubboTp: # dubbo 线程池配置
|
||||
- threadPoolName: dubboTp#20880
|
||||
corePoolSize: 100
|
||||
maximumPoolSize: 400
|
||||
keepAliveTime: 60
|
||||
rocketMqTp: # rocketmq 线程池配置
|
||||
- threadPoolName: group1#topic1
|
||||
corePoolSize: 200
|
||||
maximumPoolSize: 400
|
||||
keepAliveTime: 60
|
||||
executors: # 动态线程池配置,都有默认值,采用默认值的可以不配置该项,减少配置量
|
||||
- threadPoolName: dtpExecutor1
|
||||
executorType: common # 线程池类型common、eager:适用于io密集型
|
||||
corePoolSize: 6
|
||||
maximumPoolSize: 8
|
||||
queueCapacity: 200
|
||||
queueType: VariableLinkedBlockingQueue # 任务队列,查看源码QueueTypeEnum枚举类
|
||||
rejectedHandlerType: CallerRunsPolicy # 拒绝策略,查看RejectedTypeEnum枚举类
|
||||
keepAliveTime: 50
|
||||
allowCoreThreadTimeOut: false # 是否允许核心线程池超时
|
||||
threadNamePrefix: test # 线程名前缀
|
||||
waitForTasksToCompleteOnShutdown: false # 参考spring线程池设计,优雅关闭线程池
|
||||
awaitTerminationSeconds: 5 # 单位(s)
|
||||
preStartAllCoreThreads: false # 是否预热所有核心线程,默认false
|
||||
runTimeout: 200 # 任务执行超时阈值,目前只做告警用,单位(ms)
|
||||
queueTimeout: 100 # 任务在队列等待超时阈值,目前只做告警用,单位(ms)
|
||||
taskWrapperNames: ["ttl"] # 任务包装器名称,集成TaskWrapper接口
|
||||
notifyItems: # 报警项,不配置自动会按默认值配置(变更通知、容量报警、活性报警、拒绝报警、任务超时报警)
|
||||
- type: capacity # 报警项类型,查看源码 NotifyTypeEnum枚举类
|
||||
enabled: true
|
||||
threshold: 80 # 报警阈值
|
||||
platforms: [ding,wechat] # 可选配置,不配置默认拿上层platforms配置的所以平台
|
||||
interval: 120 # 报警间隔(单位:s)
|
||||
- type: change
|
||||
enabled: true
|
||||
- type: liveness
|
||||
enabled: true
|
||||
threshold: 80
|
||||
- type: reject
|
||||
enabled: true
|
||||
threshold: 1
|
||||
- type: run_timeout
|
||||
enabled: true
|
||||
threshold: 1
|
||||
- type: queue_timeout
|
||||
enabled: true
|
||||
threshold: 1
|
||||
- threadPoolName: orderedDtpExecutor
|
||||
executorType: ordered
|
||||
corePoolSize: 4
|
||||
maximumPoolSize: 6
|
||||
queueCapacity: 2000
|
||||
queueType: VariableLinkedBlockingQueue
|
||||
rejectedHandlerType: CallerRunsPolicy
|
||||
keepAliveTime: 50
|
||||
allowCoreThreadTimeOut: false
|
||||
threadNamePrefix: test
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<properties>
|
||||
<!-- BladeX-Tool Version -->
|
||||
<revision>4.10.0.RELEASE</revision>
|
||||
<revision>4.10.0.BASE-SNAPSHOT</revision>
|
||||
|
||||
<java.version>17</java.version>
|
||||
<maven.plugin.version>3.14.1</maven.plugin.version>
|
||||
@@ -120,6 +120,7 @@
|
||||
<module>blade-starter-trace</module>
|
||||
<module>blade-starter-transaction</module>
|
||||
<module>blade-starter-xss</module>
|
||||
<module>blade-starter-threadpool</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -941,6 +942,11 @@
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.27</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-threadpool</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
@@ -1059,11 +1065,11 @@
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>bladex</id>
|
||||
<name>BladeX Release Repository</name>
|
||||
<url>https://center.javablade.com/api/packages/blade/maven</url>
|
||||
</repository>
|
||||
<!-- <repository>-->
|
||||
<!-- <id>bladex</id>-->
|
||||
<!-- <name>BladeX Release Repository</name>-->
|
||||
<!-- <url>https://center.javablade.com/api/packages/blade/maven</url>-->
|
||||
<!-- </repository>-->
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
@@ -1076,18 +1082,18 @@
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>bladex</id>
|
||||
<name>BladeX Release Repository</name>
|
||||
<url>https://center.javablade.com/api/packages/blade/maven</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>bladex</id>
|
||||
<name>BladeX Snapshot Repository</name>
|
||||
<url>https://center.javablade.com/api/packages/blade/maven</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
<!-- <distributionManagement>-->
|
||||
<!-- <repository>-->
|
||||
<!-- <id>bladex</id>-->
|
||||
<!-- <name>BladeX Release Repository</name>-->
|
||||
<!-- <url>https://center.javablade.com/api/packages/blade/maven</url>-->
|
||||
<!-- </repository>-->
|
||||
<!-- <snapshotRepository>-->
|
||||
<!-- <id>bladex</id>-->
|
||||
<!-- <name>BladeX Snapshot Repository</name>-->
|
||||
<!-- <url>https://center.javablade.com/api/packages/blade/maven</url>-->
|
||||
<!-- </snapshotRepository>-->
|
||||
<!-- </distributionManagement>-->
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
|
||||
Reference in New Issue
Block a user