数据字典中的业务字典表

40 阅读3分钟

数据字典

业务字典表的作用即,我们需要为用户展示一些重复性的数据时,一般要在数据库里建一张字典表(通过软连接的方式关联其他表),为了方便前端使用(如渲染下拉框),通常需要将数据封装成列表,每个元素包含 Code 和 Name。

后端一般是通过前端传回的类别名,去数据库中,查询这一类别所有的字典,封装好之后传回给前端。

核心目标

根据前端传递的字典类别名pcodes),从数据库查询所有相关的字典项,并将其封装成结构化的 Vo (Value Object) 列表返回给前端。每个字典项包含一个实际值 (Code) 和一个展示名 (Name)。

数据库结构

字典数据通过以下三个核心字段在数据库中记录:

  • P_CODE:字典的类别(如 CAR_LEVEL)。
  • DICT_CODE:字典项的编号/实际值(如 1)。
  • DICT_NAME:字典项的展示名(如 轿车)。

💻 后端实现逻辑

整个流程通过 ControllerServiceMapper 三层实现:

  1. Controller 层 (getDictRedis) :

    • 接收前端请求,通过 @RequestParam 获取需要查询的字典类别列表 pcodes
    • 调用 Service 层方法进行处理。
  2. Service 层 (queryDictsByPcodes) : 核心封装逻辑

    • 查询数据库: 使用 QueryWrapper(如 MyBatis Plus)根据传入的 pcodes 查询所有有效的 (IS_EFFECTIVE="1") 字典数据 (PDict 实体),并按 sort 字段排序。

    • 数据分组 (Map 转换) : 利用 Java Stream API 的 Collectors.groupingBy(PDict::getPCode) 将查询结果 List<PDict> 转换为 Map<String, List<PDict>>,其中 String 是字典类别名 (P_CODE)。

    • Vo 封装: 遍历该 Map,将每个分组转换成前端所需的 DictGroupVo 对象。

      • 外层 DictGroupVo 设置类别名 (pCode)。
      • 内层列表 List<DictItemVo>PDict 对象的 DICT_CODEDICT_NAME 映射为 DictItemVo
    • 返回封装好的 List<DictGroupVo> 给 Controller。

  3. Mapper 层 (PDictMapper) :

    • 继承 BaseMapper<PDict>,提供了基本的 CURD 操作来支持 Service 层的数据库查询。

service层中实现逻辑:通过字典类别名去查询数据库,然后将查询到的数据转换成Map集合,再将Map转换成Vo传输给前端

具体的代码示例

controller层

@GetMapping("/v1/dict-redis")//前端的请求路径
public AjaxResult<List<DictGroupVo>> getDictRedis
(@RequestParam("pcodes") List<String> pcodes){ //前端传回需要字典类别
    List<DictGroupVo> list = dictService.queryDictsByPcodes(pcodes);
    return AjaxResult.success(list);
}

service层

//接口
List<DictGroupVo> queryDictsByPcodes (List<String> pcodes);
```
//实现
@Override
public List<DictGroupVo> queryDictsByPcodes(List<String> pcodes) {

    if (pcodes == null || pcodes.isEmpty()){
        return new ArrayList<>();
    }

    //1.查询数据库 使用QueryWrapper方便快速的查询
    QueryWrapper<PDict> query = new QueryWrapper<>();
    query.in("P_CODE",pcodes)
            .eq("IS_EFFECTIVE","1")
            .orderByAsc("sort");
    List<PDict> allDicts = this.list(query);

    //2.通过Map,存入allDicts的数据
    Map<String,List<PDict>> groupMap = allDicts.stream()
            .collect(Collectors.groupingBy(PDict::getPCode));```//因为数据库的字段是和PDict对应的
```

    //3.将map转换为前端需要的Vo对象
    List<DictGroupVo> result = new ArrayList<>();

    //循环遍历组装数据
    groupMap.forEach((pCode,dictList) ->{
        DictGroupVo dictGroupVo = new DictGroupVo();
        //设置外层分类类别名pCode
        dictGroupVo.setDictCode(pCode);

        //转换内层列表
        List<DictItemVo> itemList = dictList.stream().map(d -> {
            //这里的d就是Map<String,List<PDict>>中PDict的别名
            DictItemVo dictItemVo = new DictItemVo();
            dictItemVo.setDictCode(d.getDictCode());
            dictItemVo.setDictName(d.getDictName());
            return dictItemVo;
        }).collect(Collectors.toList());
        
        //组装好一条数据
        dictGroupVo.setList(itemList);
        //存入list中
        result.add(dictGroupVo);
    });

    return  result;//返回封装好的Vo给前端
}
```

Mapper层

@Mapper
public interface PDictMapper extends BaseMapper<PDict> {
    //直接继承BaseMapper就好了,里面有写好的方法
}

Entity

@Data
@EqualsAndHashCode(callSuper = true)
@TableName("p_dict")
public class PDict extends BaseEntity {

    private static final long serialVersionUID = 1L;
    @TableField("P_CODE")
    private String pCode;

    // 对应 dict_code (具体值,如 1)
    @TableField("DICT_CODE")
    private String dictCode;

    // 对应 dict_name (显示名,如 轿车)
    @TableField("DICT_NAME")
    private String dictName;

    // 排序
    @TableField("SORT")
    private Integer sort;

    // 是否有效
    @TableField("IS_EFFECTIVE")
    private String isEffective;




}

Vo

@Data
public class DictItemVo {
    private String dictCode; // 实际的值,如 1
    private String dictName; // 实际的名,如 轿车
}
@Data
public class DictGroupVo {
    // 这里虽然叫 dictCode,但实际存的是 pCode (如 CAR_LEVEL)
    // 这里需要跟前段的命名一致
    private String dictCode; 
    
    // 具体的字典项列表
    private List<DictItemVo> list;
}