添加字典功能及初始化数据

This commit is contained in:
2025-12-22 21:56:10 +08:00
parent 180fe20347
commit 7d53a059d7
31 changed files with 1894 additions and 79 deletions
@@ -0,0 +1,105 @@
package com.emotion.controller;
import com.emotion.service.DictionaryService;
import com.emotion.dto.request.dictionary.DictionaryCreateRequest;
import com.emotion.dto.request.dictionary.DictionaryPageRequest;
import com.emotion.dto.request.dictionary.DictionaryUpdateRequest;
import com.emotion.dto.response.dictionary.DictionaryResponse;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 字典Controller
*
* @author huazhongmin
* @date 2025-12-22
*/
@RestController
@RequestMapping("/dictionary")
public class DictionaryController {
@Autowired
private DictionaryService dictionaryService;
/**
* 创建字典
*
* @param request 创建请求
* @return 创建结果
*/
@PostMapping
public Result<DictionaryResponse> createDictionary(@Validated @RequestBody DictionaryCreateRequest request) {
return dictionaryService.createDictionary(request);
}
/**
* 更新字典
*
* @param request 更新请求
* @return 更新结果
*/
@PutMapping
public Result<DictionaryResponse> updateDictionary(@Validated @RequestBody DictionaryUpdateRequest request) {
return dictionaryService.updateDictionary(request);
}
/**
* 删除字典
*
* @param id 字典ID
* @return 删除结果
*/
@DeleteMapping("/delete")
public Result<Void> deleteDictionary(@RequestParam String id) {
return dictionaryService.deleteDictionary(id);
}
/**
* 获取字典详情
*
* @param id 字典ID
* @return 字典详情
*/
@GetMapping("/detail")
public Result<DictionaryResponse> getDictionary(@RequestParam String id) {
return dictionaryService.getDictionary(id);
}
/**
* 分页查询字典
*
* @param request 分页请求
* @return 分页结果
*/
@GetMapping("/list")
public Result<PageResult<DictionaryResponse>> listDictionaries(DictionaryPageRequest request) {
return dictionaryService.listDictionaries(request);
}
/**
* 根据字典类型查询字典集合
*
* @param dictType 字典类型
* @return 字典集合
*/
@GetMapping("/byType")
public Result<List<DictionaryResponse>> getDictionariesByType(@RequestParam String dictType) {
return dictionaryService.getDictionariesByType(dictType);
}
/**
* 根据字典类型查询启用的字典集合
*
* @param dictType 字典类型
* @return 启用的字典集合
*/
@GetMapping("/enabledByType")
public Result<List<DictionaryResponse>> getEnabledDictionariesByType(@RequestParam String dictType) {
return dictionaryService.getEnabledDictionariesByType(dictType);
}
}
@@ -0,0 +1,54 @@
package com.emotion.dto.request.dictionary;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 创建字典请求
*
* @author huazhongmin
* @date 2025-12-22
*/
@Data
public class DictionaryCreateRequest {
/**
* 字典类型
*/
@NotBlank(message = "字典类型不能为空")
private String dictType;
/**
* 字典编码
*/
@NotBlank(message = "字典编码不能为空")
private String dictCode;
/**
* 字典名称
*/
@NotBlank(message = "字典名称不能为空")
private String dictName;
/**
* 字典值
*/
private String dictValue;
/**
* 排序顺序
*/
private Integer sortOrder;
/**
* 状态: 0-禁用, 1-启用
*/
@NotNull(message = "状态不能为空")
private Integer status;
/**
* 备注
*/
private String remarks;
}
@@ -0,0 +1,36 @@
package com.emotion.dto.request.dictionary;
import com.emotion.common.BasePageRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 字典分页请求
*
* @author huazhongmin
* @date 2025-12-22
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class DictionaryPageRequest extends BasePageRequest {
/**
* 字典类型
*/
private String dictType;
/**
* 字典编码
*/
private String dictCode;
/**
* 字典名称
*/
private String dictName;
/**
* 状态: 0-禁用, 1-启用
*/
private Integer status;
}
@@ -0,0 +1,60 @@
package com.emotion.dto.request.dictionary;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 更新字典请求
*
* @author huazhongmin
* @date 2025-12-22
*/
@Data
public class DictionaryUpdateRequest {
/**
* 字典ID
*/
@NotBlank(message = "字典ID不能为空")
private String id;
/**
* 字典类型
*/
@NotBlank(message = "字典类型不能为空")
private String dictType;
/**
* 字典编码
*/
@NotBlank(message = "字典编码不能为空")
private String dictCode;
/**
* 字典名称
*/
@NotBlank(message = "字典名称不能为空")
private String dictName;
/**
* 字典值
*/
private String dictValue;
/**
* 排序顺序
*/
private Integer sortOrder;
/**
* 状态: 0-禁用, 1-启用
*/
@NotNull(message = "状态不能为空")
private Integer status;
/**
* 备注
*/
private String remarks;
}
@@ -29,6 +29,11 @@ public class UserProfileCreateRequest {
*/
private String zodiac;
/**
* 职业
*/
private String profession;
/**
* MBTI人格类型
*/
@@ -34,6 +34,11 @@ public class UserProfileUpdateRequest {
*/
private String zodiac;
/**
* 职业
*/
private String profession;
/**
* MBTI人格类型
*/
@@ -0,0 +1,61 @@
package com.emotion.dto.response.dictionary;
import lombok.Data;
import com.emotion.dto.response.BaseResponse;
import lombok.EqualsAndHashCode;
/**
* 字典响应
*
* @author huazhongmin
* @date 2025-12-22
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class DictionaryResponse extends BaseResponse {
/**
* 字典类型
*/
private String dictType;
/**
* 字典编码
*/
private String dictCode;
/**
* 字典名称
*/
private String dictName;
/**
* 字典值
*/
private String dictValue;
/**
* 排序顺序
*/
private Integer sortOrder;
/**
* 状态: 0-禁用, 1-启用
*/
private Integer status;
/**
* 创建人ID
*/
private String createBy;
/**
* 更新人ID
*/
private String updateBy;
/**
* 备注
*/
private String remarks;
}
@@ -46,6 +46,11 @@ public class UserProfileResponse {
*/
private String zodiac;
/**
* 职业
*/
private String profession;
/**
* MBTI人格类型
*/
@@ -0,0 +1,61 @@
package com.emotion.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.emotion.common.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* 字典实体类
*
* @author huazhongmin
* @date 2025-12-22
*/
@Data
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_dictionary")
public class Dictionary extends BaseEntity {
/**
* 字典类型 (如: city, constellation, mbti)
*/
@TableField("dict_type")
private String dictType;
/**
* 字典编码
*/
@TableField("dict_code")
private String dictCode;
/**
* 字典名称
*/
@TableField("dict_name")
private String dictName;
/**
* 字典值
*/
@TableField("dict_value")
private String dictValue;
/**
* 排序顺序
*/
@TableField("sort_order")
private Integer sortOrder;
/**
* 状态: 0-禁用, 1-启用
*/
@TableField("status")
private Integer status;
}
@@ -49,6 +49,12 @@ public class UserProfile extends BaseEntity {
@TableField("zodiac")
private String zodiac;
/**
* 职业
*/
@TableField("profession")
private String profession;
/**
* MBTI人格类型
*/
@@ -0,0 +1,32 @@
package com.emotion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.emotion.entity.Dictionary;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 字典Mapper接口
*
* @author huazhongmin
* @date 2025-12-22
*/
public interface DictionaryMapper extends BaseMapper<Dictionary> {
/**
* 根据字典类型查询字典集合
*
* @param dictType 字典类型
* @return 字典集合
*/
List<Dictionary> selectByDictType(@Param("dictType") String dictType);
/**
* 根据字典类型和状态查询字典集合
*
* @param dictType 字典类型
* @param status 状态
* @return 字典集合
*/
List<Dictionary> selectByDictTypeAndStatus(@Param("dictType") String dictType, @Param("status") Integer status);
}
@@ -0,0 +1,77 @@
package com.emotion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.emotion.entity.Dictionary;
import com.emotion.dto.request.dictionary.DictionaryCreateRequest;
import com.emotion.dto.request.dictionary.DictionaryPageRequest;
import com.emotion.dto.request.dictionary.DictionaryUpdateRequest;
import com.emotion.dto.response.dictionary.DictionaryResponse;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import java.util.List;
/**
* 字典Service接口
*
* @author huazhongmin
* @date 2025-12-22
*/
public interface DictionaryService extends IService<Dictionary> {
/**
* 创建字典
*
* @param request 创建请求
* @return 创建结果
*/
Result<DictionaryResponse> createDictionary(DictionaryCreateRequest request);
/**
* 更新字典
*
* @param request 更新请求
* @return 更新结果
*/
Result<DictionaryResponse> updateDictionary(DictionaryUpdateRequest request);
/**
* 删除字典
*
* @param id 字典ID
* @return 删除结果
*/
Result<Void> deleteDictionary(String id);
/**
* 获取字典详情
*
* @param id 字典ID
* @return 字典详情
*/
Result<DictionaryResponse> getDictionary(String id);
/**
* 分页查询字典
*
* @param request 分页请求
* @return 分页结果
*/
Result<PageResult<DictionaryResponse>> listDictionaries(DictionaryPageRequest request);
/**
* 根据字典类型查询字典集合
*
* @param dictType 字典类型
* @return 字典集合
*/
Result<List<DictionaryResponse>> getDictionariesByType(String dictType);
/**
* 根据字典类型查询启用的字典集合
*
* @param dictType 字典类型
* @return 启用的字典集合
*/
Result<List<DictionaryResponse>> getEnabledDictionariesByType(String dictType);
}
@@ -0,0 +1,266 @@
package com.emotion.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.entity.Dictionary;
import com.emotion.mapper.DictionaryMapper;
import com.emotion.service.DictionaryService;
import com.emotion.dto.request.dictionary.DictionaryCreateRequest;
import com.emotion.dto.request.dictionary.DictionaryPageRequest;
import com.emotion.dto.request.dictionary.DictionaryUpdateRequest;
import com.emotion.dto.response.dictionary.DictionaryResponse;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* 字典Service实现类
*
* @author huazhongmin
* @date 2025-12-22
*/
@Service
public class DictionaryServiceImpl extends ServiceImpl<DictionaryMapper, Dictionary> implements DictionaryService {
/**
* 创建字典
*
* @param request 创建请求
* @return 创建结果
*/
@Override
public Result<DictionaryResponse> createDictionary(DictionaryCreateRequest request) {
// 检查字典类型+字典编码是否已存在
LambdaQueryWrapper<Dictionary> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Dictionary::getDictType, request.getDictType())
.eq(Dictionary::getDictCode, request.getDictCode())
.eq(Dictionary::getIsDeleted, 0);
if (this.count(queryWrapper) > 0) {
return Result.error(400, "同一字典类型下字典编码已存在");
}
// 创建字典实体
Dictionary dictionary = new Dictionary();
BeanUtils.copyProperties(request, dictionary);
dictionary.setSortOrder(request.getSortOrder() != null ? request.getSortOrder() : 0);
// 保存字典
if (this.save(dictionary)) {
DictionaryResponse response = convertToResponse(dictionary);
return Result.success(response);
}
return Result.error(500, "创建字典失败");
}
/**
* 更新字典
*
* @param request 更新请求
* @return 更新结果
*/
@Override
public Result<DictionaryResponse> updateDictionary(DictionaryUpdateRequest request) {
// 检查字典是否存在
Dictionary dictionary = this.getById(request.getId());
if (dictionary == null || dictionary.getIsDeleted() == 1) {
return Result.error(400, "字典不存在");
}
// 检查字典类型+字典编码是否已存在(排除当前字典)
LambdaQueryWrapper<Dictionary> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Dictionary::getDictType, request.getDictType())
.eq(Dictionary::getDictCode, request.getDictCode())
.ne(Dictionary::getId, request.getId())
.eq(Dictionary::getIsDeleted, 0);
if (this.count(queryWrapper) > 0) {
return Result.error(400, "同一字典类型下字典编码已存在");
}
// 更新字典实体
BeanUtils.copyProperties(request, dictionary);
// 保存更新
if (this.updateById(dictionary)) {
DictionaryResponse response = convertToResponse(dictionary);
return Result.success(response);
}
return Result.error(500, "更新字典失败");
}
/**
* 删除字典
*
* @param id 字典ID
* @return 删除结果
*/
@Override
public Result<Void> deleteDictionary(String id) {
// 检查字典是否存在
Dictionary dictionary = this.getById(id);
if (dictionary == null || dictionary.getIsDeleted() == 1) {
return Result.error(400, "字典不存在");
}
// 删除字典(逻辑删除)
if (this.removeById(id)) {
return Result.success();
}
return Result.error(500, "删除字典失败");
}
/**
* 获取字典详情
*
* @param id 字典ID
* @return 字典详情
*/
@Override
public Result<DictionaryResponse> getDictionary(String id) {
// 获取字典
Dictionary dictionary = this.getById(id);
if (dictionary == null || dictionary.getIsDeleted() == 1) {
return Result.error(400, "字典不存在");
}
// 转换为响应对象
DictionaryResponse response = convertToResponse(dictionary);
return Result.success(response);
}
/**
* 分页查询字典
*
* @param request 分页请求
* @return 分页结果
*/
@Override
public Result<PageResult<DictionaryResponse>> listDictionaries(DictionaryPageRequest request) {
// 构建查询条件
LambdaQueryWrapper<Dictionary> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Dictionary::getIsDeleted, 0);
// 添加查询条件
if (request.getDictType() != null && !request.getDictType().isEmpty()) {
queryWrapper.eq(Dictionary::getDictType, request.getDictType());
}
if (request.getDictCode() != null && !request.getDictCode().isEmpty()) {
queryWrapper.like(Dictionary::getDictCode, request.getDictCode());
}
if (request.getDictName() != null && !request.getDictName().isEmpty()) {
queryWrapper.like(Dictionary::getDictName, request.getDictName());
}
if (request.getStatus() != null) {
queryWrapper.eq(Dictionary::getStatus, request.getStatus());
}
// 排序
queryWrapper.orderByAsc(Dictionary::getDictType).orderByAsc(Dictionary::getSortOrder).orderByAsc(Dictionary::getCreateTime);
// 分页查询
Page<Dictionary> page = this.page(new Page<>(request.getCurrent(), request.getSize()), queryWrapper);
// 转换为响应对象
List<DictionaryResponse> responseList = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
// 构建分页结果
PageResult<DictionaryResponse> pageResult = new PageResult<>();
pageResult.setRecords(responseList);
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
return Result.success(pageResult);
}
/**
* 根据字典类型查询字典集合
*
* @param dictType 字典类型
* @return 字典集合
*/
@Override
public Result<List<DictionaryResponse>> getDictionariesByType(String dictType) {
// 构建查询条件
LambdaQueryWrapper<Dictionary> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Dictionary::getDictType, dictType)
.eq(Dictionary::getIsDeleted, 0)
.orderByAsc(Dictionary::getSortOrder)
.orderByAsc(Dictionary::getCreateTime);
// 查询字典集合
List<Dictionary> dictionaryList = this.list(queryWrapper);
// 转换为响应对象
List<DictionaryResponse> responseList = dictionaryList.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
return Result.success(responseList);
}
/**
* 根据字典类型查询启用的字典集合
*
* @param dictType 字典类型
* @return 启用的字典集合
*/
@Override
public Result<List<DictionaryResponse>> getEnabledDictionariesByType(String dictType) {
// 构建查询条件
LambdaQueryWrapper<Dictionary> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Dictionary::getDictType, dictType)
.eq(Dictionary::getStatus, 1)
.eq(Dictionary::getIsDeleted, 0)
.orderByAsc(Dictionary::getSortOrder)
.orderByAsc(Dictionary::getCreateTime);
// 查询字典集合
List<Dictionary> dictionaryList = this.list(queryWrapper);
// 转换为响应对象
List<DictionaryResponse> responseList = dictionaryList.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
return Result.success(responseList);
}
/**
* 实体转换为响应对象
*
* @param dictionary 字典实体
* @return 字典响应对象
*/
private DictionaryResponse convertToResponse(Dictionary dictionary) {
DictionaryResponse response = new DictionaryResponse();
// 基础字段映射
response.setId(dictionary.getId());
response.setDictType(dictionary.getDictType());
response.setDictCode(dictionary.getDictCode());
response.setDictName(dictionary.getDictName());
response.setDictValue(dictionary.getDictValue());
response.setSortOrder(dictionary.getSortOrder());
response.setStatus(dictionary.getStatus());
response.setCreateBy(dictionary.getCreateBy());
response.setUpdateBy(dictionary.getUpdateBy());
response.setRemarks(dictionary.getRemarks());
// 转换时间类型
if (dictionary.getCreateTime() != null) {
response.setCreateTime(dictionary.getCreateTime().toString());
}
if (dictionary.getUpdateTime() != null) {
response.setUpdateTime(dictionary.getUpdateTime().toString());
}
return response;
}
}
@@ -71,21 +71,37 @@ public class UserProfileServiceImpl extends ServiceImpl<UserProfileMapper, UserP
public UserProfileResponse updateProfile(UserProfileUpdateRequest request) {
log.info("Updating user profile: {}", request);
UserProfile userProfile = getById(request.getId());
if (userProfile == null) {
throw new RuntimeException("档案不存在");
}
// 权限校验:只能修改自己的档案
// 获取当前登录用户ID
String currentUserId = UserContextHolder.getCurrentUserId();
if (!StringUtils.hasText(currentUserId)) {
throw new RuntimeException("用户未登录");
}
UserProfile userProfile = null;
// 先根据请求ID查询
if (StringUtils.hasText(request.getId())) {
userProfile = getById(request.getId());
}
// 如果没有查到,根据当前用户ID查询
if (userProfile == null) {
LambdaQueryWrapper<UserProfile> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserProfile::getUserId, currentUserId);
userProfile = getOne(queryWrapper);
}
// 如果还是没有,则创建新档案
if (userProfile == null) {
log.info("User profile not found, creating new profile for user: {}", currentUserId);
UserProfileCreateRequest createRequest = new UserProfileCreateRequest();
BeanUtils.copyProperties(request, createRequest);
return createProfile(createRequest);
}
// 权限校验:只能修改自己的档案
if (!userProfile.getUserId().equals(currentUserId)) {
// 管理员可以修改任意档案 (此处假设没有管理员逻辑,严格按需求: 只能修改自己的)
// 如果需要管理员权限,需配合 SecurityUtils 判断角色
// throw new RuntimeException("无权修改他人档案");
// 暂时允许用户修改自己的档案
throw new RuntimeException("无权修改他人档案");
}
// 使用Hutool的BeanUtil进行部分更新,忽略null值