一 :前言

在我们开发过程中,我们从前端页面接收的数据字典一般都是key(大多数为数字),但我们在页面显示的时候,想用其value值。如果我们每使用一次就要去写一些重复的代码去查询,这样会使我们的代码非常冗余,那有什么办法可以让我们查询出key的同时,将value值也查询出来,此时我们可以使用自定义注解的方式去做字段映射。

二:编写自定义注解——@Dict

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Dict {

    /**
     * 字典编码
     */
    String dictName();

    /**
     * 实体类内对应的中文字段名,默认为“当前字段+Text”
     * <p>
     * 例如当前字段为“type”,则对应中文字段默认为“typeText”
     */
    String dictField() default "";

}

2.1 数据字典案例

工作地点(WORK_PLACE):北京(1),上海(2),深圳(3)

2.2 String dictName();

dictName指的就是字典编码。也就是工作地点对应的WORK_PLACE。例如现在有一个数据字典,其数据表结构是

java数据字典ppt java数据字典映射_开发语言


code:表示字典的值,对应的一般为数字。例如北京对应的code就是1

text:表示字典的名称,对应的就是具体的value,例如数字1对应的名称就是北京

name:表示当前字典的编码,工作地点对应的编码就是WORK_PLACE

2.3 String dictField()

dictField指的就是需要将当前字典的名称,映射到哪个字段上。例如我们要将workPlace的值映射到workplaceText上。

/**
     * 工作地点 :1-北京 2-上海 3-深圳
     */
    @Column(name = "work_place")
    @Dict(dictName = "WORK_PLACE",dictField ="workPlaceText")
    private Integer workPlace;

    /**
     * 工作地点对应的value
     */
    @TableField(exist = false)
    private String workPlaceText;

此时当我们查询workPlace出时,其名称会自动映射到workPlaceText上

三:编写切面

我们需要在查询这些字段的时候,顺便将字典值查询出来,所以我们需要编写一个切面用来拦截查询方法

/**
 * 用于拦截{oa.flows.base.dao.TbFlowsDAO}的查询方法进行字典表字段转换
 */
@Slf4j
@Aspect
public class BydDaoDictAspect {

    @Pointcut("execution(* oa.flows.base.dao.TbFlowsDAO.query*(..))")
    public void doPointcut() {
    }

    @AfterReturning(pointcut = "doPointcut()", returning = "result")
    public void doAfterReturning(JoinPoint pjp, Object result) {
        try {
            DictUtils.convertDict(result);
        } catch (Exception e) {
            log.error("TbFlowsDAO查询结果字典转换失败", e);
        }
    }

}

1)Object result:就是需要查询实体类的的结果

{
  id:"1",
  name:"ikun",
  workPlace:"2",
  workPlaceText:null
}

workPlaceText此时还没查询出来

四:处理dict的映射

public class DictUtils {

    private static final String DICT_FIELD_SUFFIX = "Text";

    public static void convertDict(Object target) {
        if (target instanceof List) {
            List<?> objectList = ((List<?>) target);
            if (CollectionUtils.isNotEmpty(objectList)) {
                List<DictDefinition> dictDefinitions = getMetadata(objectList.get(0));
                if (CollectionUtils.isEmpty(dictDefinitions)) return;
                List<String> dictNames = dictDefinitions.stream().map(d -> d.getDict().dictName()).collect(Collectors.toList());
                Map<String, Map<String, String>> dictMapMap = getDictMap(dictNames);
                objectList.forEach(t -> doConvertDict(t, dictDefinitions, dictMapMap));
            }
        } else {
            List<DictDefinition> dictDefinitions = getMetadata(target);
            if (CollectionUtils.isEmpty(dictDefinitions)) return;
            List<String> dictNames = dictDefinitions.stream().map(d -> d.getDict().dictName()).collect(Collectors.toList());
            Map<String, Map<String, String>> dictMapMap = getDictMap(dictNames);
            doConvertDict(target, dictDefinitions, dictMapMap);
        }
    }

    /**
     * 仅获取一次Dict元数据,降低多次反射造成的性能消耗
     * @param target 目标实体类
     * @return Dict元数据
     */
    private static List<DictDefinition> getMetadata(Object target) {
        List<DictDefinition> dictDefinitions = new ArrayList<>();
        if (ClassUtils.isPrimitiveOrWrapper(target.getClass())
                || target instanceof Map || target instanceof String) {
            return dictDefinitions;
        }
        List<Field> fields = FieldUtils.getAllFieldsList(target.getClass());
        for (Field field : fields) {
            Dict dict = AnnotationUtils.getAnnotation(field, Dict.class);
            if (dict != null) {
                DictDefinition dictDefinition = new DictDefinition();
                dictDefinition.setDict(dict);
                dictDefinition.setField(field);
                dictDefinitions.add(dictDefinition);
            }
        }
        return dictDefinitions;
    }

    /**
     * 统一获取当前实体类涉及到的字典表数据,避免多次查询数据库造成的性能消耗
     * @param dictNames 字典表Key值
     * @return 字典表数据
     */
    @SneakyThrows
    private static Map<String, Map<String, String>> getDictMap(List<String> dictNames) {
        SqlBuilder sql = new SqlBuilder("select *").from("sys_dict")
                .where("name").in(dictNames).and("enabled").eq(1);
        List<SysDict> dictList = DbUtil.queryList(SysDict.class, sql);
        return dictList.stream().collect(Collectors.groupingBy(
                SysDict::getName, Collectors.toMap(SysDict::getCode, SysDict::getText, (v1, v2) -> v2)));
    }

    @SneakyThrows
    private static void doConvertDict(Object target, List<DictDefinition> dictDefinitions,
                                      Map<String, Map<String, String>> dictMapMap) {
        for (DictDefinition dictDefinition : dictDefinitions) {
            Dict dict = dictDefinition.getDict();
            Field field = dictDefinition.getField();
            Map<String, String> dictMap = dictMapMap.get(dict.dictName());
            String dictCode = String.valueOf(FieldUtils.readField(target, field.getName(), true));
            String dictField = StringUtils.isEmpty(dict.dictField()) ? field.getName() + DICT_FIELD_SUFFIX : dict.dictField();
            FieldUtils.writeField(target, dictField, dictMap.get(dictCode), true);
        }
    }

    @Data
    public static class DictDefinition {

        private Dict dict;

        private Field field;

    }

    @Data
    public static class SysDict {

        private String code;

        private String text;

        private String name;

    }

}

此时就查询出来了,如果对代码不太理解,请自行debug一行一行看