feat:新增系统配置模块(Entity/Mapper/DTO/Service/Controller)+ 登录配置公开接口
This commit is contained in:
@@ -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
|
"/actuator/**", // Actuator endpoints
|
||||||
"/admin/**", // 排除管理员路径,由管理员拦截器处理
|
"/admin/**", // 排除管理员路径,由管理员拦截器处理
|
||||||
"/auth/wechat/login", // WeChat mini program login endpoint
|
"/auth/wechat/login", // WeChat mini program login endpoint
|
||||||
|
"/auth/loginConfig", // 登录方式配置接口(免登录)
|
||||||
"/error" // Spring Boot error page
|
"/error" // Spring Boot error page
|
||||||
)
|
)
|
||||||
.order(2); // 优先级2
|
.order(2); // 优先级2
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ import com.emotion.dto.response.ResetPasswordResponse;
|
|||||||
|
|
||||||
import com.emotion.dto.response.AuthResponse;
|
import com.emotion.dto.response.AuthResponse;
|
||||||
import com.emotion.dto.response.CaptchaResponse;
|
import com.emotion.dto.response.CaptchaResponse;
|
||||||
|
import com.emotion.dto.response.LoginConfigResponse;
|
||||||
import com.emotion.dto.response.SmsCodeResponse;
|
import com.emotion.dto.response.SmsCodeResponse;
|
||||||
import com.emotion.dto.response.UserInfoResponse;
|
import com.emotion.dto.response.UserInfoResponse;
|
||||||
import com.emotion.service.AuthService;
|
import com.emotion.service.AuthService;
|
||||||
|
import com.emotion.service.SystemConfigService;
|
||||||
import com.emotion.service.TokenService;
|
import com.emotion.service.TokenService;
|
||||||
import com.emotion.util.UserContextUtils;
|
import com.emotion.util.UserContextUtils;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -41,6 +43,9 @@ public class AuthController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TokenService tokenService;
|
private TokenService tokenService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SystemConfigService systemConfigService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户登录(简化版:手机号+验证码,不存在则自动注册)
|
* 用户登录(简化版:手机号+验证码,不存在则自动注册)
|
||||||
*/
|
*/
|
||||||
@@ -61,6 +66,16 @@ public class AuthController {
|
|||||||
return Result.success("登录成功", response);
|
return Result.success("登录成功", response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取登录方式配置
|
||||||
|
*/
|
||||||
|
@GetMapping("/loginConfig")
|
||||||
|
@Operation(summary = "获取登录方式配置", description = "返回当前启用的登录方式,供小程序登录页动态渲染")
|
||||||
|
public Result<LoginConfigResponse> getLoginConfig() {
|
||||||
|
LoginConfigResponse response = systemConfigService.getLoginConfig();
|
||||||
|
return Result.success(response);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/register")
|
@PostMapping(value = "/register")
|
||||||
@Operation(summary = "用户注册", description = "使用手机号、密码和短信验证码进行注册")
|
@Operation(summary = "用户注册", description = "使用手机号、密码和短信验证码进行注册")
|
||||||
public Result<AuthResponse> register(@Valid @RequestBody RegisterRequest request) {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user