From 8e264887385b7345baf873c5cf4b896ea2f7328d Mon Sep 17 00:00:00 2001 From: ziin Date: Tue, 16 Dec 2025 21:50:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(config):=20=E6=8E=A5=E5=85=A5=20Nacos=20?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E4=B8=AD=E5=BF=83=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20AppConfig=E3=80=81NacosAppConfigCenter=20=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=B1=BB=20-=20=E5=B0=86=20userRegisterPrope?= =?UTF-8?q?rties=20=E7=9A=84=E9=BB=98=E8=AE=A4=E5=80=BC=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E4=BB=8E=20Nacos=20=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=20-=20=E6=B3=A8=E5=86=8C/=E5=88=9B=E5=BB=BA=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=97=B6=E5=85=8D=E8=B4=B9=E9=85=8D=E9=A2=9D=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E5=8A=A8=E6=80=81=E9=85=8D=E7=BD=AE=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=20-=20=E5=A2=9E=E5=8A=A0=20nacos-client=20=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E5=B9=B6=E9=85=8D=E7=BD=AE=20dev=20=E7=8E=AF=E5=A2=83=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 ++ .../com/yolo/keyborad/config/AppConfig.java | 24 ++++++ .../keyborad/config/NacosAppConfigCenter.java | 82 +++++++++++++++++++ .../config/UserRegisterProperties.java | 2 +- .../keyborad/controller/UserController.java | 3 +- .../service/impl/UserServiceImpl.java | 28 ++++--- src/main/resources/application-dev.yml | 80 +++++++++--------- src/main/resources/application-prod.yml | 24 +++--- src/main/resources/application.yml | 14 ++-- 9 files changed, 195 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/yolo/keyborad/config/AppConfig.java create mode 100644 src/main/java/com/yolo/keyborad/config/NacosAppConfigCenter.java diff --git a/pom.xml b/pom.xml index ad209e9..8ae60d5 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,13 @@ org.springframework.boot spring-boot-starter-web + + + com.alibaba.nacos + nacos-client + 3.1.1 + + io.qdrant diff --git a/src/main/java/com/yolo/keyborad/config/AppConfig.java b/src/main/java/com/yolo/keyborad/config/AppConfig.java new file mode 100644 index 0000000..990c608 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/config/AppConfig.java @@ -0,0 +1,24 @@ +package com.yolo.keyborad.config; + +import lombok.Data; + +/* + * @author: ziin + * @date: 2025/12/16 21:18 + */ +@Data +public class AppConfig { + + private UserRegisterProperties userRegisterProperties = new UserRegisterProperties(); + + + @Data + public static class UserRegisterProperties { + + /** + * 新用户注册时的免费使用次数 + */ + private Integer freeTrialQuota = 5; + + } +} diff --git a/src/main/java/com/yolo/keyborad/config/NacosAppConfigCenter.java b/src/main/java/com/yolo/keyborad/config/NacosAppConfigCenter.java new file mode 100644 index 0000000..ec8648b --- /dev/null +++ b/src/main/java/com/yolo/keyborad/config/NacosAppConfigCenter.java @@ -0,0 +1,82 @@ +package com.yolo.keyborad.config; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; + +@Slf4j +@Configuration +public class NacosAppConfigCenter { + + private final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + @Bean + public ConfigService nacosConfigService( + @Value("${nacos.config.server-addr}") String serverAddr + ) throws NacosException { + Properties p = new Properties(); + p.put("serverAddr", serverAddr); + return NacosFactory.createConfigService(p); + } + + @Bean + public DynamicAppConfig dynamicAppConfig( + ConfigService configService, + @Value("${nacos.config.group}") String group, + @Value("${nacos.config.data-id}") String dataId + ) throws Exception { + + DynamicAppConfig holder = new DynamicAppConfig(); + + // 启动先拉一次 + String content = configService.getConfig(dataId, group, 3000); + if (content != null && !content.isBlank()) { + holder.ref.set(parse(content)); + log.info("Loaded nacos config: dataId={}, group={}", dataId, group); + } else { + log.warn("Empty nacos config: dataId={}, group={}", dataId, group); + } + + // 监听热更新 + configService.addListener(dataId, group, new Listener() { + @Override public Executor getExecutor() { return null; } + @Override public void receiveConfigInfo(String configInfo) { + try { + AppConfig newCfg = parse(configInfo); + holder.ref.set(newCfg); + log.info("Refreshed nacos config: dataId={}, group={}", dataId, group); + log.info("New config: {}", newCfg.toString()); + } catch (Exception e) { + // 解析失败不覆盖旧配置 + log.error("Failed to refresh nacos config: dataId={}, keep old config.", dataId, e); + } + } + }); + + return holder; + } + + private AppConfig parse(String yaml) throws Exception { + if (yaml == null || yaml.isBlank()) return new AppConfig(); + return yamlMapper.readValue(yaml, AppConfig.class); + } + + @Getter + public static class DynamicAppConfig { + private final AtomicReference ref = new AtomicReference<>(new AppConfig()); + } +} diff --git a/src/main/java/com/yolo/keyborad/config/UserRegisterProperties.java b/src/main/java/com/yolo/keyborad/config/UserRegisterProperties.java index dc57d07..909e620 100644 --- a/src/main/java/com/yolo/keyborad/config/UserRegisterProperties.java +++ b/src/main/java/com/yolo/keyborad/config/UserRegisterProperties.java @@ -15,6 +15,6 @@ public class UserRegisterProperties { /** * 新用户注册时的免费使用次数 */ - private Integer freeTrialQuota = 5; + private Integer freeTrialQuota; } diff --git a/src/main/java/com/yolo/keyborad/controller/UserController.java b/src/main/java/com/yolo/keyborad/controller/UserController.java index 14a1e13..073bd20 100644 --- a/src/main/java/com/yolo/keyborad/controller/UserController.java +++ b/src/main/java/com/yolo/keyborad/controller/UserController.java @@ -94,8 +94,7 @@ public class UserController { @PostMapping("/register") @Operation(summary = "用户注册",description = "用户注册接口") public BaseResponse register(@RequestBody UserRegisterDTO userRegisterDTO) { - userService.userRegister(userRegisterDTO); - return ResultUtils.success(true); + return ResultUtils.success(userService.userRegister(userRegisterDTO)); } @PostMapping("/sendVerifyMail") diff --git a/src/main/java/com/yolo/keyborad/service/impl/UserServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/UserServiceImpl.java index 37fd499..47edbb5 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/UserServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/UserServiceImpl.java @@ -8,16 +8,16 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yolo.keyborad.common.ErrorCode; +import com.yolo.keyborad.config.AppConfig; +import com.yolo.keyborad.config.NacosAppConfigCenter; +import com.yolo.keyborad.config.UserRegisterProperties; import com.yolo.keyborad.exception.BusinessException; import com.yolo.keyborad.mapper.KeyboardUserMapper; import com.yolo.keyborad.model.dto.user.*; import com.yolo.keyborad.model.entity.KeyboardUser; import com.yolo.keyborad.model.entity.KeyboardUserWallet; import com.yolo.keyborad.model.vo.user.KeyboardUserRespVO; -import com.yolo.keyborad.service.KeyboardCharacterService; -import com.yolo.keyborad.service.KeyboardUserLoginLogService; -import com.yolo.keyborad.service.KeyboardUserWalletService; -import com.yolo.keyborad.service.UserService; +import com.yolo.keyborad.service.*; import jakarta.servlet.http.HttpServletRequest; import com.yolo.keyborad.utils.RedisUtil; import com.yolo.keyborad.utils.SendMailUtils; @@ -61,10 +61,16 @@ public class UserServiceImpl extends ServiceImpl 0; } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 1542905..8198c41 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -5,27 +5,27 @@ spring: username: root password: 123asd -# 日志配置 +# ???? logging: level: - # 设置 mapper 包的日志级别为 DEBUG,打印 SQL 语句 + # ?? mapper ??????? DEBUG??? SQL ?? com.yolo.keyborad.mapper: DEBUG - # 设置根日志级别 + # ??????? root: INFO - # Spring 框架日志 + # Spring ???? org.springframework: INFO - # MyBatis 日志 + # MyBatis ?? org.mybatis: DEBUG pattern: - # 彩色控制台日志格式 - # 时间-无颜色,日志级别-根据级别变色,进程ID-品红,线程-黄色,类名-青色,消息-默认色 + # ????????? + # ??-????????-?????????ID-?????-?????-?????-??? console: "%d{yyyy-MM-dd HH:mm:ss.SSS} | %clr(%-5level){highlight} %clr(${PID:- }){magenta} | %clr(%-15thread){yellow} %clr(%-50logger{50}){cyan} | %msg%n" knife4j: enable: true openapi: - title: "接口文档" + title: "????" version: 1.0 group: default: @@ -38,65 +38,71 @@ apple: issuer-id: "178b442e-b7be-4526-bd13-ab293d019df0" key-id: "Y7TF7BV74G" bundle-id: "com.loveKey.nyx" - # app 在 App Store 的 Apple ID(数值),生产环境必填 + # app ? App Store ? Apple ID??????????? app-apple-id: 1234567890 - # p8 私钥文件路径(你可以放在 resources 下) + # p8 ???????????? resources ?? private-key-path: "classpath:SubscriptionKey_Y7TF7BV74G.p8" - # SANDBOX 或 PRODUCTION + # SANDBOX ? PRODUCTION environment: "SANDBOX" - # 根证书路径(从 Apple PKI 下载) + # ??????? Apple PKI ??? root-certificates: - "classpath:AppleRootCA-G2.cer" - "classpath:AppleRootCA-G3.cer" dromara: - x-file-storage: #文件存储配置 - default-platform: cloudflare-r2 #默认使用的存储平台 - thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】 + x-file-storage: #?????? + default-platform: cloudflare-r2 #????????? + thumbnail-suffix: ".min.jpg" #?????????.min.jpg??.png? enable-byte-file-wrapper: false - #对应平台的配置写在这里,注意缩进要对齐 + #??????????????????? amazon-s3-v2: # Amazon S3 V2 - - platform: cloudflare-r2 # 存储平台标识 - enable-storage: true # 启用存储 + - platform: cloudflare-r2 # ?????? + enable-storage: true # ???? access-key: 550b33cc4d53e05c2e438601f8a0e209 secret-key: df4d529cdae44e6f614ca04f4dc0f1f9a299e57367181243e8abdc7f7c28e99a - region: ENAM # 必填 - end-point: https://b632a61caa85401f63c9b32eef3a74c8.r2.cloudflarestorage.com # 必填 - bucket-name: keyborad-resource #桶名称 - domain: https://resource.loveamorkey.com/ # 访问域名,注意“/”结尾,例如:https://abcd.s3.ap-east-1.amazonaws.com/ - base-path: avatar/ # 基础路径 + region: ENAM # ?? + end-point: https://b632a61caa85401f63c9b32eef3a74c8.r2.cloudflarestorage.com # ?? + bucket-name: keyborad-resource #??? + domain: https://resource.loveamorkey.com/ # ????????/???????https://abcd.s3.ap-east-1.amazonaws.com/ + base-path: avatar/ # ???? mailgun: - api-key: ${MAILGUN_API_KEY} # 你的 Private API Key - domain: sandboxxxxxxx.mailgun.org # 或你自己的业务域名 - from-email: no-reply@yourdomain.com # 发件人邮箱 - from-name: Key Of Love # 发件人名称(可选) + api-key: ${MAILGUN_API_KEY} # ?? Private API Key + domain: sandboxxxxxxx.mailgun.org # ????????? + from-email: no-reply@yourdomain.com # ????? + from-name: Key Of Love # ????????? -# 用户注册配置 +# ?????? user: register: - # 新用户注册时的免费使用次数 + # ????????????? free-trial-quota: 5 -############## Sa-Token 配置 (文档: https://sa-token.cc) ############## +############## Sa-Token ?? (??: https://sa-token.cc) ############## sa-token: - # token 名称(同时也是 cookie 名称) + # token ??????? cookie ??? token-name: auth-token - # token 有效期(单位:秒) 默认30天,-1 代表永久有效 + # token ????????? ??30??-1 ?????? timeout: 2592000 - # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 + # token ??????????????? token ???????????????????-1 ?????????? active-timeout: -1 - # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) + # ?????????????? ?? true ???????, ? false ?????????? is-concurrent: true - # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) + # ????????????????? token ?? true ????????? token, ? false ????????? token? is-share: false - # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + # token ?????????uuid?simple-uuid?random-32?random-64?random-128?tik? token-style: random-128 - # 是否输出操作日志 + # ???????? is-log: true + +nacos: + config: + server-addr: 127.0.0.1:8848 + group: DEFAULT_GROUP + data-id: keyboard_default-config.yaml \ No newline at end of file diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 14592f2..ed1460c 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -5,32 +5,32 @@ spring: username: root password: 123asd -# 生产环境日志配置 +# ???????? logging: level: - # 生产环境不打印 SQL 日志 + # ??????? SQL ?? com.yolo.keyborad.mapper: INFO - # 设置根日志级别 + # ??????? root: INFO - # Spring 框架日志 + # Spring ???? org.springframework: WARN - # MyBatis 日志 + # MyBatis ?? org.mybatis: WARN pattern: - # 生产环境控制台日志格式 + # ??????????? console: "%d{yyyy-MM-dd HH:mm:ss.SSS} | %clr(%-5level){highlight} %clr(${PID:- }){magenta} | %clr(%-15thread){yellow} %clr(%-50logger{50}){cyan} | %msg%n" - # 文件日志格式(无颜色代码) + # ????????????? file: "%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level ${PID:- } | %-15thread %-50logger{50} | %msg%n" file: - # 生产环境日志文件路径 + # ?????????? name: logs/keyborad-backend.log - # 日志文件大小限制 + # ???????? max-size: 10MB - # 保留的日志文件数量 + # ????????? max-history: 30 -# 用户注册配置 +# ?????? user: register: - # 新用户注册时的免费使用次数 + # ????????????? free-trial-quota: 5 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4948bf6..4dc12bb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -18,17 +18,17 @@ spring: mvc: pathmatch: matching-strategy: ANT_PATH_MATCHER - # session 失效时间(分钟) + # session ???????? session: timeout: 86400 store-type: redis - # redis 配置 + # redis ?? data: redis: port: 6379 host: localhost database: 0 - # 启用 ANSI 彩色输出 + # ?? ANSI ???? output: ansi: enabled: always @@ -47,10 +47,10 @@ mybatis-plus: log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl global-config: db-config: - logic-delete-field: isDelete # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) - logic-delete-value: 1 # 逻辑已删除值(默认为 1) - logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) - # 扫描 TypeHandler 包 + logic-delete-field: isDelete # ????????????(since 3.3.0,????????????2) + logic-delete-value: 1 # ??????(??? 1) + logic-not-delete-value: 0 # ??????(??? 0) + # ?? TypeHandler ? type-handlers-package: com.yolo.keyborad.typehandler appid: loveKeyboard