From e2de84d5a91fa7bd09eb59c5c5acc11e857da9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 28 May 2026 15:30:32 +0800 Subject: [PATCH 1/7] =?UTF-8?q?refactor(project):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E9=85=8D=E7=BD=AE=E5=92=8C=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新 Docker Compose 配置从版本 1 到 3.8,并修改服务构建方式 - 将异常处理中的 ResponseCode 替换为 SystemStatus 枚举 - 统一全局异常处理器返回类型为 RetObj,替换原有的 GenericResponse - 修复 JWT 工具类中的空指针判断逻辑错误 - 优化 RSA 加密工具类,使用 Java 自带 Base64 实现替代 Apache 工具类 - 添加 Spring Security 密码编码器支持,增强用户密码安全性 - 完善日志配置文件,增加多种环境的日志输出策略 - 优化 Dockerfile 使用 JDK 17 环境并改进构建参数配置 --- Dockerfile | 29 +++---- pom.xml | 4 + .../basedemo/common/enums/SystemStatus.java | 7 +- .../common/exception/BusinessException.java | 21 ++--- .../exception/GlobalExceptionHandler.java | 22 ++--- .../common/exception/LoginException.java | 21 ++--- .../cn/xf/basedemo/common/model/RetObj.java | 8 +- .../basedemo/common/utils/JwtTokenUtils.java | 2 +- .../cn/xf/basedemo/common/utils/RSAUtils.java | 30 +++---- .../common/utils/RequestHeaderUtil.java | 4 +- .../interceptor/TokenInterceptor.java | 15 ++-- .../service/impl/UserServiceImpl.java | 12 +-- .../resources/docker/boot-docker-compose.yml | 12 +-- src/main/resources/logback-spring.xml | 85 +++++++++++++++++++ 14 files changed, 180 insertions(+), 92 deletions(-) create mode 100644 src/main/resources/logback-spring.xml diff --git a/Dockerfile b/Dockerfile index 5f05bca..d5640e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,17 @@ -# java8运行环境 -FROM openjdk:8-jdk-alpine -# 作者名称 -MAINTAINER xiongfeng +# 使用 JDK 17 轻量级运行环境 +FROM eclipse-temurin:17-jre-alpine + +# 作者信息 +LABEL maintainer="xiongfeng" # 切换工作目录 WORKDIR /root/java -#1. coding自动化部署 -#COPY target/*.jar app.jar -## 暴露端口8080 -##EXPOSE 8080 -## 运行命令 -#ENTRYPOINT ["java","-Djava.security.egd=file:/dev/urandom","-Dfile.encoding=UTF-8","-Duser.timezone=Asia/Shanghai","-XX:MaxDirectMemorySize=1024m","-XX:MetaspaceSize=256m","-XX:MaxMetaspaceSize=512m","-XX:MaxRAMPercentage=80.0","-jar","app.jar"] +# 将编译好的 jar 包复制到容器中,避免硬编码包名版本号 +COPY target/*.jar app.jar -#2. 手动部署项目到docker环境中 -# 添加demo-start-1.0.0.jar文件到docker环境内 -ADD xf-boot-base-1.0.1.jar /root/java/xf-boot-base-1.0.1.jar -## 暴露端口8080 -#EXPOSE 8080 -## 运行命令 -ENTRYPOINT ["java", "-server", "-Xms512m", "-Xmx512m", "-jar", "/root/java/xf-boot-base-1.0.1.jar"] +# 暴露端口 8089 (对齐 application.yml) +EXPOSE 8089 + +# 运行命令,加入垃圾回收和内存优化参数,以及时区与字符编码设置 +ENTRYPOINT ["java", "-server", "-Xms512m", "-Xmx512m", "-Dfile.encoding=UTF-8", "-Duser.timezone=Asia/Shanghai", "-jar", "app.jar"] diff --git a/pom.xml b/pom.xml index d2a9b18..d356dbc 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,10 @@ java-jwt ${jwt.version} + + org.springframework.security + spring-security-crypto + org.apache.commons diff --git a/src/main/java/cn/xf/basedemo/common/enums/SystemStatus.java b/src/main/java/cn/xf/basedemo/common/enums/SystemStatus.java index 764de77..15c5d61 100644 --- a/src/main/java/cn/xf/basedemo/common/enums/SystemStatus.java +++ b/src/main/java/cn/xf/basedemo/common/enums/SystemStatus.java @@ -5,8 +5,11 @@ import lombok.Getter; @Getter public enum SystemStatus { - SUSSES(200, "请求成功"), - UNAVAILABILITY(401, "token无效"), + SUCCESS(200, "请求成功"), + USER_INPUT_ERROR(400, "参数或用户输入错误"), + UNAUTHORIZED(401, "token无效"), + FORBIDDEN(403, "禁止访问"), + TOO_FREQUENT_VISIT(429, "访问太频繁,请休息一会儿"), ERROR(500, "系统异常") ; diff --git a/src/main/java/cn/xf/basedemo/common/exception/BusinessException.java b/src/main/java/cn/xf/basedemo/common/exception/BusinessException.java index 23be9d2..65d8c56 100644 --- a/src/main/java/cn/xf/basedemo/common/exception/BusinessException.java +++ b/src/main/java/cn/xf/basedemo/common/exception/BusinessException.java @@ -1,5 +1,6 @@ package cn.xf.basedemo.common.exception; +import cn.xf.basedemo.common.enums.SystemStatus; import lombok.Getter; /** @@ -10,29 +11,29 @@ import lombok.Getter; */ @Getter public class BusinessException extends RuntimeException{ - private final ResponseCode code; + private final SystemStatus status; public BusinessException() { - super(String.format("%s", ResponseCode.INTERNAL_ERROR.getMessage())); - this.code = ResponseCode.INTERNAL_ERROR; + super(String.format("%s", SystemStatus.ERROR.getErrorMessage())); + this.status = SystemStatus.ERROR; } public BusinessException(Throwable e) { super(e); - this.code = ResponseCode.INTERNAL_ERROR; + this.status = SystemStatus.ERROR; } public BusinessException(String msg) { - this(ResponseCode.INTERNAL_ERROR, msg); + this(SystemStatus.ERROR, msg); } - public BusinessException(ResponseCode code) { - super(String.format("%s", code.getMessage())); - this.code = code; + public BusinessException(SystemStatus status) { + super(String.format("%s", status.getErrorMessage())); + this.status = status; } - public BusinessException(ResponseCode code, String msg) { + public BusinessException(SystemStatus status, String msg) { super(msg); - this.code = code; + this.status = status; } } diff --git a/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionHandler.java b/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionHandler.java index 0bcc700..42bbd7a 100644 --- a/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionHandler.java +++ b/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionHandler.java @@ -1,5 +1,7 @@ package cn.xf.basedemo.common.exception; +import cn.xf.basedemo.common.enums.SystemStatus; +import cn.xf.basedemo.common.model.RetObj; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.validation.BindException; @@ -28,9 +30,9 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(LoginException.class) @ResponseStatus(HttpStatus.FORBIDDEN) - public GenericResponse handleLoginException(LoginException e, HttpServletRequest request) { - log.warn("认证失败 [URL:{}]: code={}, message={}", request.getRequestURI(), e.getCode(), e.getMessage()); - return new GenericResponse<>(e.getCode(), null, e.getMessage()); + public RetObj handleLoginException(LoginException e, HttpServletRequest request) { + log.warn("认证失败 [URL:{}]: code={}, message={}", request.getRequestURI(), e.getStatus().getCode(), e.getMessage()); + return new RetObj<>(e.getStatus().getCode(), e.getMessage()); } /** @@ -38,9 +40,9 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(BusinessException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) // 或者使用 HttpStatus.OK,根据前端约定 - public GenericResponse handleBusinessException(BusinessException e, HttpServletRequest request) { - log.warn("业务异常 [URL:{}]: code={}, message={}", request.getRequestURI(), e.getCode(), e.getMessage()); - return new GenericResponse<>(e.getCode(), null, e.getMessage()); + public RetObj handleBusinessException(BusinessException e, HttpServletRequest request) { + log.warn("业务异常 [URL:{}]: code={}, message={}", request.getRequestURI(), e.getStatus().getCode(), e.getMessage()); + return new RetObj<>(e.getStatus().getCode(), e.getMessage()); } /** @@ -48,7 +50,7 @@ public class GlobalExceptionHandler { */ @ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class }) @ResponseStatus(HttpStatus.BAD_REQUEST) - public GenericResponse handleValidationException(Exception e, HttpServletRequest request) { + public RetObj handleValidationException(Exception e, HttpServletRequest request) { BindingResult bindingResult = null; if (e instanceof MethodArgumentNotValidException) { bindingResult = ((MethodArgumentNotValidException) e).getBindingResult(); @@ -64,7 +66,7 @@ public class GlobalExceptionHandler { } } log.warn("参数校验失败 [URL:{}]: {}", request.getRequestURI(), errorMsg); - return new GenericResponse<>(ResponseCode.USER_INPUT_ERROR.getCode(), null, errorMsg); + return new RetObj<>(SystemStatus.USER_INPUT_ERROR.getCode(), errorMsg); } /** @@ -72,9 +74,9 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public GenericResponse handleSystemException(Exception e, HttpServletRequest request) { + public RetObj handleSystemException(Exception e, HttpServletRequest request) { // 生产级关键点:必须记录异常堆栈,否则无法排查 BUG log.error("系统发生未知异常 [URL:{}]", request.getRequestURI(), e); - return new GenericResponse<>(500, null, "系统内部繁忙,请稍后再试"); + return new RetObj<>(SystemStatus.ERROR.getCode(), "系统内部繁忙,请稍后再试"); } } diff --git a/src/main/java/cn/xf/basedemo/common/exception/LoginException.java b/src/main/java/cn/xf/basedemo/common/exception/LoginException.java index 2cdeeec..f415378 100644 --- a/src/main/java/cn/xf/basedemo/common/exception/LoginException.java +++ b/src/main/java/cn/xf/basedemo/common/exception/LoginException.java @@ -1,5 +1,6 @@ package cn.xf.basedemo.common.exception; +import cn.xf.basedemo.common.enums.SystemStatus; import lombok.Getter; /** @@ -11,30 +12,30 @@ import lombok.Getter; @Getter public class LoginException extends RuntimeException{ - private final ResponseCode code; + private final SystemStatus status; public LoginException() { - super(String.format("%s", ResponseCode.AUTHENTICATION_NEEDED.getMessage())); - this.code = ResponseCode.AUTHENTICATION_NEEDED; + super(String.format("%s", SystemStatus.UNAUTHORIZED.getErrorMessage())); + this.status = SystemStatus.UNAUTHORIZED; } public LoginException(Throwable e) { super(e); - this.code = ResponseCode.AUTHENTICATION_NEEDED; + this.status = SystemStatus.UNAUTHORIZED; } public LoginException(String msg) { - this(ResponseCode.AUTHENTICATION_NEEDED, msg); + this(SystemStatus.UNAUTHORIZED, msg); } - public LoginException(ResponseCode code) { - super(String.format("%s", code.getMessage())); - this.code = code; + public LoginException(SystemStatus status) { + super(String.format("%s", status.getErrorMessage())); + this.status = status; } - public LoginException(ResponseCode code, String msg) { + public LoginException(SystemStatus status, String msg) { super(msg); - this.code = code; + this.status = status; } } diff --git a/src/main/java/cn/xf/basedemo/common/model/RetObj.java b/src/main/java/cn/xf/basedemo/common/model/RetObj.java index 282a3c2..85a4468 100644 --- a/src/main/java/cn/xf/basedemo/common/model/RetObj.java +++ b/src/main/java/cn/xf/basedemo/common/model/RetObj.java @@ -46,20 +46,20 @@ public class RetObj { } public static RetObj success() { - return new RetObj(SystemStatus.SUSSES); + return new RetObj<>(SystemStatus.SUCCESS); } public static RetObj success(T data) { - return new RetObj(SystemStatus.SUSSES, data); + return new RetObj<>(SystemStatus.SUCCESS, data); } public static RetObj error(SystemStatus status) { - return new RetObj(status); + return new RetObj<>(status); } public static RetObj error(String errorMsg) { - return new RetObj(SystemStatus.ERROR.getCode(), errorMsg); + return new RetObj<>(SystemStatus.ERROR.getCode(), errorMsg); } } diff --git a/src/main/java/cn/xf/basedemo/common/utils/JwtTokenUtils.java b/src/main/java/cn/xf/basedemo/common/utils/JwtTokenUtils.java index ce73bc5..d70958f 100644 --- a/src/main/java/cn/xf/basedemo/common/utils/JwtTokenUtils.java +++ b/src/main/java/cn/xf/basedemo/common/utils/JwtTokenUtils.java @@ -106,7 +106,7 @@ public class JwtTokenUtils { */ public static Integer getUserId(String token) { Map claims = verifyToken(token); - if (claims != null) { + if (claims == null) { return null; } diff --git a/src/main/java/cn/xf/basedemo/common/utils/RSAUtils.java b/src/main/java/cn/xf/basedemo/common/utils/RSAUtils.java index ab2fc3d..667d729 100644 --- a/src/main/java/cn/xf/basedemo/common/utils/RSAUtils.java +++ b/src/main/java/cn/xf/basedemo/common/utils/RSAUtils.java @@ -1,8 +1,5 @@ package cn.xf.basedemo.common.utils; -import org.apache.tomcat.util.codec.binary.Base64; -import org.apache.tomcat.util.http.fileupload.IOUtils; - import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; import java.security.*; @@ -11,6 +8,7 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -20,7 +18,7 @@ import java.util.Map; * @description: 加密工具类 * @author: xiongfeng * @create: 2022-06-20 10:37 - **/ + * **/ public class RSAUtils { //算法类型 @@ -49,10 +47,10 @@ public class RSAUtils { kpg.initialize(ENCRYPT_SIZE); KeyPair keyPair = kpg.generateKeyPair(); PublicKey aPublic = keyPair.getPublic(); - String publicKey = Base64.encodeBase64URLSafeString(aPublic.getEncoded()); + String publicKey = Base64.getUrlEncoder().withoutPadding().encodeToString(aPublic.getEncoded()); PrivateKey aPrivate = keyPair.getPrivate(); - String privateKey = Base64.encodeBase64URLSafeString(aPrivate.getEncoded()); + String privateKey = Base64.getUrlEncoder().withoutPadding().encodeToString(aPrivate.getEncoded()); Map map = new HashMap<>(); @@ -73,7 +71,7 @@ public class RSAUtils { public static RSAPublicKey getPublicKey(String publicKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException { // 通过X509编码的Key指令获得公钥对象 KeyFactory keyFactory = KeyFactory.getInstance(RSA); - X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64URLSafe(publicKeyStr)); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.getUrlDecoder().decode(publicKeyStr)); RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec); return key; } @@ -89,7 +87,7 @@ public class RSAUtils { public static RSAPrivateKey getPrivateKey(String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException { KeyFactory keyFactory = KeyFactory.getInstance(RSA); - PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64URLSafe(privateKeyStr)); + PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getUrlDecoder().decode(privateKeyStr)); RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8EncodedKeySpec); return privateKey; } @@ -109,8 +107,7 @@ public class RSAUtils { cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] bytes = cipher.doFinal(data.getBytes()); - return Base64.encodeBase64URLSafeString(bytes); -// return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength())); + return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); } catch (Exception e) { throw new RuntimeException(); } @@ -121,9 +118,7 @@ public class RSAUtils { Cipher cipher = Cipher.getInstance(RSA); cipher.init(Cipher.DECRYPT_MODE, privateKey); -// byte[] bytes = cipher.doFinal(Base64.decodeBase64(data.getBytes(CHARSET))); -// return new String(bytes); - return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data.getBytes(CHARSET), 0, data.getBytes(CHARSET).length), privateKey.getModulus().bitLength()), CHARSET); + return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.getUrlDecoder().decode(data.getBytes(CHARSET)), privateKey.getModulus().bitLength()), CHARSET); } catch (Exception e) { throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e); } @@ -137,11 +132,10 @@ public class RSAUtils { } else { maxBlock = keySize / 8 - 11; } - ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; - byte[] buff; int i = 0; - try { + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + byte[] buff; while (datas.length > offSet) { if (datas.length - offSet > maxBlock) { //可以调用以下的doFinal()方法完成加密或解密数据: @@ -153,12 +147,10 @@ public class RSAUtils { i++; offSet = i * maxBlock; } + return out.toByteArray(); } catch (Exception e) { throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e); } - byte[] resultDatas = out.toByteArray(); - IOUtils.closeQuietly(out); - return resultDatas; } public static void main(String[] args) { diff --git a/src/main/java/cn/xf/basedemo/common/utils/RequestHeaderUtil.java b/src/main/java/cn/xf/basedemo/common/utils/RequestHeaderUtil.java index 2846697..63a9d68 100644 --- a/src/main/java/cn/xf/basedemo/common/utils/RequestHeaderUtil.java +++ b/src/main/java/cn/xf/basedemo/common/utils/RequestHeaderUtil.java @@ -52,9 +52,9 @@ public class RequestHeaderUtil { public static String getToken(HttpServletRequest request) { //登录处理 String token = request.getHeader("Authorization"); - if (StringUtils.isEmpty(token)) + if (!StringUtils.hasText(token)) token = request.getParameter("token"); - if (StringUtils.isEmpty(token)) { + if (!StringUtils.hasText(token)) { throw new LoginException("请先登录"); } diff --git a/src/main/java/cn/xf/basedemo/interceptor/TokenInterceptor.java b/src/main/java/cn/xf/basedemo/interceptor/TokenInterceptor.java index 98daf8b..0cdbff2 100644 --- a/src/main/java/cn/xf/basedemo/interceptor/TokenInterceptor.java +++ b/src/main/java/cn/xf/basedemo/interceptor/TokenInterceptor.java @@ -1,7 +1,7 @@ package cn.xf.basedemo.interceptor; import cn.xf.basedemo.common.exception.LoginException; -import cn.xf.basedemo.common.exception.ResponseCode; +import cn.xf.basedemo.common.enums.SystemStatus; import cn.xf.basedemo.common.model.LoginUser; import cn.xf.basedemo.common.utils.ApplicationContextUtils; import com.alibaba.fastjson.JSONObject; @@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit; * @description: * @author: xiongfeng * @create: 2022-06-16 14:17 + * @component **/ @Component public class TokenInterceptor implements HandlerInterceptor { @@ -45,28 +46,28 @@ public class TokenInterceptor implements HandlerInterceptor { } //登录处理 String token = request.getHeader("Authorization"); - if (StringUtils.isEmpty(token)) + if (!StringUtils.hasText(token)) token = request.getParameter("token"); - if (StringUtils.isEmpty(token)) { + if (!StringUtils.hasText(token)) { throw new LoginException("请先登录"); }else { //验证token if (!token.startsWith("Bearer ")) { - throw new LoginException(ResponseCode.USER_INPUT_ERROR); + throw new LoginException(SystemStatus.USER_INPUT_ERROR); } token = token.substring(7); } String value = (String) redisTemplate.opsForValue().get("token:" + token); - if (StringUtils.isEmpty(value)) { + if (!StringUtils.hasText(value)) { throw new LoginException(); } JSONObject jsonObject = JSONObject.parseObject(value); //JSON对象转换成Java对象 LoginUser loginUserInfo = JSONObject.toJavaObject(jsonObject, LoginUser.class); if (loginUserInfo == null || loginUserInfo.getId() <= 0) { - throw new LoginException(ResponseCode.USER_INPUT_ERROR); + throw new LoginException(SystemStatus.USER_INPUT_ERROR); } - redisTemplate.expire(token, 86700, TimeUnit.SECONDS); + redisTemplate.expire("token:" + token, 86700, TimeUnit.SECONDS); //用户信息设置到上下文 SessionContext.getInstance().set(loginUserInfo); diff --git a/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java b/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java index 8d76202..a736644 100644 --- a/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java +++ b/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @@ -46,10 +47,12 @@ public class UserServiceImpl implements UserService { @Autowired private RedisTemplate redisTemplate; + private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + @Override public RetObj login(LoginInfoRes res) { - if (Objects.isNull(res) || StringUtils.isEmpty(res.getEncryptedData())) { + if (Objects.isNull(res) || !StringUtils.hasText(res.getEncryptedData())) { return null; } String loginJson = ""; @@ -65,15 +68,14 @@ public class UserServiceImpl implements UserService { e.printStackTrace(); return RetObj.error("账号或密码错误"); } - if (!StringUtils.isEmpty(loginInfo.check())) { + if (StringUtils.hasText(loginInfo.check())) { return RetObj.error(loginInfo.check()); } //校验登录账号密码 - QueryWrapper queryWrapper = new QueryWrapper(); + QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("account", loginInfo.getAccount()); - queryWrapper.eq("password", loginInfo.getPwd()); User user = userMapper.selectOne(queryWrapper); - if (Objects.isNull(user)) { + if (Objects.isNull(user) || !passwordEncoder.matches(loginInfo.getPwd(), user.getPassword())) { return RetObj.error("账号或密码错误"); } LoginUser loginUser = new LoginUser(); diff --git a/src/main/resources/docker/boot-docker-compose.yml b/src/main/resources/docker/boot-docker-compose.yml index 2658886..07f3e58 100644 --- a/src/main/resources/docker/boot-docker-compose.yml +++ b/src/main/resources/docker/boot-docker-compose.yml @@ -1,12 +1,14 @@ -version: '1' +version: '3.8' services: - boot_docker_compose: - image: remaindertime/boot_docker_compose:v1.0.0 - container_name: boot_docker_compose + xf-boot-base: + build: + context: ../../../ + dockerfile: Dockerfile + container_name: xf-boot-base environment: - SERVER_ADDRESS=120.48.109.209 - MYSQL_NAME=root - MYSQL_PWD=123456 - REDIS_PWD=123456 ports: - - 8090:8088 \ No newline at end of file + - 8089:8089 \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..77c427e --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,85 @@ + + + xf-boot-base + + + + + + + + ${log_pattern} + UTF-8 + + + + + + ${log_home}/base-info.log + + ${log_home}/base-%d{yyyy-MM-dd}-info.%i.log + 200MB + 30 + 10GB + + + ${log_pattern} + UTF-8 + + + INFO + + + + + + ${log_home}/base-error.log + + ${log_home}/base-%d{yyyy-MM-dd}-error.%i.log + 200MB + 30 + 5GB + + + ${log_pattern} + UTF-8 + + + ERROR + + + + + + + + + ${logIps} + 5 minutes + 5 seconds + 30 seconds + sleeping + + {"host":"${HOSTNAME}", "app_name":"${appName}"} + + + + + + + + + + + + + + + + + + + + + + From 548525acdd32b3df00fbc8227e3c45f2a7856295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 28 May 2026 15:31:38 +0800 Subject: [PATCH 2/7] =?UTF-8?q?remove(logback):=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E5=92=8C=E6=B5=8B=E8=AF=95=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E7=9A=84=E6=97=A5=E5=BF=97=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 src/main/resources/logback-spring-local.xml 配置文件 - 移除 src/main/resources/logback-spring-s.xml 配置文件 - 清理相关日志配置依赖项和属性设置 --- src/main/resources/logback-spring-local.xml | 88 --------------------- src/main/resources/logback-spring-s.xml | 32 -------- 2 files changed, 120 deletions(-) delete mode 100644 src/main/resources/logback-spring-local.xml delete mode 100644 src/main/resources/logback-spring-s.xml diff --git a/src/main/resources/logback-spring-local.xml b/src/main/resources/logback-spring-local.xml deleted file mode 100644 index 6a5ea82..0000000 --- a/src/main/resources/logback-spring-local.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - logback - - - - - - - - info - - - ${log_pattern} - UTF-8 - - - - - - ./${log_home}/base-%d{yyyy-MM-dd}-info.%i.log - - 200MB - - 3 - - - - %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n - UTF-8 - - - info - - - - - - ./${log_home}/base-%d{yyyy-MM-dd}-error.%i.log - - 200MB - - 3 - - - - %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n - UTF-8 - - - error - - - - - - - ${logIps} - - 5 minutes - - 5 seconds - - 30 second - - - sleeping - - {"host":"${HOSTNAME}", "app_name":"${appName}","plantVersion":"1"} - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/logback-spring-s.xml b/src/main/resources/logback-spring-s.xml deleted file mode 100644 index d13263e..0000000 --- a/src/main/resources/logback-spring-s.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - ${APP_NAME} - - - - ${LOG_FILE_PATH}/${APP_NAME}-%d{yyyy-MM-dd}.log - 30 - - - ${FILE_LOG_PATTERN} - - - - - - 120.48.109.209:4560 - - - - - - - - \ No newline at end of file From 6e5a3a3142766e383eec887a8856c6a5660ca9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 28 May 2026 15:33:55 +0800 Subject: [PATCH 3/7] =?UTF-8?q?refactor(common):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E9=80=9A=E7=94=A8=E5=93=8D=E5=BA=94=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除了 GenericResponse 类及其所有构造方法 - 移除了与 ResponseCode 枚举的关联逻辑 - 清理了相关的泛型数据封装结构 --- .../common/exception/GenericResponse.java | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 src/main/java/cn/xf/basedemo/common/exception/GenericResponse.java diff --git a/src/main/java/cn/xf/basedemo/common/exception/GenericResponse.java b/src/main/java/cn/xf/basedemo/common/exception/GenericResponse.java deleted file mode 100644 index 227a2c1..0000000 --- a/src/main/java/cn/xf/basedemo/common/exception/GenericResponse.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.xf.basedemo.common.exception; - -import lombok.Data; - -/** - * @Author: xiongfeng - * @CreateTime: 2023-11-08 13:47 - * @Description: TODO - * @Version: 1.0 - */ -@Data -public class GenericResponse { - private int code; - - private T data; - - private String message; - - public GenericResponse() {}; - - public GenericResponse(int code, T data) { - this.code = code; - this.data = data; - } - - public GenericResponse(int code, T data, String message) { - this(code, data); - this.message = message; - } - - public GenericResponse(ResponseCode responseCode) { - this.code = responseCode.getCode(); - this.data = null; - this.message = responseCode.getMessage(); - } - - public GenericResponse(ResponseCode responseCode, T data) { - this(responseCode); - this.data = data; - } - - public GenericResponse(ResponseCode responseCode, T data, String message) { - this(responseCode, data); - this.message = message; - } - -} From 9554192e8575e4d1e5bc9ed3e6cc5c4ca2ca9df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 28 May 2026 15:41:24 +0800 Subject: [PATCH 4/7] =?UTF-8?q?feat(config):=20=E5=90=AF=E7=94=A8=E9=A9=BC?= =?UTF-8?q?=E5=B3=B0=E5=91=BD=E5=90=8D=E5=88=B0=E4=B8=8B=E5=88=92=E7=BA=BF?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E5=B9=B6=E5=AE=8C=E5=96=84=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 application-local.yml 和 application-pre.yml 中 mybatis-plus 的 map-underscore-to-camel-case 设置为 true - 在 StringUtil 类中新增 camelToSnakeCase 方法用于驼峰转下划线命名 - 更新 camelToKebabCase 方法注释并修正转换逻辑 - 为 User 实体类添加 @TableId 注解配置自增主键 --- .../xf/basedemo/common/utils/StringUtil.java | 22 +++++++++++++++++-- .../cn/xf/basedemo/model/domain/User.java | 3 +++ src/main/resources/application-local.yml | 2 +- src/main/resources/application-pre.yml | 2 +- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/java/cn/xf/basedemo/common/utils/StringUtil.java b/src/main/java/cn/xf/basedemo/common/utils/StringUtil.java index 844163a..69359f1 100644 --- a/src/main/java/cn/xf/basedemo/common/utils/StringUtil.java +++ b/src/main/java/cn/xf/basedemo/common/utils/StringUtil.java @@ -10,10 +10,10 @@ package cn.xf.basedemo.common.utils; public class StringUtil { /** - * 驼峰命名法转下划线命名法 + * 驼峰命名法转短横线命名法(kebab-case) * * @param camelCase 驼峰命名法字符串 - * @return 下划线命名法字符串 + * @return 短横线命名法字符串 */ public static String camelToKebabCase(String camelCase) { if (camelCase == null || camelCase.isEmpty()) { @@ -26,4 +26,22 @@ public class StringUtil { // 转换为小写 return result.toLowerCase(); } + + /** + * 驼峰命名法转下划线命名法(snake_case) + * + * @param camelCase 驼峰命名法字符串 + * @return 下划线命名法字符串 + */ + public static String camelToSnakeCase(String camelCase) { + if (camelCase == null || camelCase.isEmpty()) { + return camelCase; + } + + // 使用正则表达式将大写字母前插入一个"_" + String result = camelCase.replaceAll("([a-z])([A-Z])", "$1_$2"); + + // 转换为小写 + return result.toLowerCase(); + } } diff --git a/src/main/java/cn/xf/basedemo/model/domain/User.java b/src/main/java/cn/xf/basedemo/model/domain/User.java index c506b2f..978afe5 100644 --- a/src/main/java/cn/xf/basedemo/model/domain/User.java +++ b/src/main/java/cn/xf/basedemo/model/domain/User.java @@ -1,5 +1,7 @@ package cn.xf.basedemo.model.domain; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -17,6 +19,7 @@ import java.util.Date; @TableName(value = "xf_user") public class User { + @TableId(value = "id", type = IdType.AUTO) private Integer id; private String name; diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 1964d39..64c3783 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -66,7 +66,7 @@ springdoc: mybatis-plus: configuration: - map-underscore-to-camel-case: false + map-underscore-to-camel-case: true auto-mapping-behavior: full #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印 mapper-locations: classpath*:mapper/**/*Mapper.xml diff --git a/src/main/resources/application-pre.yml b/src/main/resources/application-pre.yml index a172ef3..a911aa2 100644 --- a/src/main/resources/application-pre.yml +++ b/src/main/resources/application-pre.yml @@ -68,7 +68,7 @@ springdoc: mybatis-plus: configuration: - map-underscore-to-camel-case: false + map-underscore-to-camel-case: true auto-mapping-behavior: full #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印 mapper-locations: classpath*:mapper/**/*Mapper.xml From 270ac35e37bdf0242a4df28d541cbf1e0f800128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 28 May 2026 15:42:53 +0800 Subject: [PATCH 5/7] =?UTF-8?q?feat(config):=20=E5=90=AF=E7=94=A8=E9=A9=BC?= =?UTF-8?q?=E5=B3=B0=E5=91=BD=E5=90=8D=E5=88=B0=E4=B8=8B=E5=88=92=E7=BA=BF?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E5=B9=B6=E5=AE=8C=E5=96=84=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 application-local.yml 和 application-pre.yml 中 mybatis-plus 的 map-underscore-to-camel-case 设置为 true - 在 StringUtil 类中新增 camelToSnakeCase 方法用于驼峰转下划线命名 - 更新 camelToKebabCase 方法注释并修正转换逻辑 - 为 User 实体类添加 @TableId 注解配置自增主键 --- src/main/resources/application-local.yml | 93 ----------------------- src/main/resources/application-pre.yml | 96 ------------------------ 2 files changed, 189 deletions(-) delete mode 100644 src/main/resources/application-local.yml delete mode 100644 src/main/resources/application-pre.yml diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml deleted file mode 100644 index 64c3783..0000000 --- a/src/main/resources/application-local.yml +++ /dev/null @@ -1,93 +0,0 @@ -spring: - servlet: - multipart: - max-file-size: 20MB - max-request-size: 20MB - jackson: - date-format: yyyy-MM-dd HH:mm:ss - time-zone: GMT+8 - serialization: - WRITE_DATES_AS_TIMESTAMPS: false - FAIL_ON_EMPTY_BEANS: false - datasource: - dynamic: - primary: master - strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源. - hikari: - maximum-pool-size: 4 - minimum-idle: 4 - leak-detection-threshold: 0 - connection-init-sql: SELECT 1 - connection-test-query: SELECT 1 - datasource: - master: #${SERVER_ADDRESS} - url: jdbc:mysql://localhost:3307/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai - username: - password: - driver-class-name: com.mysql.cj.jdbc.Driver - slave: - url: jdbc:mysql://localhost:3307/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai - username: - password: - driver-class-name: com.mysql.cj.jdbc.Driver - - data: - redis: - port: 6379 - host: localhost - password: - timeout: 5000 - lettuce: #参考博客 https://blog.csdn.net/weixin_43944305/article/details/124322595 - pool: - maxActive: 5000 - maxIdle: 30 - minIdle: 5 - max-wait: 2000 - time-between-eviction-runs: 60s - cluster: - refresh: - adaptive: true - period: 60s - -global: - rsaPublicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC_F5UQC1QWsu3QsESQBz9M-GDA9Atm0qVSvwIsy568lyRLi-nq3VvvnmgrlL4yTbngFzyfb2Dn35cNCHsBvIaGuCY3_PpzPqMzVpxr2QlEkhEX9atnJQ1rWexS8QeZtPjpiIwoQrChTzXjD_sYUkDrqSykFplyivf0NSO2WqCBdwIDAQAB - rsaPrivateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL8XlRALVBay7dCwRJAHP0z4YMD0C2bSpVK_AizLnryXJEuL6erdW--eaCuUvjJNueAXPJ9vYOfflw0IewG8hoa4Jjf8-nM-ozNWnGvZCUSSERf1q2clDWtZ7FLxB5m0-OmIjChCsKFPNeMP-xhSQOupLKQWmXKK9_Q1I7ZaoIF3AgMBAAECgYBxTUA61Ry0oL7U_86HP2TO9G4ZuhmQi9EucMaPXOPvmgYRLRIzCbDbMKc_P-BN3zwYnG57cgSZNz9OoPqeGvP_oVTnkoEpVkCSV-JP2p_DK09LdbDqszJXMrxAkPmWGUw8IRMcTJT1xJJcgzFE6T0CmTo-Vk47AnmqfJD4U6o74QJBAPRjVUJKZnrMSnSqKPDL2ThgTo8h7-KFxl_Z-g724lTOFiCmBpi6nCWAcuacFRrrYqxF-r9c4zdIyR7AvLROql8CQQDIK_kRF52dVtwShciZhyeUBLoi0nWV9F8mMGt60NTEER9zPEgPsv2aVn8h97KMWOwmd2Da4EPm25QxOuaKQC_pAkBczcfXp5co9KElkmR_pHl1jiTm97U3qSM-zPDHc_tYxvXiKgoBP4QCPbfkWMsu8MoEr4Jb3vMt0EcHlZtTQTgzAkAfmNla-lhV4sUgY1_T5EK6GbjsED6hag6u74u3ukkrnexR-10ApWdkumydBwV3I_464DM4uZfeVCDjWIHVpuYpAkEA6QLPztGD4V8Q1PqTEeSF3i68CKPM8vO1_mCH2JD7qsqDQcIKkczj5rTg7hlOKwB9V6gSw4CbnOF6moTooRD-cQ - -springdoc: - api-docs: - path: /v3/api-docs # 自定义 API 文档路径 - swagger-ui: - path: /swagger-ui.html # 自定义 Swagger UI 路径 - enabled: true - info: - title: 文撩 API 文档 - description: 这是文撩平台的 API 文档 - version: v1.0 - -mybatis-plus: - configuration: - map-underscore-to-camel-case: true - auto-mapping-behavior: full - #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印 - mapper-locations: classpath*:mapper/**/*Mapper.xml - global-config: - # 逻辑删除配置 - db-config: - update-strategy: IGNORED - # 删除前 - logic-not-delete-value: 1 - # 删除后 - logic-delete-value: 0 - -# 参考文章 https://zhuanlan.zhihu.com/p/145359625 -management: - health: - elasticsearch: #禁用健康检查 - enabled: false - endpoints: - web: - exposure: - include: "health" - endpoint: - health: - show-details: always \ No newline at end of file diff --git a/src/main/resources/application-pre.yml b/src/main/resources/application-pre.yml deleted file mode 100644 index a911aa2..0000000 --- a/src/main/resources/application-pre.yml +++ /dev/null @@ -1,96 +0,0 @@ -spring: - datasource: - dynamic: - primary: master - strict: true #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源. - hikari: - minimum-idle: 4 - maximum-pool-size: 4 - connection-init-sql: SELECT 1 - connection-test-query: SELECT 1 - datasource: - master: #${SERVER_ADDRESS} - url: jdbc:mysql://${SERVER_ADDRESS}:3306/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai - username: ${MYSQL_NAME} - password: ${MYSQL_PWD} - driver-class-name: com.mysql.cj.jdbc.Driver - slave: - url: jdbc:mysql://${SERVER_ADDRESS}:3306/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai - username: ${MYSQL_NAME} - password: ${MYSQL_PWD} - driver-class-name: com.mysql.cj.jdbc.Driver - data: - redis: - port: 6379 #Redis服务器连接的端口 - host: ${SERVER_ADDRESS} # Redis服务器的地址 - password: ${REDIS_PWD} # Redis服务器连接密码(默认为空) - timeout: 5000 # 连接超时时间(毫秒) - lettuce: #参考博客 https://blog.csdn.net/weixin_43944305/article/details/124322595 - pool: - maxActive: 5000 #最大连接数 - maxIdle: 30 #连接池最大空闲连接数. - minIdle: 5 #连接池最小空闲连接数. - max-wait: 2000 #从连接池中获取连接时的最大等待时间 - time-between-eviction-runs: 60s #空闲对象逐出器线程的运行间隔时间.空闲连接线程释放周期时间. - cluster: - refresh: - adaptive: true #拓扑动态感应即客户端能够根据 redis cluster 集群的变化,动态改变客户端的节点情况,完成故障转移。 - period: 60s #刷新redis集群状态周期时间 - -global: - rsaPublicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC_F5UQC1QWsu3QsESQBz9M-GDA9Atm0qVSvwIsy568lyRLi-nq3VvvnmgrlL4yTbngFzyfb2Dn35cNCHsBvIaGuCY3_PpzPqMzVpxr2QlEkhEX9atnJQ1rWexS8QeZtPjpiIwoQrChTzXjD_sYUkDrqSykFplyivf0NSO2WqCBdwIDAQAB - rsaPrivateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL8XlRALVBay7dCwRJAHP0z4YMD0C2bSpVK_AizLnryXJEuL6erdW--eaCuUvjJNueAXPJ9vYOfflw0IewG8hoa4Jjf8-nM-ozNWnGvZCUSSERf1q2clDWtZ7FLxB5m0-OmIjChCsKFPNeMP-xhSQOupLKQWmXKK9_Q1I7ZaoIF3AgMBAAECgYBxTUA61Ry0oL7U_86HP2TO9G4ZuhmQi9EucMaPXOPvmgYRLRIzCbDbMKc_P-BN3zwYnG57cgSZNz9OoPqeGvP_oVTnkoEpVkCSV-JP2p_DK09LdbDqszJXMrxAkPmWGUw8IRMcTJT1xJJcgzFE6T0CmTo-Vk47AnmqfJD4U6o74QJBAPRjVUJKZnrMSnSqKPDL2ThgTo8h7-KFxl_Z-g724lTOFiCmBpi6nCWAcuacFRrrYqxF-r9c4zdIyR7AvLROql8CQQDIK_kRF52dVtwShciZhyeUBLoi0nWV9F8mMGt60NTEER9zPEgPsv2aVn8h97KMWOwmd2Da4EPm25QxOuaKQC_pAkBczcfXp5co9KElkmR_pHl1jiTm97U3qSM-zPDHc_tYxvXiKgoBP4QCPbfkWMsu8MoEr4Jb3vMt0EcHlZtTQTgzAkAfmNla-lhV4sUgY1_T5EK6GbjsED6hag6u74u3ukkrnexR-10ApWdkumydBwV3I_464DM4uZfeVCDjWIHVpuYpAkEA6QLPztGD4V8Q1PqTEeSF3i68CKPM8vO1_mCH2JD7qsqDQcIKkczj5rTg7hlOKwB9V6gSw4CbnOF6moTooRD-cQ - -elasticsearch: - host: localhost - port: 9200 - username: elastic - password: bz5oF*MGy8pKL_I=7KxY #window系统本地启动 es8.x 重置密码命令:.\elasticsearch-reset-password -u elastic - -rocketmq: - name-server: ${SERVER_ADDRESS}:9876 - producer: - group: producer-group - consumer: - group: consumer-group - enable-orderly: false - -springdoc: - api-docs: - path: /v3/api-docs # 自定义 API 文档路径 - swagger-ui: - path: /swagger-ui.html # 自定义 Swagger UI 路径 - enabled: true - info: - title: 文撩 API 文档 - description: 这是文撩平台的 API 文档 - version: v1.0 - -mybatis-plus: - configuration: - map-underscore-to-camel-case: true - auto-mapping-behavior: full - #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印 - mapper-locations: classpath*:mapper/**/*Mapper.xml - global-config: - # 逻辑删除配置 - db-config: - update-strategy: IGNORED - # 删除前 - logic-not-delete-value: 1 - # 删除后 - logic-delete-value: 0 - -# 参考文章 https://zhuanlan.zhihu.com/p/145359625 -management: - health: - elasticsearch: #禁用健康检查 - enabled: false - endpoints: - web: - exposure: - include: "health" - endpoint: - health: - show-details: always - From 2b123df3cf8d2b31605e1d4ca50b3acf655f0459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 28 May 2026 15:48:47 +0800 Subject: [PATCH 6/7] =?UTF-8?q?feat(config):=20=E6=B7=BB=E5=8A=A0=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=BC=82=E6=AD=A5=E7=BA=BF=E7=A8=8B=E6=B1=A0=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 防止默认线程池因无界队列引发 OOM 问题 - 配置核心线程数为 10,最大线程数为 50 - 设置缓冲队列容量为 1000,避免任务堆积 - 配置空闲线程存活时间为 60 秒 - 采用 CallerRunsPolicy 拒绝策略保证任务不丢失 - 启用优雅停机配置等待任务完成 --- .../xf/basedemo/config/ThreadPoolConfig.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/main/java/cn/xf/basedemo/config/ThreadPoolConfig.java diff --git a/src/main/java/cn/xf/basedemo/config/ThreadPoolConfig.java b/src/main/java/cn/xf/basedemo/config/ThreadPoolConfig.java new file mode 100644 index 0000000..e8c5a4c --- /dev/null +++ b/src/main/java/cn/xf/basedemo/config/ThreadPoolConfig.java @@ -0,0 +1,50 @@ +package cn.xf.basedemo.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @Description: 统一异步线程池配置类(防止默认线程池由于无界队列引发 OOM) + * @Author: xiongfeng + * @Date: 2026/5/28 + * @Version: 1.0 + */ +@Slf4j +@Configuration +@EnableAsync +public class ThreadPoolConfig { + + @Bean(name = "asyncServiceExecutor") + public Executor asyncServiceExecutor() { + log.info("初始化异步线程池 [asyncServiceExecutor] 开始..."); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + + // 核心线程数:根据 CPU 核心数与业务性质配置(此处设为 10) + executor.setCorePoolSize(10); + // 最大线程数:高并发时能够支持的最大线程数 + executor.setMaxPoolSize(50); + // 缓冲队列容量:限制任务队列大小,防止无界队列堆积导致 OOM + executor.setQueueCapacity(1000); + // 空闲线程存活时间(秒) + executor.setKeepAliveSeconds(60); + // 线程名称前缀 + executor.setThreadNamePrefix("async-executor-"); + + // 拒绝策略:当队列满且达到最大线程数时,由调用者线程直接执行任务(保证任务不丢失,同时降低提交速度) + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + + // 优雅停机配置 + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + + executor.initialize(); + log.info("初始化异步线程池 [asyncServiceExecutor] 成功!"); + return executor; + } +} From 39df5c5945d062c455662f086583dba1025d6b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 28 May 2026 15:50:58 +0800 Subject: [PATCH 7/7] =?UTF-8?q?chore(config):=20=E5=88=A0=E9=99=A4=20ELK?= =?UTF-8?q?=20Docker=20Compose=20=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 elasticsearch 服务配置(端口 9200) - 移除 kibana 服务配置(端口 5601) - 移除 logstash 服务配置(端口 4560) - 清理相关容器挂载卷和依赖关系配置 --- .../resources/docker/elk_docker-compose.yml | 36 ------------------- .../resources/docker/logstash-springboot.conf | 14 -------- 2 files changed, 50 deletions(-) delete mode 100644 src/main/resources/docker/elk_docker-compose.yml delete mode 100644 src/main/resources/docker/logstash-springboot.conf diff --git a/src/main/resources/docker/elk_docker-compose.yml b/src/main/resources/docker/elk_docker-compose.yml deleted file mode 100644 index 708c8ed..0000000 --- a/src/main/resources/docker/elk_docker-compose.yml +++ /dev/null @@ -1,36 +0,0 @@ -version: '3' -services: - elasticsearch: - image: elasticsearch:6.4.0 - container_name: elasticsearch - environment: - - "cluster.name=elasticsearch" #设置集群名称为elasticsearch - - "discovery.type=single-node" #以单一节点模式启动 - - "ES_JAVA_OPTS=-Xms512m -Xmx512m" #设置使用jvm内存大小 - volumes: - - /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins #插件文件挂载 - - /mydata/elasticsearch/data:/usr/share/elasticsearch/data #数据文件挂载 - ports: - - 9200:9200 - kibana: - image: kibana:6.4.0 - container_name: kibana - links: - - elasticsearch:es #可以用es这个域名访问elasticsearch服务 - depends_on: - - elasticsearch #kibana在elasticsearch启动之后再启动 - environment: - - "elasticsearch.hosts=http://es:9200" #设置访问elasticsearch的地址 - ports: - - 5601:5601 - logstash: - image: logstash:6.4.0 - container_name: logstash - volumes: - - /mydata/logstash/logstash-springboot.conf:/usr/share/logstash/pipeline/logstash.conf #挂载logstash的配置文件 - depends_on: - - elasticsearch #kibana在elasticsearch启动之后再启动 - links: - - elasticsearch:es #可以用es这个域名访问elasticsearch服务 - ports: - - 4560:4560 \ No newline at end of file diff --git a/src/main/resources/docker/logstash-springboot.conf b/src/main/resources/docker/logstash-springboot.conf deleted file mode 100644 index a71e919..0000000 --- a/src/main/resources/docker/logstash-springboot.conf +++ /dev/null @@ -1,14 +0,0 @@ -input { - tcp { - mode => "server" - host => "0.0.0.0" - port => 4560 - codec => json_lines - } -} -output { - elasticsearch { - hosts => "es:9200" - index => "springboot-logstash-%{+YYYY.MM.dd}" - } -} \ No newline at end of file