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