feat(controller): 新增字典管理REST API接口

- 新增SysDictTypeController字典类型管理接口
- 新增SysDictDataController字典数据管理接口
- 提供完整的CRUD操作API
- 支持分页查询和条件搜索
- 集成Sa-Token权限验证和操作日志
- 添加Swagger文档注解
This commit is contained in:
Leo 2025-09-26 16:36:44 +08:00
parent f887d73063
commit 1dc2300763
2 changed files with 473 additions and 0 deletions

View File

@ -0,0 +1,239 @@
package org.leocoder.thin.system.controller.dictdata;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.leocoder.thin.common.constants.CoderCacheConstants;
import org.leocoder.thin.common.constants.CoderConstants;
import org.leocoder.thin.common.exception.coder.YUtil;
import org.leocoder.thin.common.satoken.CoderLoginUtil;
import org.leocoder.thin.common.utils.cache.RedisUtil;
import org.leocoder.thin.domain.enums.oper.OperType;
import org.leocoder.thin.domain.model.vo.system.SysDictDataVo;
import org.leocoder.thin.domain.pojo.system.SysDictData;
import org.leocoder.thin.operlog.annotation.OperLog;
import org.leocoder.thin.system.service.dictdata.SysDictDataService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.List;
/**
* @author Leocoder
* @description [字典数据表-控制层]
*/
@Tag(name = "字典数据管理", description = "系统字典数据的增删改查操作")
@Validated
@RequestMapping("/coder")
@RequiredArgsConstructor
@RestController
public class SysDictDataController {
private final SysDictDataService sysDictDataService;
private final RedisUtil redisUtil;
/**
* @description [分页查询]
* @author Leocoder
*/
@Operation(summary = "分页查询字典数据列表", description = "根据查询条件分页获取字典数据信息")
@SaCheckPermission("system:dict:list")
@GetMapping("/sysDictData/listPage")
public IPage<SysDictData> listPage(SysDictDataVo vo) {
// 分页构造器
Page<SysDictData> page = new Page<>(vo.getPageNo(), vo.getPageSize());
// 条件构造器
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.isNotBlank(vo.getDictType()), SysDictData::getDictType, vo.getDictType());
wrapper.like(StringUtils.isNotBlank(vo.getDictLabel()), SysDictData::getDictLabel, vo.getDictLabel());
wrapper.eq(StringUtils.isNotBlank(vo.getDictStatus()), SysDictData::getDictStatus, vo.getDictStatus());
wrapper.orderByDesc(SysDictData::getDictType);
wrapper.orderByAsc(SysDictData::getSorted);
// 进行分页查询
page = sysDictDataService.page(page, wrapper);
return page;
}
/**
* @description [查询所有]
* @author Leocoder
*/
@Operation(summary = "查询所有字典数据", description = "获取所有字典数据信息")
@SaCheckPermission("system:dict:list")
@GetMapping("/sysDictData/list")
public List<SysDictData> list() {
return sysDictDataService.list();
}
/**
* @description [根据主键进行查询]
* @author Leocoder
*/
@Operation(summary = "根据ID查询字典数据", description = "通过ID获取字典数据详细信息")
@GetMapping("/sysDictData/getById/{id}")
public SysDictData getById(@PathVariable Long id) {
return sysDictDataService.getById(id);
}
/**
* @description [新增]
* @author Leocoder
*/
@Operation(summary = "新增字典数据", description = "创建新的字典数据")
@SaCheckPermission("system:dict:add")
@PostMapping("/sysDictData/add")
@OperLog(value = "新增字典数据", operType = OperType.INSERT)
public void add(@Validated @RequestBody SysDictData sysDictData) {
// 查询是否已经存在字典名称
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysDictData::getDictLabel, sysDictData.getDictLabel());
wrapper.eq(SysDictData::getDictType, sysDictData.getDictType());
long count = sysDictDataService.count(wrapper);
YUtil.isTrue(count > 0, "该字典名称已存在,请重新输入");
if (StringUtils.isNotBlank(CoderLoginUtil.getUserName())) {
sysDictData.setCreateBy(CoderLoginUtil.getUserName());
}
YUtil.isTrue(!sysDictDataService.save(sysDictData), "新增失败,请稍后重试");
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [获取最新排序]
* @author Leocoder
*/
@Operation(summary = "获取最新排序", description = "根据字典类型获取最新的排序号")
@GetMapping("/sysDictData/getSorted/{dictType}")
public int getSorted(@PathVariable("dictType") String dictType) {
YUtil.isTrue(StringUtils.isBlank(dictType), "请传递参数");
LambdaQueryWrapper<SysDictData> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.select(SysDictData::getSorted);
lambdaQueryWrapper.eq(SysDictData::getDictType, dictType);
lambdaQueryWrapper.orderByDesc(SysDictData::getSorted);
lambdaQueryWrapper.last("LIMIT 1");
SysDictData sysDictData = sysDictDataService.getOne(lambdaQueryWrapper);
if (ObjectUtils.isEmpty(sysDictData)) return CoderConstants.ONE_NUMBER;
return sysDictData.getSorted() != null ? sysDictData.getSorted() + CoderConstants.ONE_NUMBER : CoderConstants.ONE_NUMBER;
}
/**
* @description [修改]
* @author Leocoder
*/
@Operation(summary = "修改字典数据", description = "更新字典数据信息")
@SaCheckPermission("system:dict:update")
@PostMapping("/sysDictData/update")
@OperLog(value = "修改字典数据", operType = OperType.UPDATE)
public void update(@Validated @RequestBody SysDictData sysDictData) {
// 查询是否已经存在字典名称
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysDictData::getDictLabel, sysDictData.getDictLabel());
wrapper.eq(SysDictData::getDictType, sysDictData.getDictType());
SysDictData dictData = sysDictDataService.getOne(wrapper);
YUtil.isTrue(ObjectUtils.isNotEmpty(dictData) && !dictData.getDictId().equals(sysDictData.getDictId()), "该字典名称已存在,请重新输入");
if (StringUtils.isNotBlank(CoderLoginUtil.getUserName())) {
sysDictData.setUpdateBy(CoderLoginUtil.getUserName());
}
YUtil.isTrue(!sysDictDataService.updateById(sysDictData), "修改失败,请稍后重试");
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [删除]
* @author Leocoder
*/
@Operation(summary = "删除字典数据", description = "根据ID删除字典数据")
@SaCheckPermission("system:dict:delete")
@PostMapping("/sysDictData/deleteById/{id}")
@OperLog(value = "删除字典数据", operType = OperType.DELETE)
public void delete(@PathVariable Long id) {
YUtil.isTrue(!sysDictDataService.removeById(id), "删除失败,请稍后重试");
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [批量删除]
* @author Leocoder
*/
@Operation(summary = "批量删除字典数据", description = "根据ID列表批量删除字典数据")
@SaCheckPermission("system:dict:delete")
@PostMapping("/sysDictData/batchDelete")
@OperLog(value = "批量删除字典数据", operType = OperType.DELETE)
public void batchDelete(@NotNull(message = "请选择需要删除的数据") @RequestBody List<Long> ids) {
YUtil.isTrue(!sysDictDataService.removeBatchByIds(ids), "批量删除失败,请稍后重试");
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [修改状态]
* @author Leocoder
*/
@Operation(summary = "修改字典数据状态", description = "启用或停用字典数据")
@SaCheckPermission("system:dict:update")
@PostMapping("/sysDictData/updateStatus/{dictId}/{dictStatus}")
@OperLog(value = "修改字典数据状态", operType = OperType.UPDATE)
public void updateStatus(@PathVariable("dictId") Long dictId, @PathVariable("dictStatus") String dictStatus) {
UpdateWrapper<SysDictData> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("dict_status", dictStatus).eq("dict_id", dictId);
YUtil.isTrue(!sysDictDataService.update(updateWrapper), "修改失败,请稍后重试");
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [根据类型查询字典数据]
* @author Leocoder
*/
@Operation(summary = "根据类型查询字典数据", description = "通过字典类型获取对应的字典数据列表")
@GetMapping("/sysDictData/listDataByType/{dictType}")
public List<SysDictData> listDataByType(@PathVariable("dictType") String dictType) {
Boolean isExist = redisUtil.hasKey(CoderCacheConstants.DICT_REDIS_KEY + dictType);
if (!isExist) {
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
// 查询指定字段
wrapper.select(SysDictData::getDictLabel, SysDictData::getDictValue, SysDictData::getDictType, SysDictData::getDictTag, SysDictData::getDictColor);
wrapper.eq(StringUtils.isNotBlank(dictType), SysDictData::getDictType, dictType);
wrapper.eq(SysDictData::getDictStatus, CoderConstants.ZERO_STRING);
List<SysDictData> dictDataList = sysDictDataService.list(wrapper);
if (CollectionUtils.isNotEmpty(dictDataList)) {
return dictDataList;
} else {
return Collections.emptyList();
}
} else {
List<SysDictData> redisDictData = redisUtil.getKey(CoderCacheConstants.DICT_REDIS_KEY + dictType);
if (CollectionUtils.isNotEmpty(redisDictData)) {
return redisDictData;
} else {
return Collections.emptyList();
}
}
}
/**
* @description [字典数据同步Redis进行缓存]
* @author Leocoder
*/
@Operation(summary = "同步字典缓存", description = "手动同步所有字典数据到Redis缓存")
@SaCheckPermission("system:dict:update")
@GetMapping("/sysDictData/listDictCacheRedis")
@OperLog(value = "字典数据同步缓存", operType = OperType.UPDATE)
public void listDictCacheRedis() {
sysDictDataService.listDictCacheRedis();
}
}

View File

@ -0,0 +1,234 @@
package org.leocoder.thin.system.controller.dicttype;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.leocoder.thin.common.constants.CoderCacheConstants;
import org.leocoder.thin.common.constants.CoderConstants;
import org.leocoder.thin.common.exception.coder.YUtil;
import org.leocoder.thin.common.satoken.CoderLoginUtil;
import org.leocoder.thin.common.utils.cache.RedisUtil;
import org.leocoder.thin.domain.enums.oper.OperType;
import org.leocoder.thin.domain.model.vo.system.SysDictTypeVo;
import org.leocoder.thin.domain.pojo.system.SysDictData;
import org.leocoder.thin.domain.pojo.system.SysDictType;
import org.leocoder.thin.operlog.annotation.OperLog;
import org.leocoder.thin.system.service.dictdata.SysDictDataService;
import org.leocoder.thin.system.service.dicttype.SysDictTypeService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.List;
/**
* @author Leocoder
* @description [字典类型表-控制层]
*/
@Tag(name = "字典类型管理", description = "系统字典类型的增删改查操作")
@Validated
@RequestMapping("/coder")
@RequiredArgsConstructor
@RestController
public class SysDictTypeController {
private final SysDictTypeService sysDictTypeService;
private final SysDictDataService sysDictDataService;
private final RedisUtil redisUtil;
/**
* @description [分页查询]
* @author Leocoder
*/
@Operation(summary = "分页查询字典类型列表", description = "根据查询条件分页获取字典类型信息")
@SaCheckPermission("system:dict:list")
@GetMapping("/sysDictType/listPage")
public IPage<SysDictType> listPage(SysDictTypeVo vo) {
// 分页构造器
Page<SysDictType> page = new Page<>(vo.getPageNo(), vo.getPageSize());
// 条件构造器
LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(vo.getDictName()), SysDictType::getDictName, vo.getDictName());
wrapper.like(StringUtils.isNotBlank(vo.getDictType()), SysDictType::getDictType, vo.getDictType());
wrapper.eq(StringUtils.isNotBlank(vo.getDictStatus()), SysDictType::getDictStatus, vo.getDictStatus());
wrapper.orderByDesc(SysDictType::getCreateTime);
// 进行分页查询
page = sysDictTypeService.page(page, wrapper);
return page;
}
/**
* @description [查询所有]
* @author Leocoder
*/
@Operation(summary = "查询所有字典类型", description = "获取所有字典类型信息")
@SaCheckPermission("system:dict:list")
@GetMapping("/sysDictType/list")
public List<SysDictType> list() {
return sysDictTypeService.list();
}
/**
* @description [根据主键查询]
* @author Leocoder
*/
@Operation(summary = "根据ID查询字典类型", description = "通过ID获取字典类型详细信息")
@GetMapping("/sysDictType/getById/{id}")
public SysDictType getById(@PathVariable Long id) {
return sysDictTypeService.getById(id);
}
/**
* @description [新增]
* @author Leocoder
*/
@Operation(summary = "新增字典类型", description = "创建新的字典类型")
@SaCheckPermission("system:dict:add")
@PostMapping("/sysDictType/add")
@OperLog(value = "新增字典类型", operType = OperType.INSERT)
public void add(@Validated @RequestBody SysDictType sysDictType) {
// 查询是否已经存在字典名称
LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysDictType::getDictType, sysDictType.getDictType());
long count = sysDictTypeService.count(wrapper);
YUtil.isTrue(count > 0, "该字典类型已存在,请重新输入");
if (StringUtils.isNotBlank(CoderLoginUtil.getUserName())) {
sysDictType.setCreateBy(CoderLoginUtil.getUserName());
}
YUtil.isTrue(!sysDictTypeService.save(sysDictType), "新增失败,请稍后重试");
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [修改]
* @author Leocoder
*/
@Operation(summary = "修改字典类型", description = "更新字典类型信息")
@SaCheckPermission("system:dict:update")
@PostMapping("/sysDictType/update")
@OperLog(value = "修改字典类型", operType = OperType.UPDATE)
public void update(@Validated @RequestBody SysDictType sysDictType) {
// 根据ID进行查询用来同步修改字典数据类型
SysDictType sysDictTypeModel = sysDictTypeService.getById(sysDictType.getDictId());
// 查询是否已经存在字典名称
LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysDictType::getDictType, sysDictType.getDictType());
SysDictType dictType = sysDictTypeService.getOne(wrapper);
YUtil.isTrue(ObjectUtils.isNotEmpty(dictType) && !dictType.getDictId().equals(sysDictType.getDictId()), "该字典类型已存在,请重新输入");
if (StringUtils.isNotBlank(CoderLoginUtil.getUserName())) {
sysDictType.setUpdateBy(CoderLoginUtil.getUserName());
}
YUtil.isTrue(!sysDictTypeService.updateById(sysDictType), "修改失败,请稍后重试");
if(!sysDictTypeModel.getDictType().equals(sysDictType.getDictType())) {
// 将字典数据的类型也同步修改
LambdaUpdateWrapper<SysDictData> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(SysDictData::getDictType, sysDictType.getDictType());
updateWrapper.eq(SysDictData::getDictType, sysDictTypeModel.getDictType());
sysDictDataService.update(updateWrapper);
}
// 先删除该缓存
redisUtil.deleteKey(CoderCacheConstants.DICT_REDIS_KEY + sysDictTypeModel.getDictType());
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [删除]
* @author Leocoder
*/
@Operation(summary = "删除字典类型", description = "根据ID删除字典类型及其关联的字典数据")
@SaCheckPermission("system:dict:delete")
@Transactional(rollbackFor = Exception.class)
@PostMapping("/sysDictType/deleteById/{id}")
@OperLog(value = "删除字典类型", operType = OperType.DELETE)
public void delete(@PathVariable("id") Long id) {
SysDictType sysDictType = sysDictTypeService.getById(id);
YUtil.isTrue(ObjectUtils.isEmpty(sysDictType) || StringUtils.isBlank(sysDictType.getDictType()), "请检查该数据是否存在");
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysDictData::getDictType, sysDictType.getDictType());
// 删除字典详情
sysDictDataService.remove(wrapper);
YUtil.isTrue(!sysDictTypeService.removeById(id), "删除失败,请稍后重试");
// 删除缓存
redisUtil.deleteKey(CoderCacheConstants.DICT_REDIS_KEY + sysDictType.getDictType());
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [批量删除]
* @author Leocoder
*/
@Operation(summary = "批量删除字典类型", description = "根据ID列表批量删除字典类型")
@SaCheckPermission("system:dict:delete")
@Transactional(rollbackFor = Exception.class)
@PostMapping("/sysDictType/batchDelete")
@OperLog(value = "批量删除字典类型", operType = OperType.DELETE)
public void batchDelete(@NotNull(message = "请选择需要删除的数据") @RequestBody List<Long> ids) {
if (CollectionUtil.isNotEmpty(ids)) {
for (Long id : ids) {
SysDictType sysDictType = sysDictTypeService.getById(id);
YUtil.isTrue(ObjectUtils.isEmpty(sysDictType) || StringUtils.isBlank(sysDictType.getDictType()), "请检查该数据是否存在");
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysDictData::getDictType, sysDictType.getDictType());
YUtil.isTrue(!sysDictDataService.remove(wrapper), "删除失败,请稍后重试");
// 删除缓存
redisUtil.deleteKey(CoderCacheConstants.DICT_REDIS_KEY + sysDictType.getDictType());
}
}
YUtil.isTrue(!sysDictTypeService.removeBatchByIds(ids), "批量删除失败,请稍后重试");
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [修改状态]
* @author Leocoder
*/
@Operation(summary = "修改字典类型状态", description = "启用或停用字典类型")
@SaCheckPermission("system:dict:update")
@PostMapping("/sysDictType/updateStatus/{dictId}/{dictStatus}")
@OperLog(value = "修改字典类型状态", operType = OperType.UPDATE)
public void updateStatus(@PathVariable("dictId") Long dictId, @PathVariable("dictStatus") String dictStatus) {
UpdateWrapper<SysDictType> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("dict_status", dictStatus).eq("dict_id", dictId);
YUtil.isTrue(!sysDictTypeService.update(updateWrapper), "修改失败,请稍后重试");
// 同步缓存
sysDictDataService.listDictCacheRedis();
}
/**
* @description [查询字典类型下拉框]
* @author Leocoder
*/
@Operation(summary = "查询字典类型下拉框", description = "获取启用状态的字典类型列表,用于下拉选择")
@GetMapping("/sysDictType/listDictType")
public List<SysDictType> listDictType() {
LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
// 按需加载
wrapper.select(SysDictType::getDictType, SysDictType::getDictName);
wrapper.eq(SysDictType::getDictStatus, CoderConstants.ZERO_STRING);
List<SysDictType> dictTypeList = sysDictTypeService.list(wrapper);
if (CollectionUtils.isNotEmpty(dictTypeList)) {
return dictTypeList;
} else {
return Collections.emptyList();
}
}
}