一种高效的数据对象转换方式(5)-----包含列表输出,代码修改

一. 介绍

   

   第一节简单介绍怎么使用数据对象转换:一种高效的数据对象转换方式(1)

    https://blog.csdn.net/ssyujay/article/details/81638984

    第二节详细介绍怎么使用数据对象转换:一种高效的数据对象转换方式(2)

    https://blog.csdn.net/ssyujay/article/details/81813394

    第三节详细介绍具体代码实现方式:一种高效的数据对象转换方式(3)---代码实现

    https://blog.csdn.net/ssyujay/article/details/81814265

    第四节详细介绍包含列表数据对象转换:一种高效的数据对象转换方式(4)-----包含列表输出

   https://blog.csdn.net/ssyujay/article/details/81842168

    这一节讲介绍包含列表代码实现,通过修改第三节代码实现

二. 代码实现详解,以下就是修改后的实现代码

 1. xml解析类,HubXmlParser.java

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import yui.comn.hub.model.HubXmlColumn;
import yui.comn.hub.model.HubXmlColumnAttr;
import yui.comn.hub.model.HubXmlElement;
import yui.comn.hub.model.HubXmlHandlerConfig;
import yui.comn.hub.utils.HubStringUtils;
import yui.comn.utils.StrUtils;
import yui.comn.utils.Symbol;
import yui.comn.utils.annotation.Note;
import yui.comn.utils.annotation.TableNote;


/**
 * 数据装换中转站-xml解析
 * @author yuyi
 */
@SuppressWarnings("unchecked")
public class HubXmlParser {
    private Logger logger = LoggerFactory.getLogger(HubXmlParser.class);
    
    /**
     * 获取Map,主要用于输出字段描述
     * 例如  {
     *       "usNm": "登陆名",
     *       "nkNm": "昵称",
     *       "roleList": {
     *           "nm": "名称",
     *           "rmks": "备注"
     *        }
     *      }
     */
    public Map<String, Object> toGridKvMapByObj(Class<?> clazz, String name) {
        List<HubXmlColumn> colList = HubXmlCache.getInstance().toGridList(clazz, name);
        return getGridKvMap(colList);
    }
    
    /**
     * 迭代获取Map,主要用于输出字段描述
     */
    private Map<String, Object> getGridKvMap(List<HubXmlColumn> colList) {
        Map<String, Object> map = new LinkedHashMap<>();
        
        for (HubXmlColumn column : colList) {
            if (null == column.getCollections()) {
                map.put(column.getName(), column.getDescr());
            } else {
                Map<String, List<HubXmlColumn>> collections = column.getCollections();
                for (Entry<String, List<HubXmlColumn>> entry : collections.entrySet()) {
                    map.put(column.getName(), getGridKvMap(entry.getValue()));
                }
            }
        }
        
        return map;
    }
    
    /**
     * 解析xml,获取grid类型list
     */
    public List<HubXmlColumn> parseXmlGridColToList(Class<?> clazz, String name) {
        return parseXmlColToList(clazz, HubXmlElement.grid.name(), name);
    }
    
    /**
     * 解析xml,获取search类型map
     */
    public Map<String, String> parseXmlSearchColToMap(Class<?> clazz, String name) {
        List<HubXmlColumn> columns = parseXmlColToList(clazz, HubXmlElement.search.name(), name);
        
        Map<String, String> map = new HashMap<String, String>();
        for (HubXmlColumn column : columns) {
            map.put(column.getName(), column.getMapper());
        }
        
        return map;
    }
    
    /**
     * 解析xml,获取对应的type类型的元素列表
     */
    public List<HubXmlColumn> parseXmlColToList(Class<?> clazz, String type, String name) {
        Element pel = parseXmlToElement(clazz, type, name);
        List<Element> elements = pel.elements();
        
        List<HubXmlColumn> columns = parseXmlColToList(elements, type);
        //排序
        Collections.sort(columns);
        return columns;
    }
    
    
    /**
     * 解析xml,获取对应的type类型的元素列表
     */
    public List<HubXmlColumn> parseXmlColToList(List<Element> elements, String type) {
        List<HubXmlColumn> columns = new ArrayList<>();
        
        for (Element el : elements) {
            String prefix = el.attributeValue(HubXmlColumnAttr.prefix.name());
            String className = el.attributeValue(HubXmlColumnAttr.type.name());
            if (StringUtils.isBlank(className)) {
                HubXmlColumn col = new HubXmlColumn();
                
                String colName = el.attributeValue(HubXmlColumnAttr.name.name());
                String colToName = el.attributeValue(HubXmlColumnAttr.toName.name());
                
                if (StringUtils.equals(HubXmlElement.collection.name(), el.getQualifiedName())) {
                    List<HubXmlColumn> subColumns = parseXmlColToList(el.elements(), type);
                    col.putCollection(colName, subColumns);
                }
                
                //如果前缀不为空
                if (StringUtils.isNotBlank(prefix)) {
                    colName = StrUtils.upperCaseFirstCharAndAddPrefix(colName, prefix);
                    if (StringUtils.isNotBlank(colToName)) {
                        colToName = StrUtils.upperCaseFirstCharAndAddPrefix(colToName, prefix);
                    }
                }
                
                col.setName(colName);
                col.setMapper(el.attributeValue(HubXmlColumnAttr.mapper.name()));
                col.setDescr(el.attributeValue(HubXmlColumnAttr.descr.name()));
                
                String viewOrder = el.attributeValue(HubXmlColumnAttr.viewOrder.name());
                if (StringUtils.isNotBlank(viewOrder)) {
                    col.setViewOrder(Integer.valueOf(viewOrder));
                }
                
                col.setHandler(el.attributeValue(HubXmlColumnAttr.handler.name()));
                col.setToName(colToName);
                col.setToDescr(el.attributeValue(HubXmlColumnAttr.toDescr.name()));
                col.setHandlerConfigs(getConfigs(col.getHandler(), colName));
                
                columns.add(col);
            } else {
                //通过对象类有Note属性的字段,解析成List<HubColumn>
                if (StringUtils.equals(HubXmlElement.grid.name(), type)){
                    addGridColumnByType(columns, prefix, className);
                } else {
                    addSearchColumnByType(columns, prefix, className);
                }
            }
        }
        //排序
        Collections.sort(columns);
        return columns;
    }
    
    /**
     * 把class中属性的值,加入search列表中
     */
    private void addSearchColumnByType(List<HubXmlColumn> columns, String prefix, String className) {
        try {
            Class<?> clazz = Class.forName(className);
            
            String tableName = null;
            
            //先通过对象类TableNote注释获取表名,如果没有该属性,通过解析对象类名获取表名,比如SysUserVo,得到T_SYS_USER
            TableNote tableNote = clazz.getAnnotation(TableNote.class);
            if (null != tableNote) {
                //通过注解取表名
                tableName = tableNote.value();
                if (StringUtils.isBlank(tableName)) {
                    tableName = tableNote.tableName();
                }
            } else {
                //通过解析对象类名获取表名
                tableName = HubStringUtils.getTableNameByVoName(clazz.getSimpleName());
            }
            
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                Note note = field.getAnnotation(Note.class);
                if (null != note) {
                    HubXmlColumn col = new HubXmlColumn();
                    
                    String name = field.getName();
                    //如果前缀不为空
                    if (StringUtils.isNotBlank(prefix)) {
                        name = StrUtils.upperCaseFirstCharAndAddPrefix(name, prefix);
                    }
                    
                    col.setName(name);
                    
                    String attrName = StrUtils.toUnderlineAndUpperCaseByHump(field.getName());
                    col.setMapper(tableName + Symbol.DOT + attrName);
                    
                    col.setDescr(note.value());
                    columns.add(col);
                }
            }
        } catch (Exception e) {
            String errMsg = "通过className解析Column失败, className:" + className;
            logger.error(errMsg, e);
            throw new RuntimeException(errMsg, e);
        }
    }
    
    /**
     * 把class中有Note属性的字段,加入Grid列表中
     */
    private void addGridColumnByType(List<HubXmlColumn> columns, String prefix, String className) {
        try {
            Class<?> clazz = Class.forName(className);
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                Note note = field.getAnnotation(Note.class);
                if (null != note) {
                    HubXmlColumn col = new HubXmlColumn();
                    
                    String name = field.getName();
                    String toName = note.toName();
                    
                    //如果前缀不为空
                    if (StringUtils.isNotBlank(prefix)) {
                        name = StrUtils.upperCaseFirstCharAndAddPrefix(name, prefix);
                        if (StringUtils.isNotBlank(toName)) {
                            toName = StrUtils.upperCaseFirstCharAndAddPrefix(toName, prefix);
                        }
                    }
                    
                    //获取字段描述
                    String descr = note.value();
                    if (StringUtils.isBlank(descr)) {
                        descr = note.descr();
                    }
                    
                    col.setName(name);
                    //比如sysUserVo.usNm
                    col.setMapper(StrUtils.lowerCaseFirstChar(clazz.getSimpleName()) + Symbol.DOT + field.getName());
                    col.setDescr(descr);
                    col.setViewOrder(note.viewOrder());
                    col.setHandler(note.handler());
                    col.setToName(toName);
                    col.setToDescr(note.toDescr());
                    col.setHandlerConfigs(getConfigs(note.handler(), name));
                    columns.add(col);
                }
            }
        } catch (Exception e) {
            String errMsg = "通过className解析Column失败, className:" + className;
            logger.error(errMsg, e);
            throw new RuntimeException(errMsg, e);
        }
    }
    
    /**
     * 解析column中的handler属性成为List<HubXmlHandlerConfig>
     */
    private List<HubXmlHandlerConfig> getConfigs(String handler, String selfParam) {
        if (StringUtils.isBlank(handler)) {
            return null;
        }
        
        List<HubXmlHandlerConfig> handlerConfigs = new ArrayList<>();
        
        String[] configs = StringUtils.split(handler, Symbol.SEMICOLON);
        for (String config : configs) {
            handlerConfigs.add(getConfig(config, selfParam));
        }
        
        return handlerConfigs;
    }
    
    /**
     * 解析column中的handler属性成为HubXmlHandlerConfig
     */
    private HubXmlHandlerConfig getConfig(String config, String selfParam) {
        List<String> params = new ArrayList<>();
        params.add(selfParam);
        
        //如果没有括号
        int openParenIndex = StringUtils.indexOf(config, Symbol.OPNE_PAREN);
        int closeParenIndex = StringUtils.indexOf(config, Symbol.CLOSE_PAREN);
        if (openParenIndex == -1 || closeParenIndex == -1) {
            return new HubXmlHandlerConfig(config, params);
        }
        
        String handler = StringUtils.substringBefore(config, Symbol.OPNE_PAREN);
        //空括号
        if (closeParenIndex - openParenIndex == -1) {
            return new HubXmlHandlerConfig(handler, params);
        }
        
        String paramStr = StringUtils.substringBetween(config, Symbol.OPNE_PAREN, Symbol.CLOSE_PAREN);
        String[] tempParams = StringUtils.split(paramStr, Symbol.COMMA);
        
        for (String tempParam : tempParams) {
            params.add(tempParam);
        }
        
        return new HubXmlHandlerConfig(handler, params);
    }
    
    /**
     * 解析xml,获取对应的type类型元素
     */
    private Element parseXmlToElement(Class<?> clazz, String type, String name) {
        Document document = this.parseXmlToDoc(clazz, type, name);
        Element rootEl = document.getRootElement();
        
        List<Element> elements = rootEl.elements(type);
        
        for (Element el : elements) {
            if (StringUtils.equals(name, el.attributeValue(HubXmlColumnAttr.name.name()))) {
                return el;
            }
        }
        
        String errMsg = "class:" + clazz.getSimpleName() + "; type:" + type + "; name:" + name + ", 找不到对应的元素";
        logger.error(errMsg);
        throw new RuntimeException(errMsg);
        
    }
    
    /**
     * 把xml文件解析成 Document类对象
     */
    private Document parseXmlToDoc (Class<?> clazz, String type, String name) {
        InputStream ins = clazz.getResourceAsStream(getXmlName(clazz));
        try {
            return new SAXReader().read(ins);
        } catch (DocumentException e) {
            String errMsg = "class:" + clazz.getSimpleName() + "; type:" + type + "; name:" + name;
            logger.error(errMsg, e);
            throw new RuntimeException(errMsg, e);
        } finally {
            IOUtils.closeQuietly(ins);
        }
    }
    
    /**
     * 通过class获取对应的xml名称, 比如sysUserController.class类获取sysUserController.xml文件名
     */
    private String getXmlName(Class<?> clazz) {
        return new StringBuffer().append(clazz.getSimpleName()).append(".xml").toString();
    }
}

2. xml解析缓存,HubXmlCache.java

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

import yui.comn.hub.model.HubXmlColumn;
import yui.comn.utils.Symbol;

/**
 * xml 配置文件解析后缓存
 * @author yuyi
 */
public class HubXmlCache {
    // grid kv map缓存 
    private Map<String, Object> gridKvMapCache = new HashMap<>();
    // grid list缓存 
    private Map<String, List<HubXmlColumn>> gridListCache = new HashMap<>();
    // search map缓存 
    private Map<String, Map<String, String>> searchCache = new HashMap<>();
    //xml解析器
    private HubXmlParser hubXmlParser = new HubXmlParser();
    
    /** 是否开启缓存 */
    public boolean cache = true;
    
    private static HubXmlCache hubXmlCache = new HubXmlCache();
    
    public static HubXmlCache getInstance() {
        return hubXmlCache;
    }
    
    /**
     * 缓存Map中的key是由Controller类名加上name
     */
    private String spliceKey(Class<?> clazz, String name) {
        return new StringBuffer().append(clazz.getSimpleName()).append(Symbol.DOT).append(name).toString();
    }
    
    public Map<String, String> toSearch(Class<?> clazz, String name) {
        String searchKey = spliceKey(clazz, name);
        
        Map<String, String> searchMap = searchCache.get(searchKey);
        if (null == searchMap) {
            searchMap = hubXmlParser.parseXmlSearchColToMap(clazz, name);
            if (isCache()) {
                searchCache.put(searchKey, searchMap);
            }
        }
        return searchMap;
    }
    
    @SuppressWarnings("unchecked")
    public Map<String, Object> toGridKvMap(Class<?> clazz, String name) {
        String gridKey = spliceKey(clazz, name);
        
        Map<String, Object> gridKvMap = (Map<String, Object>) gridKvMapCache.get(gridKey);
        if (null == gridKvMap) {
            gridKvMap = hubXmlParser.toGridKvMapByObj(clazz, name);
            if (isCache()) {
                gridKvMapCache.put(gridKey, gridKvMap);
            }
        }
        return gridKvMap;
    }
    
    public List<HubXmlColumn> toGridList(Class<?> clazz, String name) {
        String gridKey = spliceKey(clazz, name);
        
        List<HubXmlColumn> gridList = gridListCache.get(gridKey);
        if (null == gridList) {
            gridList = hubXmlParser.parseXmlGridColToList(clazz, name);
            Collections.sort(gridList);
            if (isCache()) {
                gridListCache.put(gridKey, gridList);
            }
        }
        return gridList;
    }

    
    public boolean isCache() {
        return cache;
    }

    public void setCache(boolean cache) {
        this.cache = cache;
    }
    
}

3. 将数据对象转化为map对象,HubDataToMapParser.java

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import yui.comn.hub.data.handler.HubDataHandlerProcess;
import yui.comn.hub.model.HubJavaType;
import yui.comn.hub.model.HubXmlColumn;
import yui.comn.hub.utils.HubStringUtils;
import yui.comn.hub.xml.parser.HubXmlCache;
import yui.comn.utils.Symbol;

/**
 * 把Dto对象解析成map对象
 * @author yuyi
 */
public class HubDataToMapParser {
    private Logger logger = LoggerFactory.getLogger(HubDataToMapParser.class);
    
    private static HubDataToMapParser parser = new HubDataToMapParser();
    
    public static HubDataToMapParser getInstance() {
        return parser;
    }
    
    /**
     * 对象转Map
     */
    public Map<String, Object> toMapByObj(Class<?> clazz, String name, Object obj) {
        List<HubXmlColumn> colList = HubXmlCache.getInstance().toGridList(clazz, name);
        return toMapByObj(colList, obj);
    }
    
    /**
     * 列表转Map列表
     */
    public List<Map<String, Object>> toMapListByObjList(Class<?> clazz, String name, Collection<?> list) {
        List<HubXmlColumn> colList = HubXmlCache.getInstance().toGridList(clazz, name);
        return toMapListByObjList(colList, list);
    }
    
    
    /**
     * 列表转Map列表
     */
    private List<Map<String, Object>> toMapListByObjList(List<HubXmlColumn> colList, Collection<?> list) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        
        if (CollectionUtils.isNotEmpty(list)) {
            for (Object obj : list) {
                resultList.add(toMapByObj(colList, obj));
            }
        }
        
        return resultList;
    }
    
    
    /**
     * 对象转Map
     */
    private Map<String, Object> toMapByObj(List<HubXmlColumn> colList, Object obj) {
        Map<String, Object> resultMap = new LinkedHashMap<>();
        
        List<HubXmlColumn> columnHandlers = new ArrayList<>();
        for (HubXmlColumn column : colList) {
            if (null != column.getCollections()) {
                Map<String, List<HubXmlColumn>> collections = column.getCollections();
                for (Entry<String, List<HubXmlColumn>> entry : collections.entrySet()) {
                    List<Map<String, Object>> mapList = toMapListByObjList(entry.getValue(), (Collection<?>) getAttrValue(obj, column.getMapper()));
                    resultMap.put(column.getName(), mapList);
                }
            } else {
                resultMap.put(column.getName(), getAttrValue(obj, column.getMapper()));
                if (StringUtils.isNotBlank(column.getHandler())) {
                    columnHandlers.add(column);
                }
            }
            
        }
        //数据处理器
        for (HubXmlColumn hubXmlColumn : columnHandlers) {
            HubDataHandlerProcess.getInstance().handle(hubXmlColumn, resultMap);
        }
        
        return resultMap;
    }
    /***************************************************dto 转   xml***************************************************/
    /**
     * 例如:sysUserDtox.sysUserVo.sysUserPk
     */
    private Object getAttrValue(Object obj, String mapper) {
        if (StringUtils.isBlank(mapper)) {
            return null;
        }
        String[] attrs = StringUtils.split(mapper, Symbol.DOT);
        //先获取属性之前的对象值,比如 sysUserVo.usNm, 就是先获取sysUserVo对象
        for (int i = 0; i < attrs.length - 1; i++) {
            obj = getObjByAttr(obj, attrs[i]);
        }
        
        String attrName = attrs[attrs.length - 1];
        String methodName = null;
        try {
            Class<?> clazz = obj.getClass();
            Field field = getField(clazz, attrName, 3);
            
            //如果是boolean类型, method名称前缀是is, 比如child, 该类型是boolean, 那么获取该属性值的方法是 isChild
            if (StringUtils.equals(field.getType().getName(), HubJavaType.TYPE_BASE_BOOLEAN.getName())) {
                methodName = HubStringUtils.getIsMethodName(attrName);
            } else {
                methodName = HubStringUtils.getGetMethodName(attrName);
            }
            Method method = clazz.getMethod(methodName);
            return method.invoke(obj);
        } catch (Exception e) {
            String errMsg = "获取方法值失败, attrName=" +  attrName + ", methodName=" + methodName;
            logger.error(errMsg, e);
            throw new RuntimeException(errMsg, e);
        } 
        
    }
    
    /**
     * 通过反射执行得到对象
     */
    private Object getObjByAttr(Object obj, String attrName) {
        try {
            Class<?> clazz = obj.getClass();
            Method method = clazz.getMethod(HubStringUtils.getGetMethodName(attrName));
            return method.invoke(obj);
        } catch (Exception e) {
            String errMsg = "获取方法值失败, methodName=" + HubStringUtils.getGetMethodName(attrName);
            logger.error(errMsg, e);
            throw new RuntimeException(errMsg, e);
        }
    }
    
    private Field getField(Class<?> clazz, String fieldName, int retry) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
        } catch (Exception e) {
            field = getField(clazz.getSuperclass(), fieldName, --retry);
        }
        return field;
    }
}

4. xml中col元素属性对象类,HubXmlColumn.java

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import lombok.Data;

/**
 * @author yuyi
 */
@Data
public class HubXmlColumn implements Comparable <HubXmlColumn> {

    private String prefix;      //name的前缀, 比如prefix=sysUser, name=nm, 输出就是 sysUserNm
    private String name;        //grid: map中的key; search: 查询的key
    private String mapper;      //grid: 对象.属性; search: 表名+字段 
    private String type;        //通过解析对象属性,反射生成列
    private String descr;       //列描述 
    private Integer viewOrder;  //列排序,如果写,默认按顺序排序,如果解析类对象,按照英文首字母排序
    private String handler;     //处理器,多个处理器用分号(";")隔开
    private String toName;      //如果通过处理器想生成另一个map属性
    private String toDescr;     //是新属性列排序描述
    
    private List<HubXmlHandlerConfig> handlerConfigs;
    
    private Map<String, List<HubXmlColumn>> collections;
    
    public void putCollection(String key, List<HubXmlColumn> collection) {
        if (null == collections) {
            collections = new LinkedHashMap<>();
        }
        collections.put(key, collection);
    }
    
    public HubXmlColumn() {}
    
    public HubXmlColumn(String name, String mapper) {
        this.name = name;
        this.mapper = mapper;
    }
    
    @Override
    public int compareTo(HubXmlColumn obj) {
        if (obj.getViewOrder() == null) {
            return 1;
        }
        
        if (this.getViewOrder() == null) {
            return -1;
        } 

        return this.getViewOrder().compareTo(((HubXmlColumn) obj).getViewOrder());

    }
    
}

猜你喜欢

转载自blog.csdn.net/ssyujay/article/details/81842635