ID-NAME结果数据转换器

背景

结果数据转换:

1. 场景:数据库表存储关联表的ID,如创建人ID、机构ID、部门ID等,而前端展示需要的是名称。为了展示,正常是通过关联表查询名称解决,但这样可能导致查询执行效率低下、SQL复杂化,而且还要定义名称字段来存储名称

2. 策略:数据库表还是存储关联表的ID,但字段类型定义为字符串类型(为了代码生成器生成String类型的字段)。service层对外提供的统一为ID查询结果,若有展示需要,则在controller通过DataConverter统一转换为名称返回前端展示

3. 查询结果对象为POJO(DTO\VO\ENTITY),若定义了名称字段(名称字段需以Name结尾,如userId-》userName,org-》orgName),则通过反射将名称存储在Name字段,若未定义名称字段,则直接覆盖ID字段。

4. 查询结果对象为Map,则会新增一个名称字段(名称字段需以Name结尾,如userId-》userName,org-》orgName),名称存储在名称字段,不会覆盖ID字段

5. DataConverter中调用关联表的服务查询名称并做缓存提供转换效率

调用方法

// 转换分页对象数据
DataConverter.toName(DataType.USER_NICK_NAME, page);
// 转换单个对象
DataConverter.toName(DataType.USER_NICK_NAME, obj);
// 转换集合对象
DataConverter.toName(DataType.USER_NICK_NAME, list);

其中,DataType为支持的数据类型(具体见源码)。若默认的转换字段不满足,临时要用的请调用如下代码,比较公用的字段请联系管理员添加到数据类型配置中。

ID-NAME结果数据转换器

数据字典转换

sql查询语句,需在待转换字典值前加字典编码,例子如下(其中yes_no,user_type为字典编码):

select concat('yes_no','-',t.status),concat('user_type','-',t.type) from user t

转换调用,例子如下(其中status、type为待转换的字段):

DataConverter.toName(DataType.YAOXIE_DICT_ITEM,"status","type");

具体实现

DataConverter:结果数据转换器

package com.shusi.convertor;

import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shusi.domain.dto.OptionDTO;
import com.shusi.redis.RedisUtil;
import com.shusi.util.DataUtil;
import com.shusi.util.SpringContextHolder;
import com.shusi.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 结果数据转换器
 *
 * @Author: lincl
 * @Date: 2019/2/28 16:11
 */
@Slf4j
public class DataConverter {

    /**
     * 最多缓存多少
     */
    private final static int MAX_SIZE = 10000;

    /**
     * redis
     */
    private static RedisUtil redisUtil;

    /**
     * 初始化
     */
    public static void init() {
        // 初始化获取bean
        if (redisUtil == null) {
            redisUtil = SpringContextHolder.getBean(RedisUtil.class);
        }
    }

    /**
     * 获取名称
     *
     * @param dataType
     * @param id
     * @return
     */
    public static String getName(DataType dataType, String id) {
        // 初始化
        init();
        List<String> idList = StrUtil.split(id, ',');
        // 查询结果
        List<String> result = redisUtil.getItemListOfMap(dataType.getCachePrefix(), idList);
        // 如果请求服务后,依旧没有数据,则返回id
        if (result == null) {
            return id;
        }
        return StrUtil.join(",", result);
    }

    /**
     * 更新缓存
     *
     * @param dataType 数据类型
     * @param list     数据集合
     */
    public static void setName(DataType dataType, List<OptionDTO> list) {
        // 初始化
        init();
        Map<String, String> map = new HashMap<>(list.size());
        for (OptionDTO item : list) {
            map.put(item.getValue(), item.getLabel());
        }
        // 更新缓存
        redisUtil.setMap(dataType.getCachePrefix(), map);
        log.info("“ {} ” 缓存设置成功!共 {} 个数据!", dataType.getType(), list.size());
    }

    /**
     * 更新名称
     *
     * @param dataType 数据类型
     * @param id       id
     * @param name     名称
     */
    public static void updName(DataType dataType, String id, String name) {
        // 初始化
        init();
        // 更新缓存
        redisUtil.setItemOfMap(dataType.getCachePrefix(), id, name);

    }

    /**
     * 删除名称
     *
     * @param dataType 数据类型
     * @param ids      ids
     */
    public static void delName(DataType dataType, String... ids) {
        // 初始化
        init();
        redisUtil.delItemOfMap(dataType.getCachePrefix(), Arrays.asList(ids));

    }

    /**
     * 单个对象转换
     *
     * @param dataType 数据类型
     * @param obj      数据对象
     * @param <T>
     * @return
     */
    public static <T> T toName(DataType dataType, T obj) {
        return DataConverter.toName(dataType, obj, null);
    }

    /**
     * 集合转换
     *
     * @param list 数据集合
     * @param <T>
     * @return
     */
    public static <T> List<T> toName(DataType dataType, List<T> list) {
        return DataConverter.toName(dataType, list, null);
    }

    /**
     * 分页对象转换
     *
     * @param page
     * @return
     */
    public static Page toName(DataType dataType, Page page) {
        return DataConverter.toName(dataType, page, null);
    }

    /**
     * 单个对象转换
     *
     * @param dataType   数据类型
     * @param obj        数据对象
     * @param fieldNames 转换字段名称
     * @param <T>
     * @return
     */
    public static <T> T toName(DataType dataType, T obj, String[] fieldNames) {
        if (obj == null) {
            return null;
        }

        // 默认转换字段
        if (DataUtil.isEmpty(fieldNames)) {
            fieldNames = dataType.getFieldNames();
        }

        if (DataUtil.isNotEmpty(fieldNames)) {
            for (int i = 0; i < fieldNames.length; i++) {
                String fieldName = fieldNames[i];
                // 存储名称的字段名
                String labelField = fieldName.replace("Id", "") + "Name";
                try {
                    //Map对象
                    if (obj instanceof Map) {
                        if (((Map) obj).get(fieldName) != null) {
                            String userId = ((Map) obj).get(fieldName) + "";
                            String nickName = DataConverter.getName(dataType, userId);
                            ((Map) obj).put(labelField, nickName);
                        }
                    } else {
                        Class clz = obj.getClass();
                        if (ReflectUtil.hasField(clz, fieldName)) {
                            String id = (String) ReflectUtil.getFieldValue(obj, fieldName);
                            if (StrUtil.isNotBlank(id)) {
                                String nickName = DataConverter.getName(dataType, id);
                                if (ReflectUtil.hasField(clz, labelField)) {
                                    // 定义了额外的字段来存储名称
                                    ReflectUtil.setFieldValue(obj, labelField, nickName);
                                } else {
                                    ReflectUtil.setFieldValue(obj, fieldName, nickName);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return obj;
    }

    /**
     * 集合转换
     *
     * @param list       数据集合
     * @param fieldNames 字段名称
     * @param <T>
     * @return
     */
    public static <T> List<T> toName(DataType dataType, List<T> list, String[] fieldNames) {
        if (list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                DataConverter.toName(dataType, list.get(i), fieldNames);
            }
        }
        return list;
    }

    /**
     * 分页对象转换
     *
     * @param page
     * @param fieldNames 字段名称
     * @return
     */
    public static Page toName(DataType dataType, Page page, String[] fieldNames) {
        if (page.getRecords() != null && page.getRecords().size() > 0) {
            DataConverter.toName(dataType, page.getRecords(), fieldNames);
        }
        return page;
    }


}

DataType:数据类型

package com.shusi.convertor;

/**
 * 数据类型枚举类
 *
 * @author lincl
 */
public enum DataType {

    /**
     * 用户账号昵称,默认转换字段:"createBy", "updateBy", "operator", "orderUserId", "pushUserId"
     */
    USER_NICK_NAME("用户账号昵称", "userId", "createBy", "updateBy", "operator", "orderUserId", "pushUserId", "returnUserId", "optionUserId", "sendUserId", "receiveUserId", "receiveUserIds"),
    /**
     * 机构名称,默认转换字段:"orgId", "hospitalOrgId"
     */
    ORG_NAME("机构名称", "orgId","reqOrgId", "userBuyerId", "userSupplierId"),
    /**
     * 厂家名称,默认转换字段:"factoryId"
     */
    FACTORY_NAME("厂家名称", "factoryId", "factory", "userFactoryId"),
    /**
     * 部门名称,默认转换字段:"deptId"
     */
    DEPT_NAME("部门名称", "deptId", "departmentId"),
    /**
     * 部门合并名称,默认转换字段:"deptMergeId"
     */
    DEPT_MERGE_NAME("部门合并名称", "deptMergeId", "deptId", "departmentId"),
    /**
     * 行政区域名称
     */
    REGION_NAME("行政区域名称", "province", "city", "district", "region", "provinceId", "cityId", "districtId"),
    /**
     * 药械网:数据字典
     */
    YAOXIE_DICT_ITEM("数据字典", null),
    /**
     * 统一认证:数据字典
     */
    AUTH_DICT_ITEM("数据字典", null),
    /**
     * 权限名称
     */
    PERMISSION("权限名称", "permissionId");

    /**
     * 类型
     */
    private String type;

    /**
     * 默认转换字段
     */
    private String[] fieldNames;

    DataType(String type, String... fieldNames) {
        this.type = type;
        this.fieldNames = fieldNames;
    }

    /**
     * 获取数据类型
     *
     * @return
     */
    public String getType() {
        return type;
    }

    /**
     * 获取默认转换字段
     *
     * @return
     */
    public String[] getFieldNames() {
        return fieldNames;
    }

    /**
     * 获取缓存前缀
     *
     * @return
     */
    public String getCachePrefix() {
        return "ID_NAME:" + this.name();
    }
}