一. 介绍
第一节简单介绍怎么使用数据对象转换:一种高效的数据对象转换方式(1)
https://blog.youkuaiyun.com/ssyujay/article/details/81638984
第二节详细介绍怎么使用数据对象转换:一种高效的数据对象转换方式(2)
https://blog.youkuaiyun.com/ssyujay/article/details/81813394
第三节详细介绍具体代码实现方式:一种高效的数据对象转换方式(3)---代码实现
https://blog.youkuaiyun.com/ssyujay/article/details/81814265
第四节详细介绍包含列表数据对象转换:一种高效的数据对象转换方式(4)-----包含列表输出
https://blog.youkuaiyun.com/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 1060771195@qq.com
*/
@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 1060771195@qq.com
*/
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 1060771195@qq.com
*/
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 1060771195@qq.com
*/
@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());
}
}