From 50c80949e41d6986a6b517154993b983ffe5e0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 11 Sep 2025 18:04:20 +0800 Subject: [PATCH 01/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9maven=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ef99405..3cec8ca 100644 --- a/pom.xml +++ b/pom.xml @@ -147,9 +147,10 @@ org.apache.maven.plugins maven-compiler-plugin + 3.8.1 - 14 - 14 + 1.8 + 1.8 From a891783de136c96c60bdb0fcf1e44fc666120ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 11 Sep 2025 18:12:30 +0800 Subject: [PATCH 02/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9jdk=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 3cec8ca..e392d2f 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ xf-boot-base 拿来即用springboot单体脚手架项目 - 1.8 + 17 8.1.0 3.5.8 4.3.1 @@ -22,7 +22,7 @@ 3.19.2 2.11.1 2.0.8 - 5.3 + 5.3 2023.0.1.0 2023.0.1 8.16.0 @@ -149,8 +149,8 @@ maven-compiler-plugin 3.8.1 - 1.8 - 1.8 + 17 + 17 From 243f32773cf5524c654e5e0592f230def807099e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 11 Sep 2025 18:28:04 +0800 Subject: [PATCH 03/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9jdk=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index e392d2f..8b5f4c9 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ xf-boot-base 拿来即用springboot单体脚手架项目 - 17 + 11 8.1.0 3.5.8 4.3.1 @@ -147,10 +147,10 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.10.0 - 17 - 17 + 11 + 11 From 62b496afd3a1bb31523b7f5765276b051fbbd480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 11 Sep 2025 18:31:56 +0800 Subject: [PATCH 04/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9jdk=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 8b5f4c9..3bd139f 100644 --- a/pom.xml +++ b/pom.xml @@ -147,11 +147,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.0 - - 11 - 11 - + 3.8.1 From 3d89d3370dc059b81f05a5207fb141e7ba5bfc77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 11 Sep 2025 18:38:02 +0800 Subject: [PATCH 05/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9jdk=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3bd139f..dd844aa 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ xf-boot-base 拿来即用springboot单体脚手架项目 - 11 + 17 8.1.0 3.5.8 4.3.1 @@ -147,7 +147,11 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.11.0 + + 17 + 17 + From e2e2b0cb2f54d9e7e472704a11881a28f86b2829 Mon Sep 17 00:00:00 2001 From: xiongfeng <2439534736@qq.com> Date: Thu, 11 Sep 2025 22:26:28 +0800 Subject: [PATCH 06/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dd844aa..c7ffd0f 100644 --- a/pom.xml +++ b/pom.xml @@ -147,7 +147,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.10.1 17 17 From 28771743fa64375b7d4fb428e05fb06fe15ea830 Mon Sep 17 00:00:00 2001 From: xiongfeng <2439534736@qq.com> Date: Thu, 11 Sep 2025 22:41:21 +0800 Subject: [PATCH 07/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c7ffd0f..deda7a2 100644 --- a/pom.xml +++ b/pom.xml @@ -149,8 +149,7 @@ maven-compiler-plugin 3.10.1 - 17 - 17 + 17 From 691a4a21efcb723ae3b5ad36dfbd4ec77a2b7dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Fri, 12 Sep 2025 10:01:12 +0800 Subject: [PATCH 08/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9jdk=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index deda7a2..3143a76 100644 --- a/pom.xml +++ b/pom.xml @@ -147,7 +147,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.11.0 17 From 3d531b313e8391e03f1a4130e6590e6a726d8fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Fri, 12 Sep 2025 15:05:51 +0800 Subject: [PATCH 09/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9jdk=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3143a76..ce8847d 100644 --- a/pom.xml +++ b/pom.xml @@ -147,9 +147,11 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.11.0 - 17 + 17 + 17 + From d2819787e7e94ddfd3f3d43289852b2f5d5e33d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Fri, 12 Sep 2025 15:07:36 +0800 Subject: [PATCH 10/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9jdk=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index ce8847d..52ff9cc 100644 --- a/pom.xml +++ b/pom.xml @@ -128,6 +128,12 @@ elasticsearch-java ${elasticsearch.version} + + org.codehaus.plexus + plexus-compiler-javac + 2.15.0 + + From 800dc8f8782d41645029e4d31f9460e3f44db323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Fri, 12 Sep 2025 15:13:23 +0800 Subject: [PATCH 11/20] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 52ff9cc..9acd99d 100644 --- a/pom.xml +++ b/pom.xml @@ -128,12 +128,6 @@ elasticsearch-java ${elasticsearch.version} - - org.codehaus.plexus - plexus-compiler-javac - 2.15.0 - - @@ -155,10 +149,15 @@ maven-compiler-plugin 3.11.0 - 17 - 17 - + 17 + + + org.codehaus.plexus + plexus-compiler-javac + 2.15.0 + + From 56fdc150906dae903c26bcc1c7e9425a4e7e1cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Mon, 13 Oct 2025 15:21:33 +0800 Subject: [PATCH 12/20] =?UTF-8?q?=E9=9B=86=E6=88=90rocketMq=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E9=98=9F=E5=88=97=E6=94=B6=E5=8F=91=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 +++- .../xf/basedemo/config/SwaggerGroupApi.java | 16 +++++++- .../controller/business/UserController.java | 15 +++++-- .../interceptor/TokenInterceptor.java | 6 +++ .../xf/basedemo/mq/RocketMqMsgConsumer.java | 25 ++++++++++++ .../xf/basedemo/mq/RocketMqMsgProducer.java | 39 +++++++++++++++++++ .../cn/xf/basedemo/service/UserService.java | 2 + .../service/impl/UserServiceImpl.java | 12 ++++++ 8 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 src/main/java/cn/xf/basedemo/mq/RocketMqMsgConsumer.java create mode 100644 src/main/java/cn/xf/basedemo/mq/RocketMqMsgProducer.java diff --git a/pom.xml b/pom.xml index 9acd99d..ebcfba7 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 3.19.2 2.11.1 2.0.8 - 5.3 + 5.3 2023.0.1.0 2023.0.1 8.16.0 @@ -128,6 +128,12 @@ elasticsearch-java ${elasticsearch.version} + + + org.apache.rocketmq + rocketmq-spring-boot-starter + 2.3.4 + diff --git a/src/main/java/cn/xf/basedemo/config/SwaggerGroupApi.java b/src/main/java/cn/xf/basedemo/config/SwaggerGroupApi.java index 7648d59..c2eabcd 100644 --- a/src/main/java/cn/xf/basedemo/config/SwaggerGroupApi.java +++ b/src/main/java/cn/xf/basedemo/config/SwaggerGroupApi.java @@ -1,10 +1,13 @@ package cn.xf.basedemo.config; +import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.ExternalDocumentation; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; import org.springdoc.core.models.GroupedOpenApi; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @@ -21,6 +24,8 @@ public class SwaggerGroupApi { @Bean public OpenAPI springShopOpenAPI() { + // 定义全局安全方案名称 + String securitySchemeName = "Authorization"; return new OpenAPI() .info(new Info().title("Spring boot脚手架 API") .description("开箱即用的Spring boot脚手架 API") @@ -29,7 +34,16 @@ public class SwaggerGroupApi { .license(new License().name("Apache 2.0").url("http://springdoc.org"))) .externalDocs(new ExternalDocumentation() .description("Spring boot脚手架 Wiki Documentation") - .url("https://springshop.wiki.github.org/docs")); + .url("https://springshop.wiki.github.org/docs")) // 添加安全组件 + .components(new Components() + .addSecuritySchemes(securitySchemeName, + new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + )) + // 将安全方案应用到全局 + .addSecurityItem(new SecurityRequirement().addList(securitySchemeName)); } @Bean diff --git a/src/main/java/cn/xf/basedemo/controller/business/UserController.java b/src/main/java/cn/xf/basedemo/controller/business/UserController.java index 757ab8a..22598ad 100644 --- a/src/main/java/cn/xf/basedemo/controller/business/UserController.java +++ b/src/main/java/cn/xf/basedemo/controller/business/UserController.java @@ -27,28 +27,35 @@ public class UserController { @Operation(summary = "用户登录", description = "用户登录") @PostMapping("/login") - public RetObj login(@RequestBody LoginInfoRes res){ + public RetObj login(@RequestBody LoginInfoRes res) { return userService.login(res); } @Operation(summary = "用户信息", description = "用户信息") @PostMapping("/info") - public RetObj info(){ + public RetObj info() { LoginUser loginUser = SessionContext.getInstance().get(); return RetObj.success(loginUser); } @Operation(summary = "es同步用户信息", description = "用户信息") @GetMapping("/syncEs") - public RetObj syncEs(Long userId){ + public RetObj syncEs(Long userId) { return userService.syncEs(userId); } @Operation(summary = "es查询用户信息", description = "用户信息") @GetMapping("/getEsId") - public RetObj getEsId(Long userId){ + public RetObj getEsId(Long userId) { return userService.getEsId(userId); } + + //发送队列消息 + @Operation(summary = "发送队列消息", description = "发送队列消息") + @GetMapping("/sendMsg") + public RetObj sendMsg(String msg) { + return userService.sendMQMsg(msg); + } } diff --git a/src/main/java/cn/xf/basedemo/interceptor/TokenInterceptor.java b/src/main/java/cn/xf/basedemo/interceptor/TokenInterceptor.java index dc74858..98daf8b 100644 --- a/src/main/java/cn/xf/basedemo/interceptor/TokenInterceptor.java +++ b/src/main/java/cn/xf/basedemo/interceptor/TokenInterceptor.java @@ -49,6 +49,12 @@ public class TokenInterceptor implements HandlerInterceptor { token = request.getParameter("token"); if (StringUtils.isEmpty(token)) { throw new LoginException("请先登录"); + }else { + //验证token + if (!token.startsWith("Bearer ")) { + throw new LoginException(ResponseCode.USER_INPUT_ERROR); + } + token = token.substring(7); } String value = (String) redisTemplate.opsForValue().get("token:" + token); if (StringUtils.isEmpty(value)) { diff --git a/src/main/java/cn/xf/basedemo/mq/RocketMqMsgConsumer.java b/src/main/java/cn/xf/basedemo/mq/RocketMqMsgConsumer.java new file mode 100644 index 0000000..b0f816a --- /dev/null +++ b/src/main/java/cn/xf/basedemo/mq/RocketMqMsgConsumer.java @@ -0,0 +1,25 @@ +package cn.xf.basedemo.mq; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + +/** + * RocketMqMsgComsumer + * + * @author 海言 + * @date 2025/10/13 + * @time 14:37 + * @Description + */ +@Slf4j +@Component +@RocketMQMessageListener(topic = "user-topic",consumerGroup = "consumer-group") +public class RocketMqMsgConsumer implements RocketMQListener { + @Override + public void onMessage(String s) { + log.info("接收到消息---------:{}",s); + } +} diff --git a/src/main/java/cn/xf/basedemo/mq/RocketMqMsgProducer.java b/src/main/java/cn/xf/basedemo/mq/RocketMqMsgProducer.java new file mode 100644 index 0000000..71bdc46 --- /dev/null +++ b/src/main/java/cn/xf/basedemo/mq/RocketMqMsgProducer.java @@ -0,0 +1,39 @@ +package cn.xf.basedemo.mq; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.stereotype.Service; + +/** + * RocketMqMsgProducer + * + * @author 海言 + * @date 2025/10/13 + * @time 14:34 + * @Description + */ +@Slf4j +@Service +public class RocketMqMsgProducer { + + @Resource + private RocketMQTemplate rocketMQTemplate; + + //发送普通消息 + public void sendMsg(String topic, String msg) { + rocketMQTemplate.convertAndSend(topic, msg); + log.info("发送普通消息:{}", msg); + } + + //发送带标签的消息 + public void sendMsg(String topic, String tag, String msg) { + rocketMQTemplate.convertAndSend(topic + ":" + tag, msg); + } + + //发送延迟消息 + public void sendDelayMsg(String topic, String msg, int delayLevel) { + rocketMQTemplate.syncSendDelayTimeMills(topic, msg, delayLevel); + } + +} \ No newline at end of file diff --git a/src/main/java/cn/xf/basedemo/service/UserService.java b/src/main/java/cn/xf/basedemo/service/UserService.java index 7f8dc4f..bf66f8f 100644 --- a/src/main/java/cn/xf/basedemo/service/UserService.java +++ b/src/main/java/cn/xf/basedemo/service/UserService.java @@ -17,4 +17,6 @@ public interface UserService { RetObj syncEs(Long userId); RetObj getEsId(Long userId); + + RetObj sendMQMsg(String msg); } 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 dde91ad..5191de7 100644 --- a/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java +++ b/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java @@ -12,16 +12,19 @@ import cn.xf.basedemo.config.GlobalConfig; import cn.xf.basedemo.mappers.UserMapper; import cn.xf.basedemo.model.domain.User; import cn.xf.basedemo.model.res.LoginInfoRes; +import cn.xf.basedemo.mq.RocketMqMsgProducer; import cn.xf.basedemo.service.UserService; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.RestController; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -49,6 +52,9 @@ public class UserServiceImpl implements UserService { @Autowired private RedisTemplate redisTemplate; + @Resource + private RocketMqMsgProducer rocketMqMsgProducer; + @Override public RetObj login(LoginInfoRes res) { @@ -116,4 +122,10 @@ public class UserServiceImpl implements UserService { } return RetObj.error("es中不存在该用户"); } + + @Override + public RetObj sendMQMsg(String msg) { + rocketMqMsgProducer.sendMsg("user-topic", msg); + return RetObj.success(); + } } From b6eb4d534152225bc980eaf2ad3f3ec4a8f8ef06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Mon, 13 Oct 2025 15:25:03 +0800 Subject: [PATCH 13/20] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-local.yml | 15 --- src/main/resources/application-pre.yml | 144 ++++++++--------------- 2 files changed, 51 insertions(+), 108 deletions(-) diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 01228ee..fefc4ca 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -111,18 +111,3 @@ rabbitmq: subscribeList: - queue: 'app-business' messageListener: commonChangeMessageListener - -#应用可以默认使用的配置文件 -#global: -# testCofnig: "aaa" -# tokenSecret: '12435twefdsfsdt4tsdcqw43tregdsgd' -# tokenExpire: 14400 #10天 -# smsMqTopic: 'topic_msg' -# smsMqTag: 'tag-sms' -# rsaPrivateKey: 'MIIEpQIBAAKCAQEAuAltXJI4kMQkucWCeLGK4Zyqw7VUp1JYS1GkJb0eJKCgxqJBzwjl8XpStA1hCv9BEX6SEsm/d2T6SDo+G6ySpfV0RQeZ7v32kE9+Eh0BK1Q8wU91nCa1CM9yfBhKXsQ3DKq2am5oLryNWXdKLXZPgoJbuIONG2G4oKakwUMX3aASp3Cj3rNXLea8ilXjFZ+OEp0DuZ4CsasO1MTaBS84mJhnzRNbuhHq5qyrVI02jw7Fim8siIBsmDDHgBd4l9hj6KAAr0jf9JOHaOp+KxfH76taqqaXI5lZIPG7lCP65iBuNNEqDSc21abcPhgvgK5K4xj9p5sG+V1FBISCE0dPrQIDAQABAoIBAG6dg/UTEhq5OhXKyDwBAqfOgbk2IVacoONMg+wG+rorLdeWKRXmlEcLLfB45i409Agu2l+ekY2SzPhiwXfixxYnLSZchkJmtS9SCEWc11oSvJ24Q8mCXmeYQIikFPdW2nurlA7uo4IL5K20jIo8xVd9QOHreAHQP6eX4gkjaZHUIOSJ2P6iffEQCHbXehoyCoTMLdK+1HTuZdO4C9r/S9f/Y1kLWfV5ogEi0DHJpUy37npinfqPp0LHbgpK2WBPOkQIhKvi/4OQ71EcYR5gyrA7nR+rQyPHdhFzTTyfTNTgmuNFuAYJODN5yd62RQd8i6chMx63tYDoYhCjI/ixv8UCgYEA9S1JTacLrFQP+2ryHnn6A3JOhbzj1Y552Nc1XixI9aJMxxCJGI0PvmzDb46BSLfoOz4yaqL1lBS2vyX4tc1rKL82JiokZhDlnFNS0yQgR03484BGPJ3D1+tTWQV0cXyq0nYOI+m9vPBciI1Lw07tJ5ZqJbTabtcu2aq8WrKMuFsCgYEAwCk0WB5TTQJQgjuuFXT/GU4cIl8/Pa3IgF7Ccd1WVkFr9uI6vBpToN+0i1zAb83Ss9maD3eH1Na/7GiKwzZOJj8Yas6b1UsbcHZA1Yt+cI2WUZf8L8QVYJrUtIkbKbG+jdg/KjjZt8mAO8IcXivUhfmj8XUIBClYCezEZmSIVpcCgYEAupHWmUfHo0Bo1QqB6l0pupuuUyj1OxprcG38B4itkHYL9OOJX+xgEalUYzzO9tYz23kuBmWxeRj2I6kyhK4noF85RnuFLUIoZ/gkK9Xu1jPogOuZByGK2XETAMgc3wteNj9t7Tg+kVtbHvJet+YEo75bUgw4uGX5GdxJ7r62RMcCgYEAgJfSaJm6oxFGcTCg+cj2oaeM2k+lEZCHWaiQNQSqr0ROjMOuDI0No92wg4aJXQh+1U5sc6dI5dzkSL9ZBPQFbkDRBUDINf9yGFt6Xa1g6s9FZcrwv8JXj/NtHneWDtvcqi2pb4bl48DbqKHou/hW22VJGd94gthsCxBACkmCl3cCgYEAp2/KJrDnLwAr4h6SVCufRRuNkZSRI+XITkE4xyQ/UDeL+iwCbX38Jcqa2lxCAXCLk++1xilSF/sJbBVkiDorBU9CC0tI5tPJFfHQodbePx1C0SQE8e0F+wtaeR9Z5m5KzHNs2Gciqw+2nJPU9uFQjUfGdXuIZF2bBvtXBWH+Prk=' -# rsaPublickey: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuAltXJI4kMQkucWCeLGK4Zyqw7VUp1JYS1GkJb0eJKCgxqJBzwjl8XpStA1hCv9BEX6SEsm/d2T6SDo+G6ySpfV0RQeZ7v32kE9+Eh0BK1Q8wU91nCa1CM9yfBhKXsQ3DKq2am5oLryNWXdKLXZPgoJbuIONG2G4oKakwUMX3aASp3Cj3rNXLea8ilXjFZ+OEp0DuZ4CsasO1MTaBS84mJhnzRNbuhHq5qyrVI02jw7Fim8siIBsmDDHgBd4l9hj6KAAr0jf9JOHaOp+KxfH76taqqaXI5lZIPG7lCP65iBuNNEqDSc21abcPhgvgK5K4xj9p5sG+V1FBISCE0dPrQIDAQAB' -# appDowloadUrl: 'http://llzby.cn/s/E9TTlQrJ' -# pcAccessUrl: 'http://llzby.cn/s/E9TTlQrJ' -# customServiceUrl: 'https://chaten.soboten.com/chat/h5/v2/index.html?sysnum=caf21f78c499463fbb54077f5c4a8efd&channelid=13&source=1&groupid=d16ef9bdcf3b46dc9726bbb00a7ee45b&partnerid=' #智齿客服 + biz_userId -# - diff --git a/src/main/resources/application-pre.yml b/src/main/resources/application-pre.yml index 7ab1468..a172ef3 100644 --- a/src/main/resources/application-pre.yml +++ b/src/main/resources/application-pre.yml @@ -41,98 +41,56 @@ 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 -##redis -#redis: -# datasource: -# token: -# database: 1 -# host: 122.112.153.128 -# port: 6379 -# password: 'redis' -# lettuce: -# pool: -# max-active: 8 -# max-wait: -1ms -# max-idle: 8 -# min-idle: 0 -# timeout: 3000ms +elasticsearch: + host: localhost + port: 9200 + username: elastic + password: bz5oF*MGy8pKL_I=7KxY #window系统本地启动 es8.x 重置密码命令:.\elasticsearch-reset-password -u elastic -#oss: -# name: alioss -# endpoint: ll-oss-pre.lianlianlvyou.com -# accessKey: -# secretKey: -# bucketName: -# args: -# expireTime: 3600 #过期时间 -# contentLengthRange: 2000 #大小限制 -##oss: -## name: alioss -## endpoint: ll-oss-pre.lianlianlvyou.com -## accessKey: -## secretKey: -## bucketName: -## args: -## expireTime: 3600 #过期时间 -## contentLengthRange: 2000 #大小限制 -## redis分布式锁 -#redisson: -# enabled: true -# address: 'redis://192.168.10.113:6379' -# password: '123456' -# database: 5 -# connectionPoolSize: 4 -# connectionMinimumIdleSize: 4 -# -## 阿里云rocketmq -#aliyun: -# rocketmq: -# config: -# AccessKey: 1 -# SecretKey: 1 -# NAMESRV_ADDR: 1 -# GROUP_ID: 1 -# producer: -# enabled: true -# -#rabbitmq: -# configs: -# order: #实例名称 -# host: 192.168.10.111 -# port: 5672 -# virtualHost: ll-dev -# username: zhangziheng -# password: zhangziheng -# producer: -# enabled: true -# exchange: order_status -# routingKey: ORDER_COMPLETE -# confirmCallback: orderMqConfirmCallback -# commonChange: -# host: 192.168.10.111 -# port: 5672 -# virtualHost: ll-dev -# username: zhangziheng -# password: zhangziheng -# producer: -# enabled: false -# consumer: -# enabled: true -# subscribeList: -# - queue: 'app-business' -# messageListener: commonChangeMessageListener -# -##应用可以默认使用的配置文件 -#global: -# testCofnig: "aaa" -# tokenSecret: '12435twefdsfsdt4tsdcqw43tregdsgd' -# tokenExpire: 14400 #10天 -# smsMqTopic: 'topic_msg' -# smsMqTag: 'tag-sms' -# rsaPrivateKey: 'MIIEpQIBAAKCAQEAuAltXJI4kMQkucWCeLGK4Zyqw7VUp1JYS1GkJb0eJKCgxqJBzwjl8XpStA1hCv9BEX6SEsm/d2T6SDo+G6ySpfV0RQeZ7v32kE9+Eh0BK1Q8wU91nCa1CM9yfBhKXsQ3DKq2am5oLryNWXdKLXZPgoJbuIONG2G4oKakwUMX3aASp3Cj3rNXLea8ilXjFZ+OEp0DuZ4CsasO1MTaBS84mJhnzRNbuhHq5qyrVI02jw7Fim8siIBsmDDHgBd4l9hj6KAAr0jf9JOHaOp+KxfH76taqqaXI5lZIPG7lCP65iBuNNEqDSc21abcPhgvgK5K4xj9p5sG+V1FBISCE0dPrQIDAQABAoIBAG6dg/UTEhq5OhXKyDwBAqfOgbk2IVacoONMg+wG+rorLdeWKRXmlEcLLfB45i409Agu2l+ekY2SzPhiwXfixxYnLSZchkJmtS9SCEWc11oSvJ24Q8mCXmeYQIikFPdW2nurlA7uo4IL5K20jIo8xVd9QOHreAHQP6eX4gkjaZHUIOSJ2P6iffEQCHbXehoyCoTMLdK+1HTuZdO4C9r/S9f/Y1kLWfV5ogEi0DHJpUy37npinfqPp0LHbgpK2WBPOkQIhKvi/4OQ71EcYR5gyrA7nR+rQyPHdhFzTTyfTNTgmuNFuAYJODN5yd62RQd8i6chMx63tYDoYhCjI/ixv8UCgYEA9S1JTacLrFQP+2ryHnn6A3JOhbzj1Y552Nc1XixI9aJMxxCJGI0PvmzDb46BSLfoOz4yaqL1lBS2vyX4tc1rKL82JiokZhDlnFNS0yQgR03484BGPJ3D1+tTWQV0cXyq0nYOI+m9vPBciI1Lw07tJ5ZqJbTabtcu2aq8WrKMuFsCgYEAwCk0WB5TTQJQgjuuFXT/GU4cIl8/Pa3IgF7Ccd1WVkFr9uI6vBpToN+0i1zAb83Ss9maD3eH1Na/7GiKwzZOJj8Yas6b1UsbcHZA1Yt+cI2WUZf8L8QVYJrUtIkbKbG+jdg/KjjZt8mAO8IcXivUhfmj8XUIBClYCezEZmSIVpcCgYEAupHWmUfHo0Bo1QqB6l0pupuuUyj1OxprcG38B4itkHYL9OOJX+xgEalUYzzO9tYz23kuBmWxeRj2I6kyhK4noF85RnuFLUIoZ/gkK9Xu1jPogOuZByGK2XETAMgc3wteNj9t7Tg+kVtbHvJet+YEo75bUgw4uGX5GdxJ7r62RMcCgYEAgJfSaJm6oxFGcTCg+cj2oaeM2k+lEZCHWaiQNQSqr0ROjMOuDI0No92wg4aJXQh+1U5sc6dI5dzkSL9ZBPQFbkDRBUDINf9yGFt6Xa1g6s9FZcrwv8JXj/NtHneWDtvcqi2pb4bl48DbqKHou/hW22VJGd94gthsCxBACkmCl3cCgYEAp2/KJrDnLwAr4h6SVCufRRuNkZSRI+XITkE4xyQ/UDeL+iwCbX38Jcqa2lxCAXCLk++1xilSF/sJbBVkiDorBU9CC0tI5tPJFfHQodbePx1C0SQE8e0F+wtaeR9Z5m5KzHNs2Gciqw+2nJPU9uFQjUfGdXuIZF2bBvtXBWH+Prk=' -# rsaPublickey: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuAltXJI4kMQkucWCeLGK4Zyqw7VUp1JYS1GkJb0eJKCgxqJBzwjl8XpStA1hCv9BEX6SEsm/d2T6SDo+G6ySpfV0RQeZ7v32kE9+Eh0BK1Q8wU91nCa1CM9yfBhKXsQ3DKq2am5oLryNWXdKLXZPgoJbuIONG2G4oKakwUMX3aASp3Cj3rNXLea8ilXjFZ+OEp0DuZ4CsasO1MTaBS84mJhnzRNbuhHq5qyrVI02jw7Fim8siIBsmDDHgBd4l9hj6KAAr0jf9JOHaOp+KxfH76taqqaXI5lZIPG7lCP65iBuNNEqDSc21abcPhgvgK5K4xj9p5sG+V1FBISCE0dPrQIDAQAB' -# appDowloadUrl: 'http://llzby.cn/s/E9TTlQrJ' -# pcAccessUrl: 'http://llzby.cn/s/E9TTlQrJ' -# customServiceUrl: 'https://chaten.soboten.com/chat/h5/v2/index.html?sysnum=caf21f78c499463fbb54077f5c4a8efd&channelid=13&source=1&groupid=d16ef9bdcf3b46dc9726bbb00a7ee45b&partnerid=' #智齿客服 + biz_userId -# +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: false + 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 cc105a6434881ec4245133efe102737f5e3c90e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Fri, 24 Oct 2025 10:58:05 +0800 Subject: [PATCH 14/20] =?UTF-8?q?pom.xml=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ebcfba7..87e1f48 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,7 @@ 2023.0.1 8.16.0 4.0.1 + 2.3.4 @@ -132,7 +133,7 @@ org.apache.rocketmq rocketmq-spring-boot-starter - 2.3.4 + ${rocketmq.version} From ad2e60b54a018d94392a0e2d14f370268f75a64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 6 Nov 2025 18:09:43 +0800 Subject: [PATCH 15/20] =?UTF-8?q?=E7=A7=BB=E9=99=A4rocketmq=E9=9B=86?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 ---- .../controller/business/UserController.java | 7 ---- .../xf/basedemo/mq/RocketMqMsgConsumer.java | 25 ------------ .../xf/basedemo/mq/RocketMqMsgProducer.java | 39 ------------------- .../cn/xf/basedemo/service/UserService.java | 1 - .../service/impl/UserServiceImpl.java | 9 ----- 6 files changed, 88 deletions(-) delete mode 100644 src/main/java/cn/xf/basedemo/mq/RocketMqMsgConsumer.java delete mode 100644 src/main/java/cn/xf/basedemo/mq/RocketMqMsgProducer.java diff --git a/pom.xml b/pom.xml index 87e1f48..4a86b2e 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,6 @@ 2023.0.1 8.16.0 4.0.1 - 2.3.4 @@ -129,12 +128,6 @@ elasticsearch-java ${elasticsearch.version} - - - org.apache.rocketmq - rocketmq-spring-boot-starter - ${rocketmq.version} - diff --git a/src/main/java/cn/xf/basedemo/controller/business/UserController.java b/src/main/java/cn/xf/basedemo/controller/business/UserController.java index 22598ad..2af5a09 100644 --- a/src/main/java/cn/xf/basedemo/controller/business/UserController.java +++ b/src/main/java/cn/xf/basedemo/controller/business/UserController.java @@ -51,11 +51,4 @@ public class UserController { return userService.getEsId(userId); } - - //发送队列消息 - @Operation(summary = "发送队列消息", description = "发送队列消息") - @GetMapping("/sendMsg") - public RetObj sendMsg(String msg) { - return userService.sendMQMsg(msg); - } } diff --git a/src/main/java/cn/xf/basedemo/mq/RocketMqMsgConsumer.java b/src/main/java/cn/xf/basedemo/mq/RocketMqMsgConsumer.java deleted file mode 100644 index b0f816a..0000000 --- a/src/main/java/cn/xf/basedemo/mq/RocketMqMsgConsumer.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.xf.basedemo.mq; - - -import lombok.extern.slf4j.Slf4j; -import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; -import org.apache.rocketmq.spring.core.RocketMQListener; -import org.springframework.stereotype.Component; - -/** - * RocketMqMsgComsumer - * - * @author 海言 - * @date 2025/10/13 - * @time 14:37 - * @Description - */ -@Slf4j -@Component -@RocketMQMessageListener(topic = "user-topic",consumerGroup = "consumer-group") -public class RocketMqMsgConsumer implements RocketMQListener { - @Override - public void onMessage(String s) { - log.info("接收到消息---------:{}",s); - } -} diff --git a/src/main/java/cn/xf/basedemo/mq/RocketMqMsgProducer.java b/src/main/java/cn/xf/basedemo/mq/RocketMqMsgProducer.java deleted file mode 100644 index 71bdc46..0000000 --- a/src/main/java/cn/xf/basedemo/mq/RocketMqMsgProducer.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.xf.basedemo.mq; - -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.apache.rocketmq.spring.core.RocketMQTemplate; -import org.springframework.stereotype.Service; - -/** - * RocketMqMsgProducer - * - * @author 海言 - * @date 2025/10/13 - * @time 14:34 - * @Description - */ -@Slf4j -@Service -public class RocketMqMsgProducer { - - @Resource - private RocketMQTemplate rocketMQTemplate; - - //发送普通消息 - public void sendMsg(String topic, String msg) { - rocketMQTemplate.convertAndSend(topic, msg); - log.info("发送普通消息:{}", msg); - } - - //发送带标签的消息 - public void sendMsg(String topic, String tag, String msg) { - rocketMQTemplate.convertAndSend(topic + ":" + tag, msg); - } - - //发送延迟消息 - public void sendDelayMsg(String topic, String msg, int delayLevel) { - rocketMQTemplate.syncSendDelayTimeMills(topic, msg, delayLevel); - } - -} \ No newline at end of file diff --git a/src/main/java/cn/xf/basedemo/service/UserService.java b/src/main/java/cn/xf/basedemo/service/UserService.java index bf66f8f..4348ed0 100644 --- a/src/main/java/cn/xf/basedemo/service/UserService.java +++ b/src/main/java/cn/xf/basedemo/service/UserService.java @@ -18,5 +18,4 @@ public interface UserService { RetObj getEsId(Long userId); - RetObj sendMQMsg(String msg); } 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 5191de7..3bd98c7 100644 --- a/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java +++ b/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java @@ -52,9 +52,6 @@ public class UserServiceImpl implements UserService { @Autowired private RedisTemplate redisTemplate; - @Resource - private RocketMqMsgProducer rocketMqMsgProducer; - @Override public RetObj login(LoginInfoRes res) { @@ -122,10 +119,4 @@ public class UserServiceImpl implements UserService { } return RetObj.error("es中不存在该用户"); } - - @Override - public RetObj sendMQMsg(String msg) { - rocketMqMsgProducer.sendMsg("user-topic", msg); - return RetObj.success(); - } } From 70b6d0babc233cf77954180c95792538e94e1523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Thu, 6 Nov 2025 18:10:09 +0800 Subject: [PATCH 16/20] =?UTF-8?q?=E7=A7=BB=E9=99=A4rocketmq=E9=9B=86?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java | 3 --- 1 file changed, 3 deletions(-) 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 3bd98c7..dde91ad 100644 --- a/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java +++ b/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java @@ -12,19 +12,16 @@ import cn.xf.basedemo.config.GlobalConfig; import cn.xf.basedemo.mappers.UserMapper; import cn.xf.basedemo.model.domain.User; import cn.xf.basedemo.model.res.LoginInfoRes; -import cn.xf.basedemo.mq.RocketMqMsgProducer; import cn.xf.basedemo.service.UserService; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.RestController; import java.util.Objects; import java.util.concurrent.TimeUnit; From 7f1503485f188371c3e3eecec9e494724514b7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Fri, 7 Nov 2025 11:28:31 +0800 Subject: [PATCH 17/20] =?UTF-8?q?=E7=A7=BB=E9=99=A4es8.x=E9=9B=86=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xf/basedemo/common/model/EsBaseModel.java | 42 -- .../basedemo/common/model/EsSearchModel.java | 81 --- .../cn/xf/basedemo/common/utils/EsUtil.java | 499 ------------------ .../java/cn/xf/basedemo/config/EsConfig.java | 79 --- .../controller/business/UserController.java | 12 - .../cn/xf/basedemo/service/UserService.java | 4 - .../service/impl/UserServiceImpl.java | 25 - 7 files changed, 742 deletions(-) delete mode 100644 src/main/java/cn/xf/basedemo/common/model/EsBaseModel.java delete mode 100644 src/main/java/cn/xf/basedemo/common/model/EsSearchModel.java delete mode 100644 src/main/java/cn/xf/basedemo/common/utils/EsUtil.java delete mode 100644 src/main/java/cn/xf/basedemo/config/EsConfig.java diff --git a/src/main/java/cn/xf/basedemo/common/model/EsBaseModel.java b/src/main/java/cn/xf/basedemo/common/model/EsBaseModel.java deleted file mode 100644 index dd32333..0000000 --- a/src/main/java/cn/xf/basedemo/common/model/EsBaseModel.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.xf.basedemo.common.model; - -import lombok.Data; - -/** - * packageName cn.xf.basedemo.common.model - * @author remaindertime - * @className EsModel - * @date 2024/12/10 - * @description es基础模型 - */ -@Data -public class EsBaseModel { - - public EsBaseModel(String indexName, String documentId, T documentModel, Class clazz) { - this.indexName = indexName; - this.documentId = documentId; - this.documentModel = documentModel; - this.clazz = clazz; - } - - /** - * 索引名称 - */ - private String indexName; - - /** - * 文档id - */ - private String documentId; - - /** - * 映射对象 - */ - private T documentModel; - - /** - * 映射对象类对象 - */ - private Class clazz; - -} diff --git a/src/main/java/cn/xf/basedemo/common/model/EsSearchModel.java b/src/main/java/cn/xf/basedemo/common/model/EsSearchModel.java deleted file mode 100644 index 13bc030..0000000 --- a/src/main/java/cn/xf/basedemo/common/model/EsSearchModel.java +++ /dev/null @@ -1,81 +0,0 @@ -package cn.xf.basedemo.common.model; - -import lombok.Data; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * packageName cn.xf.basedemo.common.model - * @author remaindertime - * @className EsSearchModel - * @date 2024/12/11 - * @description es 搜索模型 - */ -@Data -public class EsSearchModel { - - public EsSearchModel() { - // 使用 LinkedHashMap 保持插入顺序 - this.sort = new LinkedHashMap<>(); - } - - /** - * 索引名称 - */ - private String indexName; - - /** - * 文档类型 - */ - private Class clazz; - - /** - * 页数 - */ - private Integer pageNum; - - /** - * 每页数量 - */ - private Integer pageSize; - /** - * 精准查询字段 - */ - private Map termQuery; - - /** - * 模糊查询字段(一般是text类型) - */ - private Map matchQuery; - - /** - * 排序字段规则 ({"age":"desc"}) - */ - private Map sort; - - /** - * 分组去重字段(支持的字段类型:keyword、numeric、date 和 boolean ) - */ - private String repeatField;; - - /** - * 分组嵌套查询别名 - */ - private String innerAlias; - - /** - * 分组嵌套查询数量 - */ - private Integer innerSize; - - /** - * 指定需要返回的字段 - */ - private List includes; - /** - * 指定需要排除的字段 - */ - private List excludes; - -} \ No newline at end of file diff --git a/src/main/java/cn/xf/basedemo/common/utils/EsUtil.java b/src/main/java/cn/xf/basedemo/common/utils/EsUtil.java deleted file mode 100644 index 3b371e1..0000000 --- a/src/main/java/cn/xf/basedemo/common/utils/EsUtil.java +++ /dev/null @@ -1,499 +0,0 @@ -package cn.xf.basedemo.common.utils; - -import cn.xf.basedemo.common.model.EsBaseModel; -import cn.xf.basedemo.common.model.EsSearchModel; -import co.elastic.clients.elasticsearch.ElasticsearchClient; -import co.elastic.clients.elasticsearch._types.*; -import co.elastic.clients.elasticsearch._types.query_dsl.*; -import co.elastic.clients.elasticsearch.core.*; -import co.elastic.clients.elasticsearch.core.search.*; -import co.elastic.clients.elasticsearch.indices.CreateIndexResponse; -import co.elastic.clients.elasticsearch.indices.ExistsRequest; -import co.elastic.clients.json.JsonData; -import co.elastic.clients.transport.endpoints.BooleanResponse; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; -import java.util.*; -import java.util.stream.Collectors; - -/** - * packageName cn.xf.basedemo.common.utils - * @author remaindertime - * @className EsUtil - * @date 2024/12/10 - * @description elasticsearch工具类 - */ -@Slf4j -@Component -public class EsUtil { - - public static ElasticsearchClient esClient; - - { - esClient = (ElasticsearchClient) ApplicationContextUtils.getBean("elasticsearchClient"); - } - - /** - * 判断索引是否存在 - * @param indexName - * @return - */ - public static boolean existIndex(String indexName) { - try { - // 创建 ExistsRequest 请求 - ExistsRequest request = new ExistsRequest.Builder() - .index(indexName) - .build(); - // 发送请求并获取响应 - BooleanResponse response = esClient.indices().exists(request); - // 返回索引是否存在 - return response.value(); - } catch (Exception e) { - // 处理异常 - e.printStackTrace(); - return false; - } - } - - /** - * 删除索引 - * - * @param indexName - */ - @SneakyThrows - public static void delIndex(String indexName) { - if (existIndex(indexName)) { - return; - } - esClient.indices().delete(d -> d.index(indexName)); - } - - /** - * 创建索引 - * - * @param indexName - * @return - */ - public static void createIndex(String indexName) { - if (existIndex(indexName)) { - throw new RuntimeException("索引已经存在"); - } - try { - CreateIndexResponse createIndexResponse = esClient.indices().create(c -> c.index(indexName)); - // 处理响应 - if (createIndexResponse.acknowledged()) { - log.info(" indexed create successfully."); - } else { - log.info("Failed to create index."); - } - } catch (Exception e) { - // 捕获异常并打印详细错误信息 - e.printStackTrace(); - throw new RuntimeException("创建索引失败,索引名:" + indexName + ",错误信息:" + e.getMessage(), e); - } - } - - /** - * 新增文档 - * @param esBaseModel - * @return - */ - public static boolean addDocument(EsBaseModel esBaseModel) { - try { - ObjectMapper objectMapper = new ObjectMapper(); - String jsonString = objectMapper.writeValueAsString(esBaseModel.getDocumentModel()); - log.info("es新增文档,文档内容:{}", jsonString); - // 创建 IndexRequest 实例 - IndexRequest request = new IndexRequest.Builder() - .index(esBaseModel.getIndexName()) - .id(esBaseModel.getDocumentId()) //指定文档id,不指定会自动生成 - .document(esBaseModel.getDocumentModel()) - .opType(OpType.Create) // 只会在文档 ID 不存在时创建文档 - .build(); - - IndexResponse response = esClient.index(request); - if ("created".equals(response.result())) { - log.info("Document created: " + response.id()); - return true; - } else { - log.info("Document already exists or failed to create."); - return false; - } - } catch (Exception e) { - log.error("es新增文档失败", e); - e.printStackTrace(); - } - return false; - } - - /** - * 更新文档 - * @param esBaseModel - * @return - */ - public boolean updateDocument(EsBaseModel esBaseModel) { - try { - UpdateRequest updateRequest = new UpdateRequest.Builder<>() - .index(esBaseModel.getIndexName()) - .id(esBaseModel.getDocumentId()) - .doc(esBaseModel.getDocumentModel()).build(); - UpdateResponse updateResponse = esClient.update(updateRequest, esBaseModel.getClazz()); - log.info("Document updated: " + updateResponse.id()); - return true; - } catch (Exception e) { - e.printStackTrace(); - } - return false; - } - - /** - * 更新文档指定字段(script 脚本) - * @param esBaseModel - * @param script 脚本内容 - * @param params 传递参数内容 - */ - public void updateDocumentWithScript(EsBaseModel esBaseModel, String script, Map params) { - try { - UpdateRequest updateRequest = new UpdateRequest.Builder<>() - .index(esBaseModel.getIndexName()) - .id(esBaseModel.getDocumentId()) - .script(s -> - s.source(script)// 脚本内容:.source("ctx._source.age += params.increment") - .params(params)) // 传递参数内容:.params("increment",sonData.of(5)) - .build(); - UpdateResponse updateResponse = esClient.update(updateRequest, esBaseModel.getClazz()); - log.info("Document updated: " + updateResponse.id()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * 根据id查询文档 - * @param esBaseModel - * @return - */ - public static T getDocumentById(EsBaseModel esBaseModel) { - try { - GetRequest getRequest = new GetRequest.Builder() - .index(esBaseModel.getIndexName()) - .id(esBaseModel.getDocumentId()) - .build(); - GetResponse getResponse = esClient.get(getRequest, esBaseModel.getClazz()); - if (getResponse.found()) { - return getResponse.source(); - } - } catch (Exception e) { - log.error("es列表查询失败", e); - } - return null; - } - - /** - * 查询文档列表 - * @param searchModel - * @return - */ - public static List getDocumentList(EsSearchModel searchModel) { - List eslist = new ArrayList<>(); - try { - SearchResponse search = esClient.search(buildSearchRequest(searchModel), searchModel.getClazz()); - if (Objects.isNull(search)) { - return eslist; - } - HitsMetadata hits = search.hits(); - if (Objects.isNull(hits)) { - return eslist; - } - List> sourceHitList = hits.hits(); - if (CollectionUtils.isEmpty(sourceHitList)) { - return eslist; - } - sourceHitList.forEach(item -> { - // 处理每个命中 - eslist.add(item.source()); - }); - return eslist; - } catch (Exception e) { - log.error("es列表查询失败", e); - } - return eslist; - } - - /** - * 查询文档数量 - * @param searchModel - * @return - */ - public static long getDocumentCount(EsSearchModel searchModel) { - try { - CountRequest.Builder countRequest = new CountRequest.Builder(); - countRequest.index(searchModel.getIndexName()); - countRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery())); - CountResponse count = esClient.count(countRequest.build()); - if (Objects.isNull(count)) { - log.info("es列表数量查询异常{}", searchModel); - return 0; - } - return count.count(); - } catch (Exception e) { - log.error("es列表数量查询失败", e); - } - return 0; - } - - /** - * 根据id删除文档 - * @param esBaseModel - * @return - */ - public static Boolean deleteDocumentById(EsBaseModel esBaseModel) { - try { - DeleteRequest deleteRequest = new DeleteRequest.Builder() - .index(esBaseModel.getDocumentId()) - .id(esBaseModel.getDocumentId()) - .build(); - DeleteResponse deleteResponse = esClient.delete(deleteRequest); - if ("deleted".equals(deleteResponse.result())) { - log.info("Document deleted: " + deleteResponse.id()); - return true; - } else { - log.info("Document delete failed: " + deleteResponse.id()); - return false; - } - } catch (Exception e) { - log.error("es列表删除失败", e); - } - return false; - } - - /** - * 根据条件删除文档 - * @param searchModel - * @return 删除数量 - */ - public static long deleteDocumentByQuery(EsSearchModel searchModel) { - try { - DeleteByQueryRequest.Builder deleteRequest = new DeleteByQueryRequest.Builder(); - deleteRequest.index(searchModel.getIndexName()); - deleteRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery())); - deleteRequest.refresh(true); //设置删除操作后是否立即刷新索引,使删除结果立即可见 - deleteRequest.timeout(new Time.Builder().time("2s").build()); //设置删除操作的超时时间 - deleteRequest.conflicts(Conflicts.Proceed); //Conflicts.Proceed:在版本冲突时继续删除操作;Conflicts.Abort:在版本冲突时中止删除操作 - DeleteByQueryResponse dResponse = esClient.deleteByQuery(deleteRequest.build()); - if (Objects.nonNull(dResponse)) { - log.info("es条件删除成功,删除数量:{}", dResponse.deleted()); - return dResponse.deleted(); - } - } catch (Exception e) { - log.error("es条件删除数据失败", e); - } - return 0; - } - - /** - * 构建搜索请求对象 - * @param searchModel - * @return - */ - private static SearchRequest buildSearchRequest(EsSearchModel searchModel) { - //定义查询对象 - SearchRequest.Builder searchRequest = new SearchRequest.Builder(); - //设置索引名称 - searchRequest.index(searchModel.getIndexName()); - //分组去重 - if (StringUtils.isNotBlank(searchModel.getRepeatField())) { - searchRequest.collapse(buildCollapse(searchModel)); - } - //设置查询条件 - searchRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery())); - //设置排序规则 - if (searchModel.getSort() != null) { - searchRequest.sort(buildSort(searchModel.getSort())); - } - //设置分页参数 - if (searchModel.getPageSize() != null && searchModel.getPageSize() != null) { - searchRequest.from(searchModel.getPageSize() * (searchModel.getPageNum() - 1)); - searchRequest.size(searchModel.getPageSize()); - } - //设置查询字段/排查字段 - SourceConfig sourceConfig = buildSourceConfig(searchModel.getIncludes(), searchModel.getExcludes()); - if (Objects.nonNull(sourceConfig)) { - searchRequest.source(sourceConfig); - } - return searchRequest.build(); - } - - /** - * 构建查询条件 - * @param termQuery - * @param matchQuery - * @return - */ - private static Query createBoolQuery(Map termQuery, Map matchQuery) { - BoolQuery.Builder cQuery = new BoolQuery.Builder(); - // TermQuery 精准匹配 - if (termQuery != null) { - for (Map.Entry entry : termQuery.entrySet()) { - if (Objects.isNull(entry.getValue())) { - continue; - } - String key = entry.getKey(); - Object value = entry.getValue(); - if (value.getClass().isArray()) { //数组查询,使用 TermsQuery - Object[] values = (Object[]) entry.getValue(); - List objs = Arrays.stream(values) - .map(v -> FieldValue.of(v)) // 将每个对象转换为 FieldValue - .collect(Collectors.toList()); - cQuery.must(new TermsQuery.Builder() - .field(key) - .terms(t -> t.value(objs)) - .build() - ._toQuery()); - } else if (value.toString().contains(" ")) { // 短语查询,使用 MatchPhraseQuery (要严格按照单词顺序字符串中有空格,短信需匹配) - cQuery.must(new MatchPhraseQuery.Builder() - .field(key) - .query(value.toString()) - .build() - ._toQuery()); - } else { // 其他情况,使用 TermQuery 精准匹配 - cQuery.must(new TermQuery.Builder() - .field(key) - .value(value.toString()) - .build() - ._toQuery()); - } - } - } - // MatchQuery 模糊匹配全文检索分词查询 - if (matchQuery != null) { - for (Map.Entry entry : matchQuery.entrySet()) { - if (Objects.isNull(entry.getValue())) { - continue; - } - cQuery.must(new MatchQuery.Builder() - .field(entry.getKey()) - .query(entry.getValue().toString()) - .build() - ._toQuery()); - } - } - return cQuery.build()._toQuery(); - } - - /** - * 构建时间区间查询 - * @param startTime 开始时间 - * @param endTime 结束时间 - * @param fieldName 时间字段 - * @return - */ - public static Query createTimeQuery(String startTime, String endTime, String fieldName) { - DateRangeQuery dataQuery = new DateRangeQuery.Builder() - .field(fieldName) - .build(); - // 时间区间查询 - dataQuery.of(o -> o.gte(startTime)); - dataQuery.of(o -> o.lte(endTime)); - return dataQuery._toRangeQuery()._toQuery(); - } - - - /** - * 设置查询字段/排查字段 - * @param includes 需要字段 - * @param excludes 排除字段 - * @return - */ - private static SourceConfig buildSourceConfig(List includes, List excludes) { - boolean isIncludes = CollectionUtils.isEmpty(includes); - boolean isExcludes = CollectionUtils.isEmpty(excludes); - //设置查询字段/排查字段 - if (isIncludes || isExcludes) { - SourceFilter.Builder sourceFilter = new SourceFilter.Builder(); - if (isIncludes) - sourceFilter.includes(includes); - if (isExcludes) - sourceFilter.excludes(excludes); - return new SourceConfig.Builder().filter(sourceFilter.build()).build(); - } - return null; - } - - - /** - * 构建分组去重 - * @param searchModel - * @return - */ - private static FieldCollapse buildCollapse(EsSearchModel searchModel) { - FieldCollapse.Builder fieldCollapse = new FieldCollapse.Builder(); - //设置分组字段 - fieldCollapse.field(searchModel.getRepeatField()); - //设置嵌套配置 - if (StringUtils.isNotBlank(searchModel.getInnerAlias())) { - InnerHits.Builder innerHits = new InnerHits.Builder(); - //设置别名 - innerHits.name(searchModel.getInnerAlias()); - //设置查询数量 - if (searchModel.getInnerSize() != null) { - innerHits.size(searchModel.getInnerSize()); - } - fieldCollapse.innerHits(InnerHits.of(i -> i.name(searchModel.getInnerAlias()).size(10))); - } - return fieldCollapse.build(); - } - - /** - * 构建排序规则 - * @param sortMap - * @return - */ - private static List buildSort(Map sortMap) { - if (sortMap == null) { - return null; - } - List sortList = new ArrayList<>(); - for (Map.Entry sort : sortMap.entrySet()) { - sortList.add(new SortOptions.Builder().field(f -> f.field(sort.getKey()).order(SortOrder.valueOf(sort.getValue()))).build()); - } - return sortList; - } - - /** - * 案例:组合多条件查询(关于 must、mustNot、should 条件的使用) - */ - public Query combinationQueryTest() { - //query.must():and 文档必须满足该条件,如果不满足,文档将不匹配。 and - //query.should():or 文档可以不满足该条件,但满足该条件时会得分更高;即使不满足,文档也会出现在查询结果中,只是查询结果靠后。 - - //场景1:文档必须符合所有 must 条件和 mustNot 条件,同时至少满足一个 should 条件。如果 should 条件都不满足,文档将被排除不查询出来。 - BoolQuery.Builder query = new BoolQuery.Builder(); - //数字范围查询 - NumberRangeQuery.Builder numberQuery = new NumberRangeQuery.Builder(); - numberQuery.field("age").lte(30.0).build(); - // 构建查询条件 - query.must(o -> o.term(t -> t.field("status").value("active"))) // 必须满足的条件 - .mustNot(o -> o.term(t -> t.field("country").value("China"))) // 不能满足的条件 - .filter(f -> f.bool(bo -> bo - .should(so -> so.range(r -> r.number(numberQuery.build()))) // 至少满足一个 should 条件 - .should(so -> so.term(t -> t.field("gender").value("male"))) // 至少满足一个 should 条件 - .minimumShouldMatch("1") // 至少满足一个 should 条件 也可设置百分比 “50%” - )); - //场景2:文档必须符合所有 must 条件和 mustNot 条件,同时至少满足一个 should 条件。如果 should 条件都不满足,不用做额外的过滤(按照should原生特性处理)。 - query.must(o -> o.bool(bo -> bo - .should(so -> so.range(r -> r.number(numberQuery.build()))) // 至少满足一个 should 条件 - .should(so -> so.term(t -> t.field("gender").value("male"))) // 至少满足一个 should 条件 - .minimumShouldMatch("1") // 至少满足一个 should 条件 - )) - .must(o -> o.term(t -> t.field("status").value("active"))) // 必须满足的条件 - .mustNot(o -> o.term(t -> t.field("country").value("China"))); // 不能满足的条件 - - return query.build()._toQuery(); - } - -} diff --git a/src/main/java/cn/xf/basedemo/config/EsConfig.java b/src/main/java/cn/xf/basedemo/config/EsConfig.java deleted file mode 100644 index 70e2c1c..0000000 --- a/src/main/java/cn/xf/basedemo/config/EsConfig.java +++ /dev/null @@ -1,79 +0,0 @@ -package cn.xf.basedemo.config; - -import co.elastic.clients.elasticsearch.ElasticsearchClient; -import co.elastic.clients.json.jackson.JacksonJsonpMapper; -import co.elastic.clients.transport.ElasticsearchTransport; -import co.elastic.clients.transport.rest_client.RestClientTransport; -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestClientBuilder; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Component; - -/** - * packageName cn.xf.basedemo.config - * @author remaindertime - * @className ElasticsearchConfig - * @date 2024/12/9 - * @description es工具类 - */ -@Component -public class EsConfig { - - @Value("${elasticsearch.host}") - private String elasticsearchHost; - @Value("${elasticsearch.port}") - private int elasticsearchPort; - @Value("${elasticsearch.username}") - private String username; - @Value("${elasticsearch.password}") - private String password; - - /** - -最大连接数 (maxConnTotal):设置总的最大连接数,取决于业务的并发量。500-2000 之间较为合理。 - -每个节点的最大连接数 (maxConnPerRoute):控制每个节点的最大连接数,建议 50-100 之间。 - -IO 线程数 (setIoThreadCount):根据 CPU 核心数设置,通常为 2-4 倍 CPU 核心数。 - -连接超时、套接字超时、获取连接超时:一般设置为 10-30 秒,复杂查询或大数据量操作可适当增加到 20-60 秒。 - -失败监听器 (setFailureListener):自定义重试和故障处理逻辑,确保高可用性。 - */ - @Bean - public ElasticsearchClient elasticsearchClient() { - - // 创建凭证提供者 - CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials( - AuthScope.ANY, - new UsernamePasswordCredentials(username, password) - ); - - // 自定义 RestClientBuilder 配置 - RestClientBuilder restClientBuilder = RestClient.builder( - new HttpHost(elasticsearchHost, elasticsearchPort, "http") - ).setHttpClientConfigCallback(httpClientBuilder -> - httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider) // 配置认证信息 - ); - // 配置连接超时、套接字超时、获取连接超时 - restClientBuilder.setRequestConfigCallback(builder -> - builder.setConnectTimeout(20000) - .setSocketTimeout(20000) - .setConnectionRequestTimeout(20000) - ); - // 创建 RestClientTransport 和 ElasticsearchClient - RestClient restClient = restClientBuilder.build(); - ElasticsearchTransport transport = new RestClientTransport( - restClient, - new JacksonJsonpMapper() // 使用 Jackson 进行 JSON 处理 - ); - - return new ElasticsearchClient(transport); - } - - /** - window系统本地启动 es8.x 重置密码命令:.\elasticsearch-reset-password -u elastic - */ -} diff --git a/src/main/java/cn/xf/basedemo/controller/business/UserController.java b/src/main/java/cn/xf/basedemo/controller/business/UserController.java index 2af5a09..f18ef7d 100644 --- a/src/main/java/cn/xf/basedemo/controller/business/UserController.java +++ b/src/main/java/cn/xf/basedemo/controller/business/UserController.java @@ -39,16 +39,4 @@ public class UserController { return RetObj.success(loginUser); } - @Operation(summary = "es同步用户信息", description = "用户信息") - @GetMapping("/syncEs") - public RetObj syncEs(Long userId) { - return userService.syncEs(userId); - } - - @Operation(summary = "es查询用户信息", description = "用户信息") - @GetMapping("/getEsId") - public RetObj getEsId(Long userId) { - return userService.getEsId(userId); - } - } diff --git a/src/main/java/cn/xf/basedemo/service/UserService.java b/src/main/java/cn/xf/basedemo/service/UserService.java index 4348ed0..d303267 100644 --- a/src/main/java/cn/xf/basedemo/service/UserService.java +++ b/src/main/java/cn/xf/basedemo/service/UserService.java @@ -14,8 +14,4 @@ public interface UserService { RetObj login(LoginInfoRes res); - RetObj syncEs(Long userId); - - RetObj getEsId(Long userId); - } 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 dde91ad..8d76202 100644 --- a/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java +++ b/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java @@ -1,13 +1,10 @@ package cn.xf.basedemo.service.impl; -import cn.xf.basedemo.common.model.EsBaseModel; import cn.xf.basedemo.common.model.LoginInfo; import cn.xf.basedemo.common.model.LoginUser; import cn.xf.basedemo.common.model.RetObj; -import cn.xf.basedemo.common.utils.EsUtil; import cn.xf.basedemo.common.utils.JwtTokenUtils; import cn.xf.basedemo.common.utils.RSAUtils; -import cn.xf.basedemo.common.utils.StringUtil; import cn.xf.basedemo.config.GlobalConfig; import cn.xf.basedemo.mappers.UserMapper; import cn.xf.basedemo.model.domain.User; @@ -94,26 +91,4 @@ public class UserServiceImpl implements UserService { return RetObj.success(loginUser); } - @Override - public RetObj syncEs(Long userId) { - User user = userMapper.selectById(userId); - if (Objects.isNull(user)) { - return RetObj.error("用户不存在"); - } - String index = StringUtil.camelToKebabCase(user.getClass().getSimpleName()); - if (!EsUtil.existIndex(index)) { - EsUtil.createIndex(index); - } - EsUtil.addDocument(new EsBaseModel(index, String.valueOf(user.getId()), user, user.getClass())); - return RetObj.success(); - } - - @Override - public RetObj getEsId(Long userId) { - Object user = EsUtil.getDocumentById(new EsBaseModel("user", String.valueOf(userId), null, User.class)); - if (Objects.nonNull(user)) { - return RetObj.success(user); - } - return RetObj.error("es中不存在该用户"); - } } From c8f9746d6ddbf4d86d3d55a1aaea59efd7ce0297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Fri, 7 Nov 2025 11:33:10 +0800 Subject: [PATCH 18/20] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pom.xml b/pom.xml index 4a86b2e..1b95392 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,6 @@ 5.3 2023.0.1.0 2023.0.1 - 8.16.0 4.0.1 @@ -122,12 +121,6 @@ ${sverlet.version} provided - - - co.elastic.clients - elasticsearch-java - ${elasticsearch.version} - From 27b45cca66b87f07a9e316b188f1b57c46282097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Wed, 26 Nov 2025 16:54:53 +0800 Subject: [PATCH 19/20] =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + src/main/resources/application-local.yml | 146 ++++++++++------------- 2 files changed, 65 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 73286b7..c8f1cec 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ - master 快速上手开发spring boot 用户端单体应用 - feature/admin-auth-spring-security 基于master分支集成spring官方鉴权框架spring security框架,可用于后台管理系统后端项目,实现RBAC模型(角色 → 用户 → 菜单 → 权限)基于角色的访问控制 - feature/admin-auth-sa-token 基于master分支集成国产权限框架sa-token,可用于后台管理系统后端项目,实现RBAC模型(角色 → 用户 → 菜单 → 权限)基于角色的访问控制 +- component/rocketmq-and-es 基于master分支集成消息队列原生RocketMQ5.x与原生Elasticsearch 8.x,提供消息队列与搜索引擎服务,实现消息持久化与全文检索 +- feature/master-payment 基于master分支集成支付宝沙盒功能(H5支付、APP支付) ### 集成技术与功能亮点 diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index fefc4ca..1964d39 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -1,113 +1,93 @@ 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: true #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源. + strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源. hikari: - minimum-idle: 4 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://9.9.9.9:3307/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai + 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://9.9.9.9:3307/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai + 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 #Redis服务器连接的端口 - host: 9.9.9.9 # Redis服务器的地址 - password: # Redis服务器连接密码(默认为空) - timeout: 5000 # 连接超时时间(毫秒) + 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 #空闲对象逐出器线程的运行间隔时间.空闲连接线程释放周期时间. + maxActive: 5000 + maxIdle: 30 + minIdle: 5 + max-wait: 2000 + time-between-eviction-runs: 60s cluster: refresh: - adaptive: true #拓扑动态感应即客户端能够根据 redis cluster 集群的变化,动态改变客户端的节点情况,完成故障转移。 - period: 60s #刷新redis集群状态周期时间 + 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 -redis: - datasource: - token: - database: 1 - host: 122.112.153.128 - port: 6379 - password: 'redis' - lettuce: - pool: - max-active: 8 - max-wait: -1ms - max-idle: 8 - min-idle: 0 - timeout: 3000ms +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 -oss: - name: alioss - endpoint: ll-oss-pre.lianlianlvyou.com - accessKey: - secretKey: - bucketName: - args: - expireTime: 3600 #过期时间 - contentLengthRange: 2000 #大小限制 -# redis分布式锁 -redisson: - enabled: true - address: 'redis://192.168.10.113:6379' - password: '123456' - database: 5 - connectionPoolSize: 4 - connectionMinimumIdleSize: 4 +mybatis-plus: + configuration: + map-underscore-to-camel-case: false + 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 -# 阿里云rocketmq -aliyun: - rocketmq: - config: - AccessKey: 1 - SecretKey: 1 - NAMESRV_ADDR: 1 - GROUP_ID: 1 - producer: - enabled: true - -rabbitmq: - configs: - order: #实例名称 - host: 192.168.10.111 - port: 5672 - virtualHost: ll-dev - username: zhangziheng - password: zhangziheng - producer: - enabled: true - exchange: order_status - routingKey: ORDER_COMPLETE - confirmCallback: orderMqConfirmCallback - commonChange: - host: 192.168.10.111 - port: 5672 - virtualHost: ll-dev - username: zhangziheng - password: zhangziheng - producer: - enabled: false - consumer: - enabled: true - subscribeList: - - queue: 'app-business' - messageListener: commonChangeMessageListener +# 参考文章 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 From 055987541c1f88ec11c9a355850707bf7221c089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E8=A8=80?= <2439534736@qq.com> Date: Fri, 9 Jan 2026 11:41:19 +0800 Subject: [PATCH 20/20] =?UTF-8?q?1.=E4=BC=98=E5=8C=96=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E5=85=A8=E5=B1=80=E5=BC=82=E5=B8=B8=E7=B1=BB=202.=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E4=BB=8B=E7=BB=8D=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 173 ++++++++++++------ pom.xml | 4 + .../exception/GlobalExceptionHandler.java | 80 ++++++++ .../exception/GlobalExceptionResolver.java | 53 ------ .../controller/business/UserController.java | 3 +- .../xf/basedemo/model/res/LoginInfoRes.java | 2 + 6 files changed, 209 insertions(+), 106 deletions(-) create mode 100644 src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionHandler.java delete mode 100644 src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionResolver.java diff --git a/README.md b/README.md index c8f1cec..591139e 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,136 @@ -## 拿来即用springboot基础脚手架 +# XF-Boot-Base (Spring Boot Base Demo) + +
+ +Spring Boot +Java +Nacos +MyBatis Plus + +
+
+ +[![GitHub stars](https://img.shields.io/github/stars/RemainderTime/spring-boot-base-demo?style=social&label=Stars)](https://github.com/RemainderTime/spring-boot-base-demo) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square)](./LICENSE) --- -### 项目介绍 -[![](https://img.shields.io/badge/-@remaindertime-FC5531?style=flat&logo=csdn&logoColor=FC5531&labelColor=424242)](https://blog.csdn.net/qq_39818325?type=blog) -[![GitHub Stars](https://img.shields.io/github/stars/RemainderTime/spring-boot-base-demo?style=social)](https://github.com/RemainderTime/spring-boot-base-demo) -![](https://img.shields.io/badge/jdk-1.8+-blue.svg) -![](https://img.shields.io/badge/springboot-3.3.3-{徽标颜色}.svg) -![](https://img.shields.io/badge/springdoc-2.6.0-{徽标颜色}.svg) -![](https://img.shields.io/badge/elasticsearch-8.16.0-005571.svg) -![](https://img.shields.io/badge/redis-3.3.3-FF4438.svg) ---- -> 这是一个基于 **Spring Boot 3.3.3** 的快速构建单体架构脚手架,旨在帮助开发者快速搭建高效、稳定的项目基础框架。项目集成了多种常用的技术组件与功能,涵盖从用户认证到数据加密、从全局异常处理到搜索引擎操作,适合个人学习与企业级单体应用开发。 +### 「 为企业级开发而生的高效脚手架 」 -#### 分支 -- master 快速上手开发spring boot 用户端单体应用 -- feature/admin-auth-spring-security 基于master分支集成spring官方鉴权框架spring security框架,可用于后台管理系统后端项目,实现RBAC模型(角色 → 用户 → 菜单 → 权限)基于角色的访问控制 -- feature/admin-auth-sa-token 基于master分支集成国产权限框架sa-token,可用于后台管理系统后端项目,实现RBAC模型(角色 → 用户 → 菜单 → 权限)基于角色的访问控制 -- component/rocketmq-and-es 基于master分支集成消息队列原生RocketMQ5.x与原生Elasticsearch 8.x,提供消息队列与搜索引擎服务,实现消息持久化与全文检索 -- feature/master-payment 基于master分支集成支付宝沙盒功能(H5支付、APP支付) +

+ 💎 关于项目  |  + ⚡ 核心亮点  |  + 🌿 生态全景  |  + 🚀 快速运行  |  + 📅 项目日志 +

+
-### 集成技术与功能亮点 +
-- 身份认证与授权(JWT):基于 JWT 实现用户认证与授权,确保系统安全性。 -- 数据加密(RSA):提供 RSA 非对称加密支持,保障敏感数据安全。 -- 持久层框架(MyBatis Plus):简化数据库操作,提供高效的 CRUD 支持。 -- 数据库(MySQL):采用 MySQL 作为默认数据库,易于扩展和维护。 -- 数据连接池(Hikari):高性能数据源管理,优化数据库连接效率。 -- 缓存(Redis):支持分布式缓存,提升系统响应速度与并发能力。 -- 接口文档(springdoc-openapi):自动生成标准化 API 文档,便于调试与集成。 -- 模板引擎(Thymeleaf):支持动态页面渲染,提升前后端协同效率。 -- 容器化支持(Docker):内置 Dockerfile,轻松实现环境部署与迁移。 -- 搜索引擎(Elasticsearch 8.x):集成最新版本 Elasticsearch Java 客户端,提供高效的全文检索与复杂查询功能。 -- 全局异常处理:统一管理异常,提升代码可维护性与调试效率。 -- 拦截器支持:轻松实现请求拦截与权限控制。 +## � 关于项目 -### 项目优势 -**全面适配 Spring Boot 3.x** -- 所有组件已全面升级为支持 Spring Boot 3.x 的最新版本。解决了开发者在版本升级中遇到的各种不兼容和适配问题,大大减少了升级带来的额外工作量,让项目开发更加顺畅。 +**XF-Boot-Base** 并非仅仅是一个简单的 "Hello World" 示例,而是一个经过精心打磨、具备生产级标准的 **Spring Boot 3.3** 全栈开发底座。 -**初学者友好** -- 提供清晰的代码结构与详细的配置说明,帮助初学者快速上手微服务与单体架构的开发实践。 +我们深入分析了企业单体应用到微服务架构演进过程中的痛点,构建了一套**模块化、可插拔、高扩展**的基础框架。从底层的 **JDK 17** 优化,到顶层的 API 接口规范;从**JWT 安全认证**的丝滑接入,到 **Docker 容器化**的一键部署。XF-Boot-Base 旨在消除重复造轮子的时间成本,让开发者能够专注于核心业务逻辑的实现。 -**高扩展性** -- 丰富的功能集成,涵盖了开发中常见的场景,减少重复开发工作量,同时为定制化需求预留了扩展空间。 - -**稀缺的最新技术操作示例** -- 最新版本的 Elasticsearch 8.x 集成、Java 客户端操作示例和现代化 API 设计,让开发者能够轻松掌握分布式搜索引擎的使用。 - -### 版本更新 2024-10-12 +无论你是想要快速验证想法的独立开发者,还是寻找稳健基石的架构师,这里都有你需要的最佳实践。 --- -1. springboot版本升级3.x -2. mybatis plus版本升级3.x -3. dynamic mybatis plus版本升级3.x -4. redis版本升级3.x以及配置优化 -5. 替换swagger依赖支持spring boot3.x (knife4j->springdoc-openapi) -6. 新增请求头工具类 -7. 参数校验异常捕获优化 -8. 登录拦截器注册为spring容器管理 -9. 新增本地日志配置文件 + +## ⚡ 核心亮点 + +
+ +| 🚀 **前沿技术** | 🔐 **安全无忧** | 🐳 **云原生友好** | +| :--- | :--- | :--- | +| 紧跟 **Spring Boot 3.x** 生态,
基于 **Java 17 LTS** 构建,
享受最新技术红利。 | 深度整合 **JWT** 令牌认证
& **RSA** 非对称加密,
为数据安全保驾护航。 | 内置 **Dockerfile** 脚本,
支持 **Docker Compose** 编排,
部署快人一步。 | + +| 💾 **数据增强** | 🔌 **微服务预装** | 🛠 **极致体验** | +| :--- | :--- | :--- | +| **MyBatis Plus** 强力驱动,
**Dynamic Datasource**
轻松驾驭多数据源场景。 | 原生集成 **Nacos**,
配置中心与注册中心开箱即用,
平滑过渡微服务。 | **SpringDoc (OpenAPI 3)**
自动生成精美文档,
调试开发得心应手。 | + +
--- -如果这个项目对你有帮助,请随手点个 Star ⭐ 支持一下吧!🎉✨ 你的支持是我持续优化的动力!❤️ + +## 🌿 生态全景 + +我们采用 **"核心 + 插件化"** 的分支管理策略,以 `master` 为稳定基石,通过不同分支满足多样化的业务需求。 + +| 🌳 分支标识 | 🎯 定位 | 📝 功能描述 | 🏭 最佳应用场景 | +| :--- | :--- | :--- | :--- | +| **`master`** | **核心底座** | 标准化脚手架,含 JWT/Nacos/Redis | 🚀 快速启动标准单体项目 | +| `feature/admin-auth-spring-security` | **安全堡垒** | Spring Security 官方方案 (RBAC) | 🏦 金融级、政府级后台系统 | +| `feature/admin-auth-sa-token` | **敏捷权限** | Sa-Token 轻量级权限控制 | ⚡ 中小型项目、国内快速开发 | +| `component/rocketmq-and-es` | **高并发** | RocketMQ 5.x + Elasticsearch 8.x | 📈 海量日志、搜索、高吞吐业务 | +| `feature/master-payment` | **商业变现** | 支付宝沙盒支付 (H5/App) | 💳 电商、会员订阅、SaaS 平台 | + +> **💡 提示**: 所有分支均基于 `master` 演进,可根据项目规模灵活 `git merge` 所需功能模块。 + +--- + +## 🚀 快速运行 + +### 🛠️ 环境依赖 +* **JDK**: 17 + +* **Maven**: 3.8 + +* **MySQL**: 8.0 + +* **Redis**: 5.0 + +* **Nacos**: 2.x (可选) + +### 🏃‍♂️ 启动步骤 + +> **Step 1: 获取源码** +> ```bash +> git clone https://github.com/RemainderTime/spring-boot-base-demo.git +> cd spring-boot-base-demo +> ``` + +> **Step 2: 数据准备** +> * 创建数据库 `xf_boot_base` +> * 修改 `src/main/resources/application.yml` 配好你的数据库账号密码 +> * *(注:实体类完善,表结构建议通过 JPA 或手动创建)* + +> **Step 3: 启动服务** +> +> **方式 A: 本地 Maven 运行** +> ```bash +> mvn spring-boot:run +> ``` +> +> **方式 B: Docker Compose 一键编排** +> ```bash +> cd src/main/resources/docker +> docker-compose -f boot-docker-compose.yml up -d +> ``` + +> **Step 4: 探索接口** +> 打开浏览器访问: `http://localhost:8080/doc.html` + +--- + +## 📅 项目日志 + +### v1.0.1 (2024-10-12) +* ⬆️ **内核升级**: Spring Boot 3.3.3 & MyBatis Plus 3.5.8 +* 📝 **文档重构**: 全面拥抱 SpringDoc OpenAPI,弃用旧版 Swagger +* 🛡️ **安全加固**: 优化全局异常拦截与参数校验机制 + +--- + +## 📈 关注趋势 + +[![Star History Chart](https://api.star-history.com/svg?repos=RemainderTime/spring-boot-base-demo&type=Date)](https://star-history.com/#RemainderTime/spring-boot-base-demo&Date) + +
+
+ +**喜欢这个项目?请点个 Star ⭐ 支持作者持续更新!** + +
+ + + diff --git a/pom.xml b/pom.xml index 1b95392..d2a9b18 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,10 @@ org.springframework.boot spring-boot-starter-actuator + + org.springframework.boot + spring-boot-starter-validation + org.springframework.boot spring-boot-starter-data-redis diff --git a/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionHandler.java b/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..0bcc700 --- /dev/null +++ b/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionHandler.java @@ -0,0 +1,80 @@ +package cn.xf.basedemo.common.exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * @Description: 全局异常处理类 (使用 @RestControllerAdvice 替代旧版 + * HandlerExceptionResolver) + * @Author: xiongfeng + * @Date: 2025/1/9 + * @Version: 2.0 + */ +@Slf4j +@RestControllerAdvice +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()); + } + + /** + * 处理业务逻辑异常 + */ + @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()); + } + + /** + * 处理参数校验异常 (处理 @Valid / @Validated 触发的异常) + */ + @ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class }) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public GenericResponse handleValidationException(Exception e, HttpServletRequest request) { + BindingResult bindingResult = null; + if (e instanceof MethodArgumentNotValidException) { + bindingResult = ((MethodArgumentNotValidException) e).getBindingResult(); + } else if (e instanceof BindException) { + bindingResult = ((BindException) e).getBindingResult(); + } + + String errorMsg = "参数校验失败"; + if (bindingResult != null && bindingResult.hasErrors()) { + FieldError fieldError = bindingResult.getFieldError(); + if (fieldError != null) { + errorMsg = fieldError.getDefaultMessage(); + } + } + log.warn("参数校验失败 [URL:{}]: {}", request.getRequestURI(), errorMsg); + return new GenericResponse<>(ResponseCode.USER_INPUT_ERROR.getCode(), null, errorMsg); + } + + /** + * 处理所有未知的系统异常 (兜底) + */ + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public GenericResponse handleSystemException(Exception e, HttpServletRequest request) { + // 生产级关键点:必须记录异常堆栈,否则无法排查 BUG + log.error("系统发生未知异常 [URL:{}]", request.getRequestURI(), e); + return new GenericResponse<>(500, null, "系统内部繁忙,请稍后再试"); + } +} diff --git a/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionResolver.java b/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionResolver.java deleted file mode 100644 index 09ad30f..0000000 --- a/src/main/java/cn/xf/basedemo/common/exception/GlobalExceptionResolver.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.xf.basedemo.common.exception; - -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import java.io.IOException; -import java.io.PrintWriter; - -/** - * @Description: 全局异常捕获类(所有异常(包括拦截器、Controller、视图))HandlerExceptionResolver更底层 - * @ClassName: GlobalExceptionResolver - * @Author: xiongfeng - * @Date: 2025/8/23 23:30 - * @Version: 1.0 - */ -@Slf4j -@Component -public class GlobalExceptionResolver implements HandlerExceptionResolver { - @Override - public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { - response.setContentType("application/json;charset=UTF-8"); - - try (PrintWriter writer = response.getWriter()) { - if (ex instanceof LoginException) { - response.setStatus(HttpStatus.FORBIDDEN.value()); - LoginException le = (LoginException) ex; - writer.write(new ObjectMapper().writeValueAsString( - new GenericResponse<>(le.getCode(), null, le.getMessage()) - )); - } else if (ex instanceof BusinessException) { - BusinessException be = (BusinessException) ex; - response.setStatus(HttpStatus.BAD_REQUEST.value()); - writer.write(new ObjectMapper().writeValueAsString( - new GenericResponse<>(be.getCode(), null, be.getMessage()) - )); - } else { - response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); - writer.write(new ObjectMapper().writeValueAsString( - new GenericResponse<>(500, null, "系统异常") - )); - } - } catch (IOException ioEx) { - log.error("写响应失败", ioEx); - } - return new ModelAndView(); - } -} diff --git a/src/main/java/cn/xf/basedemo/controller/business/UserController.java b/src/main/java/cn/xf/basedemo/controller/business/UserController.java index f18ef7d..5633410 100644 --- a/src/main/java/cn/xf/basedemo/controller/business/UserController.java +++ b/src/main/java/cn/xf/basedemo/controller/business/UserController.java @@ -8,6 +8,7 @@ import cn.xf.basedemo.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; /** @@ -27,7 +28,7 @@ public class UserController { @Operation(summary = "用户登录", description = "用户登录") @PostMapping("/login") - public RetObj login(@RequestBody LoginInfoRes res) { + public RetObj login(@RequestBody @Validated LoginInfoRes res) { return userService.login(res); } diff --git a/src/main/java/cn/xf/basedemo/model/res/LoginInfoRes.java b/src/main/java/cn/xf/basedemo/model/res/LoginInfoRes.java index 7c7a5d0..d719e92 100644 --- a/src/main/java/cn/xf/basedemo/model/res/LoginInfoRes.java +++ b/src/main/java/cn/xf/basedemo/model/res/LoginInfoRes.java @@ -1,6 +1,7 @@ package cn.xf.basedemo.model.res; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; import lombok.Data; /** @@ -16,6 +17,7 @@ public class LoginInfoRes { /** * 登录密文 */ + @NotBlank(message = "登录密文不能为空") @Schema(name = "登录密文") private String encryptedData; }