feat:新增系统配置模块(Entity/Mapper/DTO/Service/Controller)+ 登录配置公开接口

This commit is contained in:
2026-06-27 10:25:17 +08:00
parent ed741ac8bf
commit 9131203d1c
11 changed files with 433 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
-- 系统配置表
CREATE TABLE t_system_config (
id VARCHAR(64) PRIMARY KEY,
config_key VARCHAR(100) NOT NULL UNIQUE COMMENT '配置唯一标识',
config_value VARCHAR(500) NOT NULL DEFAULT '' COMMENT '配置值',
value_type VARCHAR(20) NOT NULL DEFAULT 'string' COMMENT '值类型: boolean/string/number/json',
config_group VARCHAR(50) NOT NULL DEFAULT 'system' COMMENT '配置分组: system/login/notification',
config_name VARCHAR(100) NOT NULL DEFAULT '' COMMENT '显示名称',
description VARCHAR(300) DEFAULT '' COMMENT '配置说明',
sort_order INT NOT NULL DEFAULT 0 COMMENT '排序号',
is_visible TINYINT NOT NULL DEFAULT 1 COMMENT '是否在管理后台可见: 0-隐藏, 1-显示',
create_by VARCHAR(64) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(64) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
is_deleted TINYINT NOT NULL DEFAULT 0
) COMMENT = '系统配置表';
-- 初始数据:短信登录开关(默认关闭)
INSERT INTO t_system_config (id, config_key, config_value, value_type, config_group, config_name, description, sort_order, is_visible, create_time, update_time, is_deleted)
VALUES (
REPLACE(UUID(), '-', ''),
'sms_login_enabled',
'false',
'boolean',
'login',
'短信登录',
'是否启用手机号+短信验证码登录方式',
1,
1,
NOW(),
NOW(),
0
);
@@ -60,6 +60,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
"/actuator/**", // Actuator endpoints
"/admin/**", // 排除管理员路径,由管理员拦截器处理
"/auth/wechat/login", // WeChat mini program login endpoint
"/auth/loginConfig", // 登录方式配置接口(免登录)
"/error" // Spring Boot error page
)
.order(2); // 优先级2
@@ -10,9 +10,11 @@ import com.emotion.dto.response.ResetPasswordResponse;
import com.emotion.dto.response.AuthResponse;
import com.emotion.dto.response.CaptchaResponse;
import com.emotion.dto.response.LoginConfigResponse;
import com.emotion.dto.response.SmsCodeResponse;
import com.emotion.dto.response.UserInfoResponse;
import com.emotion.service.AuthService;
import com.emotion.service.SystemConfigService;
import com.emotion.service.TokenService;
import com.emotion.util.UserContextUtils;
import io.swagger.v3.oas.annotations.Operation;
@@ -41,6 +43,9 @@ public class AuthController {
@Autowired
private TokenService tokenService;
@Autowired
private SystemConfigService systemConfigService;
/**
* 用户登录(简化版:手机号+验证码,不存在则自动注册)
*/
@@ -61,6 +66,16 @@ public class AuthController {
return Result.success("登录成功", response);
}
/**
* 获取登录方式配置
*/
@GetMapping("/loginConfig")
@Operation(summary = "获取登录方式配置", description = "返回当前启用的登录方式,供小程序登录页动态渲染")
public Result<LoginConfigResponse> getLoginConfig() {
LoginConfigResponse response = systemConfigService.getLoginConfig();
return Result.success(response);
}
@PostMapping(value = "/register")
@Operation(summary = "用户注册", description = "使用手机号、密码和短信验证码进行注册")
public Result<AuthResponse> register(@Valid @RequestBody RegisterRequest request) {
@@ -0,0 +1,48 @@
package com.emotion.controller;
import com.emotion.common.Result;
import com.emotion.dto.request.SystemConfigUpdateRequest;
import com.emotion.dto.response.SystemConfigResponse;
import com.emotion.service.SystemConfigService;
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.*;
import java.util.List;
/**
* 系统配置管理控制器(管理端)
*
* @author system
* @date 2026-06-27
*/
@RestController
@RequestMapping("/admin/systemConfig")
@Tag(name = "系统配置管理", description = "系统配置的查询和更新功能")
public class SystemConfigController {
@Autowired
private SystemConfigService systemConfigService;
/**
* 获取所有可见配置列表
*/
@GetMapping("/list")
@Operation(summary = "获取配置列表", description = "获取所有可见的系统配置列表")
public Result<List<SystemConfigResponse>> list() {
List<SystemConfigResponse> configs = systemConfigService.getVisibleConfigList();
return Result.success(configs);
}
/**
* 批量更新配置
*/
@PutMapping("/update")
@Operation(summary = "批量更新配置", description = "批量更新系统配置值")
public Result<Void> update(@RequestBody @Validated List<SystemConfigUpdateRequest> requests) {
systemConfigService.batchUpdateConfigs(requests);
return Result.success("更新成功", null);
}
}
@@ -0,0 +1,27 @@
package com.emotion.dto.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 系统配置更新请求
*
* @author system
* @date 2026-06-27
*/
@Data
public class SystemConfigUpdateRequest {
/**
* 配置唯一标识
*/
@NotBlank(message = "配置标识不能为空")
private String configKey;
/**
* 配置值
*/
@NotBlank(message = "配置值不能为空")
private String configValue;
}
@@ -0,0 +1,24 @@
package com.emotion.dto.response;
import lombok.Data;
/**
* 登录方式配置响应
* 返回给小程序,告知当前启用的登录方式
*
* @author system
* @date 2026-06-27
*/
@Data
public class LoginConfigResponse {
/**
* 是否启用微信登录
*/
private Boolean wechatLoginEnabled;
/**
* 是否启用短信登录
*/
private Boolean smsLoginEnabled;
}
@@ -0,0 +1,48 @@
package com.emotion.dto.response;
import lombok.Data;
/**
* 系统配置响应
*
* @author system
* @date 2026-06-27
*/
@Data
public class SystemConfigResponse {
/**
* 配置唯一标识
*/
private String configKey;
/**
* 配置值
*/
private String configValue;
/**
* 值类型: boolean/string/number/json
*/
private String valueType;
/**
* 配置分组
*/
private String configGroup;
/**
* 显示名称
*/
private String configName;
/**
* 配置说明
*/
private String description;
/**
* 排序号
*/
private Integer sortOrder;
}
@@ -0,0 +1,72 @@
package com.emotion.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.emotion.common.BaseEntity;
import lombok.experimental.SuperBuilder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 系统配置实体
*
* @author system
* @date 2026-06-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_system_config")
public class SystemConfig extends BaseEntity {
/**
* 配置唯一标识
*/
@TableField("config_key")
private String configKey;
/**
* 配置值
*/
@TableField("config_value")
private String configValue;
/**
* 值类型: boolean/string/number/json
*/
@TableField("value_type")
private String valueType;
/**
* 配置分组: system/login/notification
*/
@TableField("config_group")
private String configGroup;
/**
* 显示名称
*/
@TableField("config_name")
private String configName;
/**
* 配置说明
*/
@TableField("description")
private String description;
/**
* 排序号
*/
@TableField("sort_order")
private Integer sortOrder;
/**
* 是否在管理后台可见: 0-隐藏, 1-显示
*/
@TableField("is_visible")
private Integer isVisible;
}
@@ -0,0 +1,15 @@
package com.emotion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.emotion.entity.SystemConfig;
import org.apache.ibatis.annotations.Mapper;
/**
* 系统配置Mapper接口
*
* @author system
* @date 2026-06-27
*/
@Mapper
public interface SystemConfigMapper extends BaseMapper<SystemConfig> {
}
@@ -0,0 +1,41 @@
package com.emotion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.emotion.dto.request.SystemConfigUpdateRequest;
import com.emotion.dto.response.LoginConfigResponse;
import com.emotion.dto.response.SystemConfigResponse;
import com.emotion.entity.SystemConfig;
import java.util.List;
/**
* 系统配置服务接口
*
* @author system
* @date 2026-06-27
*/
public interface SystemConfigService extends IService<SystemConfig> {
/**
* 获取所有可见配置列表
*/
List<SystemConfigResponse> getVisibleConfigList();
/**
* 批量更新配置
*/
void batchUpdateConfigs(List<SystemConfigUpdateRequest> requests);
/**
* 获取配置值(带 Redis 缓存)
*
* @param configKey 配置标识
* @return 配置值字符串,不存在返回 null
*/
String getConfigValue(String configKey);
/**
* 获取登录方式配置
*/
LoginConfigResponse getLoginConfig();
}
@@ -0,0 +1,108 @@
package com.emotion.service.impl;
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.emotion.dto.request.SystemConfigUpdateRequest;
import com.emotion.dto.response.LoginConfigResponse;
import com.emotion.dto.response.SystemConfigResponse;
import com.emotion.entity.SystemConfig;
import com.emotion.mapper.SystemConfigMapper;
import com.emotion.service.SystemConfigService;
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 java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 系统配置服务实现类
*
* @author system
* @date 2026-06-27
*/
@Slf4j
@Service
public class SystemConfigServiceImpl extends ServiceImpl<SystemConfigMapper, SystemConfig> implements SystemConfigService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String CACHE_PREFIX = "system_config:";
private static final long CACHE_EXPIRE_HOURS = 24;
private static final String SMS_LOGIN_ENABLED_KEY = "sms_login_enabled";
@Override
public List<SystemConfigResponse> getVisibleConfigList() {
LambdaQueryWrapper<SystemConfig> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemConfig::getIsVisible, 1)
.orderByAsc(SystemConfig::getSortOrder);
List<SystemConfig> configs = list(wrapper);
return configs.stream().map(this::convertToResponse).collect(Collectors.toList());
}
@Override
public void batchUpdateConfigs(List<SystemConfigUpdateRequest> requests) {
for (SystemConfigUpdateRequest request : requests) {
LambdaUpdateWrapper<SystemConfig> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(SystemConfig::getConfigKey, request.getConfigKey())
.set(SystemConfig::getConfigValue, request.getConfigValue());
update(updateWrapper);
// 清除缓存
redisTemplate.delete(CACHE_PREFIX + request.getConfigKey());
log.info("更新系统配置: key={}, value={}", request.getConfigKey(), request.getConfigValue());
}
}
@Override
public String getConfigValue(String configKey) {
// 先查 Redis 缓存
String cacheKey = CACHE_PREFIX + configKey;
String cached = (String) redisTemplate.opsForValue().get(cacheKey);
if (cached != null) {
return cached;
}
// 查数据库
LambdaQueryWrapper<SystemConfig> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemConfig::getConfigKey, configKey);
SystemConfig config = getOne(wrapper);
if (config == null) {
return null;
}
// 写入缓存
redisTemplate.opsForValue().set(cacheKey, config.getConfigValue(), CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
return config.getConfigValue();
}
@Override
public LoginConfigResponse getLoginConfig() {
LoginConfigResponse response = new LoginConfigResponse();
response.setWechatLoginEnabled(true);
String smsEnabled = getConfigValue(SMS_LOGIN_ENABLED_KEY);
response.setSmsLoginEnabled("true".equalsIgnoreCase(smsEnabled));
return response;
}
/**
* 实体转响应对象
*/
private SystemConfigResponse convertToResponse(SystemConfig config) {
SystemConfigResponse response = new SystemConfigResponse();
response.setConfigKey(config.getConfigKey());
response.setConfigValue(config.getConfigValue());
response.setValueType(config.getValueType());
response.setConfigGroup(config.getConfigGroup());
response.setConfigName(config.getConfigName());
response.setDescription(config.getDescription());
response.setSortOrder(config.getSortOrder());
return response;
}
}