Commit aa115e88 authored by trumansdo's avatar trumansdo
Browse files

重改映射,利用原有的beetlsql的注解。

parent 34c9ce81
package processor;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ibeetl.admin.core.util.cache.CacheUtil;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.kit.BeanKit;
import org.beetl.sql.core.mapping.BeanProcessor;
import resultmap.GridColumn;
import resultmap.GridHeader;
import resultmap.GridMapping;
import resultmap.GridRow;
public class JsonBeanProcessor extends BeanProcessor {
public JsonBeanProcessor(SQLManager sm) {
super(sm);
}
/**
* 网格化输出结果集
* @param resultSet
* @throws SQLException
*/
public void printfResultSet(ResultSet resultSet) throws SQLException {
Map<String, List<Object>> map = MapUtil.<String, List<Object>>builder().build();
ResultSetMetaData metaData = resultSet.getMetaData();
int count = metaData.getColumnCount();
int rn = 0;
resultSet.absolute(0);
while (resultSet.next()) {
for (int i = 1; i <= count; i++) {
String columnLabel = metaData.getColumnLabel(i);
List<Object> objectList = map.getOrDefault(columnLabel, CollUtil.newArrayList());
Object object = resultSet.getObject(i);
objectList.add(object);
map.put(columnLabel, objectList);
}
rn++;
}
resultSet.absolute(0);
Set<String> keySet = map.keySet();
for (String key : keySet) {
System.out.printf("| %-32s ", key);
}
System.out.println();
for (int i = 0; i < rn; i++) {
Set<Entry<String, List<Object>>> entrySet = map.entrySet();
for (Entry<String, List<Object>> entry : entrySet) {
System.out.printf("| %-32s ", entry.getValue().get(i));
}
System.out.println();
}
}
@Override
public <T> List<T> toBeanList(String sqlId, ResultSet rs, Class<T> type) throws SQLException {
if (!rs.next()) {
return new ArrayList<T>(0);
}
List<T> results = new ArrayList<T>();
PropertyDescriptor[] props = this.propertyDescriptors(type);
ResultSetMetaData rsmd = rs.getMetaData();
int[] columnToProperty = this.mapColumnsToProperties(type, rsmd, props);
Map json = (Map) CacheUtil.get(sqlId);
GridMapping mapping = new GridMapping(json);
if (null == mapping) {
/*无映射的情况下使用beetlsql默认自带的映射*/
do {
results.add(super.createBean(sqlId, rs, type, props, columnToProperty));
} while (rs.next());
} else {
/*复杂结果集映射,取消TailBean的便利性*/
rs.absolute(0);
fillMappingRow(rs, mapping);
results = convertMapping(mapping, type);
}
return results;
}
/**
* 循环转换整个网格映射
*
* @param mapping
* @param objType
* @param <T>
* @return
*/
public <T> List<T> convertMapping(GridMapping mapping, Class<T> objType) throws SQLException {
List<T> results = new ArrayList<T>();
List<GridRow> mappingNestedRows = mapping.getNestedRows();
for (GridRow mappingNestedRow : mappingNestedRows) {
T obj = convertRow(mappingNestedRow, objType);
results.add(obj);
}
return results;
}
/**
* 递归转换整个网格行
*
* @param row
* @param objType
* @param <T>
* @return
*/
public <T> T convertRow(GridRow row, Class<T> objType) throws SQLException {
T obj = super.newInstance(objType);
List<GridColumn> nestedColumns = row.getNestedColumns();
GridColumn curObjCol = nestedColumns.get(0);
for (int i = 1; i < nestedColumns.size(); i++) {
GridColumn nestedColumn = nestedColumns.get(i);
GridHeader mappingHeader = nestedColumn.getMappingHeader();
String resultType = mappingHeader.getResultType();
List<GridRow> nestedRows = nestedColumn.getNestedRows();
for (GridRow nestedRow : nestedRows) {
if (StrUtil.isNotBlank(resultType)) {
/*在映射中标明类型,证明是复杂类型*/
Class nestedPropType = ClassUtil.loadClass(resultType);
String nestedPropName = mappingHeader.getNestedPropName();
boolean isCollection = mappingHeader.getIsCollection();
Object resultObj = BeanUtil.getFieldValue(obj, nestedPropName);
Object nestedPropObj = convertRow(nestedRow, nestedPropType);
if (isCollection) {
((Collection) resultObj).add(nestedPropObj);
resultObj = CollUtil.removeNull(((Collection) resultObj));
} else {
resultObj = nestedPropObj;
}
BeanUtil.setFieldValue(obj, nestedPropName, resultObj);
} else {
/*在映射中没有标明类型,证明是基本类型*/
String nestedPropName = mappingHeader.getNestedPropName();
boolean isCollection = mappingHeader.getIsCollection();
Object resultObj = BeanUtil.getFieldValue(obj, nestedPropName);
Map<String, Object> beanMap = nestedRow.getNestedColumns().get(0).getBeanMap();
/*几乎此处说明内嵌的字段是一个基本类型的集合,所以beanmap中应该只有一个值*/
Object nestedPropObj = CollUtil.getFirst(beanMap.values());
if (isCollection) {
((Collection) resultObj).add(nestedPropObj);
resultObj = CollUtil.removeNull(((Collection) resultObj));
} else {
resultObj = nestedPropObj;
}
BeanUtil.setFieldValue(obj, nestedPropName, resultObj);
}
}
}
/*TODO 重写,以便提供命名转换*/
BeanUtil.fillBeanWithMap(curObjCol.getBeanMap(), obj, true, true);
return obj;
}
/**
* 填充整个网格映射mapping数据结构:通过网格头映射生成一个个网格行
*
* @param resultSet
* @param mapping
* @throws SQLException
*/
protected void fillMappingRow(ResultSet resultSet, GridMapping mapping) throws SQLException {
GridHeader header = mapping.getHeader();
GridColumn column = new GridColumn();
while (resultSet.next()) {
List<GridRow> mappingNestedRows = mapping.getNestedRows();
GridRow row = fillRowColumn(resultSet, header, column);
if (!mappingNestedRows.contains(row)) {
mappingNestedRows.add(row);
}
}
}
/**
* 网格行中存在一个个网格列,也对应着相应的网格头结构
* */
protected GridRow fillRowColumn(ResultSet resultSet, GridHeader header, GridColumn column) {
/*搜寻已经存在的row,如果没有,则插入一个*/
Map<String, Object> beanMap = extractMapFromRs(resultSet, header);
Integer calculateKey = GridColumn.calculateKey(beanMap);
GridRow row = column.findRowByKey(calculateKey);
/*这里可能出现一个问题,始终第0个行是空白的*/
if (ObjectUtil.isNull(row)) {
/*生成一个新的*/
row = GridRow.generateRowByHeader(header);
column.getNestedRows().add(row);
row.setBelongColumn(column);
}
List<GridHeader> nestedHeaders = header.getNestedHeaders();
for (GridHeader nestedHeader : nestedHeaders) {
GridColumn nestedColumn = row.findColumnByHeader(nestedHeader);
List<GridRow> nestedRows = nestedColumn.getNestedRows();
GridRow nestedRow = fillRowColumn(resultSet, nestedHeader, nestedColumn);
if (!nestedRows.contains(nestedRow)) {
nestedRows.add(nestedRow);
}
}
row.getNestedColumns().get(0).setBeanMap(beanMap);
return row;
}
/**
* 遍历网格头,由网格头的信息从结果集中读取值。<br/>
* 这样做的好处是方便算法编写;坏处是失去了tailbean的处理,因为无法确定结果集列的读取状态。
* @param resultSet
* @param header
* @return
*/
private Map<String, Object> extractMapFromRs(ResultSet resultSet, GridHeader header) {
Map<String, Object> tempBeanMap = MapUtil.newHashMap();
/*第一步、先处理当前可以处理的*/
Map<String, String> javaToJdbcMap = header.getJavaToJdbcMap();
Set<Entry<String, String>> entrySet = javaToJdbcMap.entrySet();
for (Entry<String, String> entry : entrySet) {
try {
tempBeanMap.put(entry.getKey(), resultSet.getObject(entry.getValue()));
} catch (SQLException e) {
/*普遍错误:从resultset中获取一个不存在的列,但可以忽视*/
}
}
return tempBeanMap;
}
/**
* 根据class取得属性描述PropertyDescriptor
*
* @param c
* @return
* @throws SQLException
*/
private PropertyDescriptor[] propertyDescriptors(Class<?> c) throws SQLException {
try {
return BeanKit.propertyDescriptors(c);
} catch (IntrospectionException e) {
throw new SQLException("Bean introspection failed: " + e.getMessage());
}
}
}
package resultmap;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 网格列,结果集映射的java类型中的基本类型属性,都应该在一个列中。<br>
* 非基本类型的属性字段,应该内嵌多行 <br>
* 包含:值映射map、映射类型、最关键的obj key<br>
* objkey 决定了数据库结果集的多条重复记录会被唯一记录成一个对象。
*/
public class GridColumn implements Serializable {
/** 对应的属性与数据库中值的映射,用于map to Bean 转换 */
Map<String, Object> beanMap = MapUtil.newHashMap();
/** 映射类型 */
String resultType;
/** 一个网格列包含一个对象中的所有数据列,通过对这些数据列进行hash得到数据列的唯一性 */
Integer objKey;
/** 包含的网格行 */
List<GridRow> nestedRows = CollUtil.<GridRow>newArrayList();
/** 归属的网格行 */
GridRow belongRow;
GridHeader mappingHeader;
public Map<String, Object> getBeanMap() {
return beanMap;
}
public void setBeanMap(Map<String, Object> beanMap) {
this.beanMap = beanMap;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public Integer getObjKey() {
objKey = calculateKey(beanMap);
return objKey;
}
public static Integer calculateKey(Map<String, Object> map) {
if (MapUtil.isEmpty(map)) {
return Integer.MIN_VALUE;
}
int hs = 0;
Set<Entry<String, Object>> entrySet = map.entrySet();
for (Entry<String, Object> entry : entrySet) {
if (ObjectUtil.isNull(entry.getValue())) continue;
hs += entry.getValue().hashCode();
}
return hs * 42;
}
public List<GridRow> getNestedRows() {
return nestedRows;
}
public void setNestedRows(List<GridRow> nestedRows) {
this.nestedRows = nestedRows;
}
public GridRow getBelongRow() {
return belongRow;
}
public void setBelongRow(GridRow belongRow) {
this.belongRow = belongRow;
}
public void setMappingHeader(GridHeader mappingHeader) {
this.mappingHeader = mappingHeader;
}
public GridHeader getMappingHeader() {
return this.mappingHeader;
}
public GridRow findRowByKey(Integer objKey) {
for (GridRow row : this.nestedRows) {
if (ObjectUtil.equal(row.getRowKey(), objKey)) {
return row;
}
}
return null;
}
}
package resultmap;
import static cn.hutool.core.util.StrUtil.EMPTY;
import static cn.hutool.core.util.StrUtil.isNotBlank;
import static java.util.Optional.ofNullable;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ClassUtil;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 网格头,保存了属性与列的映射关系,以及映射的java类型。<br>
* 内嵌的网格头,内嵌网格头的映射java类型,是否是映射至List集合字段
*/
public class GridHeader implements Serializable {
/** java属性名与数据库列名的对应。顺序:prop:column */
Map<String, String> javaToJdbcMap;
/** 映射java类型,如果该值为空,代表为基础类型,并且忽视javaToJdbcMap中的key,因为此刻是基本类型的List, */
String resultType;
/** 嵌套类型的网格头 */
List<GridHeader> nestedHeaders = CollUtil.<GridHeader>newArrayList();
/** 嵌套类型的网格头 */
GridHeader parentHeader;
/** 嵌套字段属性名 */
String nestedPropName;
/** 嵌套类型是否是一个集合 */
boolean isCollection = false;
/** 网格头所属的网格映射 */
GridMapping belongMapping;
public GridHeader(Map<String, Object> resultMapping) {
javaToJdbcMap = new HashMap<String, String>();
processResultMapping(resultMapping);
}
public Map<String, String> getJavaToJdbcMap() {
return javaToJdbcMap;
}
public void setJavaToJdbcMap(Map<String, String> javaToJdbcMap) {
this.javaToJdbcMap = javaToJdbcMap;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public List<GridHeader> getNestedHeaders() {
return nestedHeaders;
}
public void setNestedHeaders(List<GridHeader> nestedHeaders) {
this.nestedHeaders = nestedHeaders;
}
public GridHeader getParentHeader() {
return parentHeader;
}
public void setParentHeader(GridHeader parentHeader) {
this.parentHeader = parentHeader;
}
public String getNestedPropName() {
return nestedPropName;
}
public void setNestedPropName(String nestedPropName) {
this.nestedPropName = nestedPropName;
}
public boolean getIsCollection() {
return isCollection;
}
public void setIsCollection(boolean isCollection) {
this.isCollection = isCollection;
}
public GridMapping getBelongMapping() {
return belongMapping;
}
public void setBelongMapping(GridMapping belongMapping) {
this.belongMapping = belongMapping;
}
private void processResultMapping(Map<String, Object> resultMapping) {
Set<Entry<String, Object>> entrySet = resultMapping.entrySet();
this.setResultType(ofNullable(resultMapping.get("resultType")).orElse(EMPTY).toString());
resultMapping.remove("resultType");
for (Entry<String, Object> objectEntry : entrySet) {
String key = objectEntry.getKey();
Object value = objectEntry.getValue();
Class<?> valClass = ClassUtil.getClass(value);
if (List.class.isAssignableFrom(valClass)) {
/*生成嵌套网格头,此嵌套网格头的类型对应集合字段*/
Map<String, Object> nestedMapping =
(Map<String, Object>) ((List) value).stream().findFirst().orElse(MapUtil.newHashMap(0));
GridHeader nestedHeader = new GridHeader(nestedMapping);
nestedHeader.setIsCollection(true);
nestedHeader.setNestedPropName(key);
nestedHeader.setBelongMapping(this.getBelongMapping());
this.getNestedHeaders().add(nestedHeader);
nestedHeader.setParentHeader(this);
} else if (Map.class.isAssignableFrom(valClass)) {
/*生成嵌套网格头,此嵌套网格头的类型对应单个对象字段*/
Map<String, Object> nestedMapping = (Map<String, Object>) value;
GridHeader nestedHeader = new GridHeader(nestedMapping);
nestedHeader.setIsCollection(false);
nestedHeader.setNestedPropName(key);
nestedHeader.setBelongMapping(this.getBelongMapping());
this.getNestedHeaders().add(nestedHeader);
nestedHeader.setParentHeader(this);
} else if (isNotBlank(key) || (null != value && isNotBlank(String.valueOf(value)))) {
javaToJdbcMap.put(key, String.valueOf(value));
}
}
}
}
package resultmap;
import static cn.hutool.core.util.StrUtil.EMPTY;
import static java.util.Optional.ofNullable;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/** 网格映射数据结构: 包含一个网格头 {@link GridHeader}和多个网格行{@link GridRow} */
public class GridMapping implements Serializable {
/** 映射id */
String mappingId;
/** 当前映射配置对应的class类型 */
String resultType;
/** 网格头 */
GridHeader header;
List<GridRow> nestedRows = CollUtil.newArrayList();
public GridMapping(Map<String, Object> resultMapping) {
JSON parse = JSONUtil.parse(resultMapping);
String id = ofNullable(parse.getByPath("id")).orElse(EMPTY).toString();
String resultType = ofNullable(parse.getByPath("mapping.resultType")).orElse(EMPTY).toString();
Assert.notBlank(id, "result mapping must have [id].");
Assert.notBlank(resultType, "result mapping must have [resultType].");
this.mappingId = id;
this.resultType = resultType;
this.header = new GridHeader((Map<String, Object>) parse.getByPath("mapping"));
}
public GridHeader getHeader() {
return header;
}
public void setHeader(GridHeader header) {
this.header = header;
this.header.setBelongMapping(this);
}
public String getMappingId() {
return mappingId;
}
public void setMappingId(String mappingId) {
this.mappingId = mappingId;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public List<GridRow> getNestedRows() {
return nestedRows;
}
public void setNestedRows(List<GridRow> nestedRows) {
this.nestedRows = nestedRows;
}
public GridRow nextRow(GridColumn column){
GridRow row = GridRow.generateRowByHeader(this.header);
/*给最外层的row设置一个空的列,为了后面的算法便利。可以理解成仅仅只是一个容器而已*/
column.getNestedRows().add(row);
row.setBelongColumn(column);
this.nestedRows.add(row);
return row;
}
}
package resultmap;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import java.io.Serializable;
import java.util.List;
/**
* 网格行,包含一个个网格列<br>
* 一个网格行,对应着SQL select查询出的一个Java的逻辑对象
*/
public class GridRow implements Serializable {
/** 包含的列,第0个列代表的是当前整个类的映射,从0列之后是内部对象字段的映射 */
List<GridColumn> nestedColumns = CollUtil.<GridColumn>newArrayList();
/** 所属的列 */
GridColumn belongColumn;
/** 映射对象的类型名 */
String resultType;
/** 通过每个列的key进行hash得到一个唯一row id */
Integer rowKey;
public GridRow() {}
public List<GridColumn> getNestedColumns() {
return nestedColumns;
}
public void setNestedColumns(List<GridColumn> nestedColumns) {
this.nestedColumns = nestedColumns;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public Integer getRowKey() {
return this.nestedColumns.get(0).getObjKey();
}
public GridColumn getBelongColumn() {
return belongColumn;
}
public void setBelongColumn(GridColumn belongColumn) {
this.belongColumn = belongColumn;
}
/**
* 根据网格头,生成对应的网格行结构。 行套列或者列套行再套列两种。
*
* @return
*/
public static GridRow generateRowByHeader(GridHeader gridHeader) {
if (ObjectUtil.isNull(gridHeader)) {
return null;
}
/*这是外层*/
GridRow gridRow = new GridRow();
/*这个列才是真正的存储数据值的*/
GridColumn gridColumn = new GridColumn();
gridRow.getNestedColumns().add(gridColumn);
gridColumn.setBelongRow(gridRow);
List<GridHeader> headers = gridHeader.getNestedHeaders();
for (GridHeader header : headers) {
/*这只是外部的一个容器性质的列,这个是内层*/
GridColumn containerColumn = new GridColumn();
GridRow nestedRow = generateRowByHeader(header);
containerColumn.getNestedRows().add(nestedRow);
nestedRow.setBelongColumn(containerColumn);
gridRow.getNestedColumns().add(containerColumn);
containerColumn.setBelongRow(gridRow);
containerColumn.setMappingHeader(header);
}
gridColumn.setMappingHeader(gridHeader);
gridColumn.setResultType(gridHeader.getResultType());
gridRow.setResultType(gridHeader.getResultType());
return gridRow;
}
public GridColumn findColumnByHeader(GridHeader header) {
for (GridColumn column : this.nestedColumns) {
if (ObjectUtil.equal(column.getMappingHeader(), header)) {
return column;
}
}
return null;
}
}
package com.ibeetl.admin.core.conf.beetl.processor; package com.ibeetl.admin.core.conf.beetl.processor;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil; import com.ibeetl.admin.core.conf.beetl.resultmap.DBColumnProperty;
import cn.hutool.core.util.StrUtil; import com.ibeetl.admin.core.conf.beetl.resultmap.GridCell;
import com.ibeetl.admin.core.conf.beetl.resultmap.GridColumn;
import com.ibeetl.admin.core.conf.beetl.resultmap.GridHeader; import com.ibeetl.admin.core.conf.beetl.resultmap.GridHeader;
import com.ibeetl.admin.core.conf.beetl.resultmap.GridMapping; import com.ibeetl.admin.core.conf.beetl.resultmap.GridMapping;
import com.ibeetl.admin.core.conf.beetl.resultmap.GridRow; import com.ibeetl.admin.core.conf.beetl.resultmap.JavaFieldProperty;
import com.ibeetl.admin.core.util.cache.CacheUtil; import com.ibeetl.admin.core.util.cache.CacheUtil;
import java.beans.IntrospectionException; import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.sql.JDBCType;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import org.beetl.sql.core.SQLManager; import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.db.DBStyle; import org.beetl.sql.core.db.DBStyle;
...@@ -99,11 +100,11 @@ public class JsonBeanProcessor extends BeanProcessor { ...@@ -99,11 +100,11 @@ public class JsonBeanProcessor extends BeanProcessor {
} else { } else {
/*复杂结果集映射,取消TailBean的便利性*/ /*复杂结果集映射,取消TailBean的便利性*/
rs.absolute(0); rs.absolute(0);
mapping.setNestedRows(null); mapping.getVirtualCell().getNestedCells().clear();
fillMappingRow(sqlId, rs, mapping); fillMappingNestedCells(sqlId, rs, mapping);
results = convertMapping(mapping, type); results = parserMappingNestedCells(mapping);
} }
return CollUtil.getFirst(results); return CollUtil.isNotEmpty(results) ? CollUtil.getFirst(results) : null;
} }
/** /**
...@@ -136,136 +137,174 @@ public class JsonBeanProcessor extends BeanProcessor { ...@@ -136,136 +137,174 @@ public class JsonBeanProcessor extends BeanProcessor {
} else { } else {
/*复杂结果集映射,取消TailBean的便利性*/ /*复杂结果集映射,取消TailBean的便利性*/
rs.absolute(0); rs.absolute(0);
mapping.getNestedRows().clear(); mapping.getVirtualCell().getNestedCells().clear();
fillMappingRow(sqlId, rs, mapping); fillMappingNestedCells(sqlId, rs, mapping);
results = convertMapping(mapping, type); results = parserMappingNestedCells(mapping);
} }
return results; return results;
} }
/** /**
* 循环转换整个网格映射 * 循环转换整个网格映射为最终的映射类型
* *
* @param mapping * @param mapping 预先处理好的网格映射
* @param objType
* @param <T>
* @return * @return
*/ */
public <T> List<T> convertMapping(GridMapping mapping, Class<T> objType) throws SQLException { public List parserMappingNestedCells(GridMapping mapping) throws SQLException {
List<T> results = new ArrayList<T>(); List results = parserRealContainerCell(mapping.getVirtualCell());
List<GridRow> mappingNestedRows = mapping.getNestedRows();
for (GridRow mappingNestedRow : mappingNestedRows) {
T obj = convertRow(mappingNestedRow, objType);
results.add(obj);
}
return results; return results;
} }
/** /**
* 递归转换整个网格 * 递归转换整个网格
* *
* @param row * @param virtualCell
* @param objType
* @param <T>
* @return * @return
*/ */
public <T> T convertRow(GridRow row, Class<T> objType) throws SQLException { public List parserRealContainerCell(GridCell virtualCell) throws SQLException {
T obj = super.newInstance(objType); /*判断是单个对象还是集合*/
GridHeader relationGridHeader = virtualCell.getRelationGridHeader();
List<GridColumn> nestedColumns = row.getNestedColumns(); JavaFieldProperty firstLevelBelongNestedField = relationGridHeader.getBelongNestedField();
GridColumn curObjCol = nestedColumns.get(0); List objList = new ArrayList();
List<GridCell> realCellList = virtualCell.getNestedCells();
for (int i = 1; i < nestedColumns.size(); i++) { for (GridCell realContainerCell : realCellList) {
GridColumn nestedColumn = nestedColumns.get(i); List<GridCell> virtualCellList = realContainerCell.getNestedCells();
GridHeader mappingHeader = nestedColumn.getMappingHeader(); GridCell contentCell = virtualCellList.get(0);
String resultType = mappingHeader.getResultType(); Object obj = this.createObjectFromResultSetMap(contentCell);
for (int i = 1; i < virtualCellList.size(); i++) {
List<GridRow> nestedRows = nestedColumn.getNestedRows(); GridCell tempVirtualCell = virtualCellList.get(i);
for (GridRow nestedRow : nestedRows) { JavaFieldProperty twoLevelBelongNestedField =
if (StrUtil.isNotBlank(resultType)) { tempVirtualCell.getRelationGridHeader().getBelongNestedField();
/*在映射中标明类型,表示是复杂类型*/ Boolean isList =
Class nestedPropType = ClassUtil.loadClass(resultType); Optional.ofNullable(twoLevelBelongNestedField)
String nestedPropName = mappingHeader.getNestedPropName(); .map(JavaFieldProperty::isList)
boolean isCollection = mappingHeader.getIsCollection(); .orElse(true);
Object resultObj = BeanUtil.getFieldValue(obj, nestedPropName); List beanList = parserRealContainerCell(tempVirtualCell);
Object nestedPropObj = convertRow(nestedRow, nestedPropType); Object val;
if (isCollection) { if (isList) {
((Collection) resultObj).add(nestedPropObj); val = beanList.isEmpty() ? null : beanList;
resultObj = CollUtil.removeNull(((Collection) resultObj));
} else {
resultObj = nestedPropObj;
}
BeanUtil.setFieldValue(obj, nestedPropName, resultObj);
} else { } else {
/*在映射中没有标明类型,表示是基本类型*/ val = beanList.isEmpty() ? null : beanList.get(0);
String nestedPropName = mappingHeader.getNestedPropName();
boolean isCollection = mappingHeader.getIsCollection();
Object resultObj = BeanUtil.getFieldValue(obj, nestedPropName);
Map<String, Object> beanMap = nestedRow.getNestedColumns().get(0).getBeanMap();
/*无法递归,表明是基本类型集合*/
Object nestedPropObj = CollUtil.getFirst(beanMap.values());
if (isCollection) {
((Collection) resultObj).add(nestedPropObj);
resultObj = CollUtil.removeNull(((Collection) resultObj));
} else {
resultObj = nestedPropObj;
}
BeanUtil.setFieldValue(obj, nestedPropName, resultObj);
} }
super.callSetter(
obj,
twoLevelBelongNestedField.getPropertyDescriptor(),
val,
twoLevelBelongNestedField.getField().getType());
}
objList.add(obj);
}
return objList;
}
private Object createObjectFromResultSetMap(GridCell contentCell) throws SQLException {
Object bean;
Map<String, Object> valueMap = contentCell.getBeanMap();
GridHeader relationGridHeader = contentCell.getRelationGridHeader();
Class resultType = relationGridHeader.getResultType();
if (resultType == null) {
/*无对应类,说明是一个基本类型或者包装类*/
JavaFieldProperty belongNestedField = relationGridHeader.getBelongNestedField();
Object tv = valueMap.values().stream().findFirst().orElse(null);
Object convertVal;
if (belongNestedField.isList()) {
Type listElementType = belongNestedField.getListElementType();
convertVal = Convert.convert(listElementType, tv);
} else {
Class<?> type = belongNestedField.getField().getType();
convertVal = Convert.convert(type, tv);
} }
return convertVal;
}
bean = super.newInstance(resultType);
Map<JavaFieldProperty, DBColumnProperty> fieldToColumnMap =
relationGridHeader.getFieldToColumnMap();
Set<Entry<JavaFieldProperty, DBColumnProperty>> entrySet = fieldToColumnMap.entrySet();
for (Entry<JavaFieldProperty, DBColumnProperty> entry : entrySet) {
JavaFieldProperty javaFieldProperty = entry.getKey();
Field field = javaFieldProperty.getField();
Object value = valueMap.get(field.getName());
super.callSetter(bean, javaFieldProperty.getPropertyDescriptor(), value, field.getType());
} }
BeanUtil.fillBeanWithMap(curObjCol.getBeanMap(), obj, true, true); return bean;
return obj;
} }
/** /**
* 填充整个网格映射mapping数据结构:通过网格头映射生成一个个网格行 * 填充整个网格映射mapping数据结构:通过网格头映射生成一个个网格单元。<br>
* 并没有对大数据量结果集做处理。而且递归有深度限制,列数映射过多可能会出现递归堆栈溢出,不过应该极少出现。
* *
* @param resultSet * @param resultSet
* @param mapping * @param mapping
* @throws SQLException * @throws SQLException
*/ */
protected void fillMappingRow(String sqlId, ResultSet resultSet, GridMapping mapping) protected void fillMappingNestedCells(String sqlId, ResultSet resultSet, GridMapping mapping)
throws SQLException { throws SQLException {
if (!resultSet.next()) return;
GridHeader header = mapping.getHeader(); GridHeader header = mapping.getHeader();
GridColumn column = new GridColumn(); processJdbcColumn(header, resultSet);
while (resultSet.next()) { /*必须给一个虚假容器,为了实现递归*/
List<GridRow> mappingNestedRows = mapping.getNestedRows(); do {
GridRow row = fillRowColumn(sqlId, resultSet, header, column); fillNestedGridCell(sqlId, resultSet, header, mapping.getVirtualCell());
if (!mappingNestedRows.contains(row)) { } while (resultSet.next());
mappingNestedRows.add(row); }
} /** 填充网格映射中的单元格映射结构。 */
protected void fillNestedGridCell(
String sqlId, ResultSet resultSet, GridHeader header, GridCell virtualCell) {
/*通过当前header获取对应的结果集列*/
Map<String, Object> beanMap = extractMapFromRs(sqlId, resultSet, header);
GridCell realContainerCell = virtualCell.addOrCreateNestedCell(header, beanMap);
List<GridHeader> nestedHeaders = header.getNestedHeaders();
for (GridHeader nestedHeader : nestedHeaders) {
/*在 realContainerCell 中找到对应header的虚拟cell*/
GridCell nestedVirtualCell = realContainerCell.findVirtualCell(nestedHeader);
fillNestedGridCell(sqlId, resultSet, nestedHeader, nestedVirtualCell);
} }
} }
/** /**
* 填充网格行中的单元格映射结构。 * Method processJdbcColumn ...<br>
* 根据当前sql语句的resultset 处理gridheader中的fieldToColumnMap。
* *
* <p>网格行中存在一个个网格列,也对应着相应的网格头结构 * @param header of type GridHeader
* @param resultSet of type ResultSet
*/ */
protected GridRow fillRowColumn( private void processJdbcColumn(GridHeader header, ResultSet resultSet) {
String sqlId, ResultSet resultSet, GridHeader header, GridColumn column) throws SQLException {
/*搜寻已经存在的row,如果没有,则插入一个*/
Map<String, Object> beanMap = extractMapFromRs(sqlId, resultSet, header);
Integer calculateKey = GridColumn.calculateKey(beanMap);
GridRow row = column.findRowByKey(calculateKey);
/*这里可能出现一个问题,始终第0个行是空白的*/
if (ObjectUtil.isNull(row)) {
/*生成一个新的*/
row = GridRow.generateRowByHeader(header);
column.getNestedRows().add(row);
row.setBelongColumn(column);
}
List<GridHeader> nestedHeaders = header.getNestedHeaders(); List<GridHeader> nestedHeaders = header.getNestedHeaders();
for (GridHeader nestedHeader : nestedHeaders) { for (GridHeader nestedHeader : nestedHeaders) {
GridColumn nestedColumn = row.findColumnByHeader(nestedHeader); processJdbcColumn(nestedHeader, resultSet);
List<GridRow> nestedRows = nestedColumn.getNestedRows(); }
GridRow nestedRow = fillRowColumn(sqlId, resultSet, nestedHeader, nestedColumn); try {
if (!nestedRows.contains(nestedRow)) { ResultSetMetaData metaData = resultSet.getMetaData();
nestedRows.add(nestedRow); int columnCount = metaData.getColumnCount();
List<String> effectiveColumnLabelList = new ArrayList<String>();
for (int i = 1; i <= columnCount; i++) {
effectiveColumnLabelList.add(metaData.getColumnLabel(i).toLowerCase());
}
Map<JavaFieldProperty, DBColumnProperty> fieldToColumnMap = header.getFieldToColumnMap();
Set<Entry<JavaFieldProperty, DBColumnProperty>> entrySet = fieldToColumnMap.entrySet();
for (Entry<JavaFieldProperty, DBColumnProperty> entry : entrySet) {
DBColumnProperty dbColumnProperty = entry.getValue();
String columnLabel = dbColumnProperty.getColumnLabel();
boolean contains = effectiveColumnLabelList.contains(columnLabel.toLowerCase());
if (!contains) {
dbColumnProperty.setHasEffective(false);
continue;
}
boolean isSpecialDbRn =
(super.dbType == DBStyle.DB_ORACLE || super.dbType == DBStyle.DB_SQLSERVER)
&& columnLabel.equalsIgnoreCase("beetl_rn");
if (isSpecialDbRn) {
dbColumnProperty.setHasEffective(false);
// sql server 特殊处理,sql'server的翻页使用了额外列作为翻页参数,需要过滤
continue;
}
int columnIndex = resultSet.findColumn(columnLabel);
dbColumnProperty.setHasEffective(true);
dbColumnProperty.setColumnIndex(columnIndex);
dbColumnProperty.setJdbcType(JDBCType.valueOf(metaData.getColumnType(columnIndex)));
} }
} catch (SQLException e) {
e.printStackTrace();
} }
row.getNestedColumns().get(0).setBeanMap(beanMap);
return row;
} }
/** /**
...@@ -275,64 +314,46 @@ public class JsonBeanProcessor extends BeanProcessor { ...@@ -275,64 +314,46 @@ public class JsonBeanProcessor extends BeanProcessor {
* @param header * @param header
* @return * @return
*/ */
private Map<String, Object> extractMapFromRs(String sqlId, ResultSet resultSet, GridHeader header) private Map<String, Object> extractMapFromRs(
throws SQLException { String sqlId, ResultSet resultSet, GridHeader header) {
Map<String, Object> tempBeanMap = MapUtil.newHashMap(); Map<String, Object> tempBeanMap = MapUtil.newHashMap();
/*保存着结果集的列标签与索引的映射关系*/
Map<String, Integer> columnLableToIndexMap = MapUtil.newHashMap();
ResultSetMetaData metaData = resultSet.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
String key = metaData.getColumnLabel(i);
boolean isSpecialDbRn =
(super.dbType == DBStyle.DB_ORACLE || super.dbType == DBStyle.DB_SQLSERVER)
&& key.equalsIgnoreCase("beetl_rn");
if (isSpecialDbRn) {
// sql server 特殊处理,sql'server的翻页使用了额外列作为翻页参数,需要过滤
continue;
}
columnLableToIndexMap.putIfAbsent(key, i);
}
/*处理每个头部映射的bean类型与结果集的列的类型转换*/ /*处理每个头部映射的bean类型与结果集的列的类型转换*/
String resultType = header.getResultType(); Map<JavaFieldProperty, DBColumnProperty> fieldToColumnMap = header.getFieldToColumnMap();
Class objectClass = Set<Entry<JavaFieldProperty, DBColumnProperty>> entrySet = fieldToColumnMap.entrySet();
StrUtil.isNotBlank(resultType) ? ClassUtil.loadClass(resultType, false) : null; for (Entry<JavaFieldProperty, DBColumnProperty> entry : entrySet) {
Map<String, String> javaToJdbcMap = header.getJavaToJdbcMap();
Set<Entry<String, String>> entrySet = javaToJdbcMap.entrySet();
for (Entry<String, String> entry : entrySet) {
try { try {
if (objectClass == null) { JavaFieldProperty javaFieldProperty = entry.getKey();
tempBeanMap.put(entry.getKey(), resultSet.getObject(entry.getValue())); DBColumnProperty dbColumnProperty = entry.getValue();
if (!dbColumnProperty.isHasEffective()) {
continue; continue;
} }
Field declaredField = ClassUtil.getDeclaredField(objectClass, entry.getKey()); Class fieldType =
Class fieldType = declaredField != null ? declaredField.getType() : null; Optional.ofNullable(javaFieldProperty)
.map(JavaFieldProperty::getField)
/*忽视列标签的大小写问题*/ .map(Field::getType)
Integer columnIndex = columnLableToIndexMap.getOrDefault(entry.getValue(), -1); .orElse(null);
columnIndex =
columnIndex != -1
? columnIndex
: columnLableToIndexMap.getOrDefault(entry.getValue().toUpperCase(), -1);
columnIndex =
columnIndex != -1
? columnIndex
: columnLableToIndexMap.getOrDefault(entry.getValue().toLowerCase(), -1);
TypeParameter typeParameter =
new TypeParameter(sqlId, super.dbName, fieldType, resultSet, metaData, columnIndex);
JavaSqlTypeHandler handler = super.getHandlers().get(fieldType); JavaSqlTypeHandler handler = super.getHandlers().get(fieldType);
if (handler == null) { if (handler == null) {
handler = super.getDefaultHandler(); handler = super.getDefaultHandler();
} }
tempBeanMap.put(entry.getKey(), handler.getValue(typeParameter)); TypeParameter typeParameter =
new TypeParameter(
sqlId,
super.dbName,
fieldType,
resultSet,
resultSet.getMetaData(),
dbColumnProperty.getColumnIndex());
tempBeanMap.put(javaFieldProperty.getKey(), handler.getValue(typeParameter));
} catch (SQLException e) { } catch (SQLException e) {
/*大部分错误:从resultset中获取一个不存在的列,但可以忽视*/ e.printStackTrace();
} }
} }
tempBeanMap.values().remove(null);
return tempBeanMap; return tempBeanMap;
} }
......
...@@ -3,7 +3,60 @@ package com.ibeetl.admin.core.conf.beetl.resultmap; ...@@ -3,7 +3,60 @@ package com.ibeetl.admin.core.conf.beetl.resultmap;
import java.sql.JDBCType; import java.sql.JDBCType;
public class DBColumnProperty { public class DBColumnProperty {
private String columnName; /** json映射中value */
private int columnIndex; String value;
private JDBCType jdbcType; /** SQL select 中as 别名 */
String columnLabel;
/** 对应列索引位置,从1开始 */
int columnIndex;
/** 对应的jdbc类型 */
JDBCType jdbcType;
boolean hasEffective;
public DBColumnProperty(String columnLabel) {
this.columnLabel = columnLabel;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColumnLabel() {
return columnLabel;
}
public void setColumnLabel(String columnLabel) {
this.columnLabel = columnLabel;
}
public int getColumnIndex() {
return columnIndex;
}
public void setColumnIndex(int columnIndex) {
this.columnIndex = columnIndex;
}
public JDBCType getJdbcType() {
return jdbcType;
}
public void setJdbcType(JDBCType jdbcType) {
this.jdbcType = jdbcType;
}
public boolean isHasEffective() {
return hasEffective;
}
public void setHasEffective(boolean hasEffective) {
this.hasEffective = hasEffective;
}
} }
...@@ -7,6 +7,7 @@ import java.io.Serializable; ...@@ -7,6 +7,7 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set; import java.util.Set;
/** /**
...@@ -15,47 +16,62 @@ import java.util.Set; ...@@ -15,47 +16,62 @@ import java.util.Set;
* 包含:值映射map、映射类型、最关键的obj key<br> * 包含:值映射map、映射类型、最关键的obj key<br>
* objkey 决定了数据库结果集的多条重复记录会被唯一记录成一个对象。 * objkey 决定了数据库结果集的多条重复记录会被唯一记录成一个对象。
*/ */
public class GridColumn implements Serializable { public class GridCell implements Serializable {
/** 对应的属性与数据库中值的映射,用于map to Bean 转换 */ /** 对应的属性与数据库中值的映射,用于map to Bean 转换 */
Map<String, Object> beanMap = MapUtil.newHashMap(); Map<String, Object> beanMap = MapUtil.newHashMap();
/** 映射类型 */ /** 映射类型 */
String resultType; Class resultType;
/** 一个网格列包含一个对象中的所有数据列,通过对这些数据列进行hash得到数据列的唯一性 */ /** 一个单元格包含一个对象中的所有数据列,通过对这些数据列进行hash得到数据列的唯一性 */
Integer objKey; Integer hashKey;
/** 包含的网格 */ /** 包含的网格单元格 */
List<GridRow> nestedRows = CollUtil.<GridRow>newArrayList(); List<GridCell> nestedCell = CollUtil.<GridCell>newArrayList();
/** 归属的网格 */ /** 归属的网格单元格 */
GridRow belongRow; GridCell parentCell;
GridHeader mappingHeader; GridHeader relationGridHeader;
/** 是否是作为容器 */
boolean hasContainer;
public Map<String, Object> getBeanMap() { public Map<String, Object> getBeanMap() {
return beanMap; return beanMap;
} }
public void setBeanMap(Map<String, Object> beanMap) { public void setBeanMap(Map<String, Object> beanMap) {
this.hashKey = calculateHashKey(beanMap);
this.beanMap = beanMap; this.beanMap = beanMap;
} }
public String getResultType() { public Class getResultType() {
return resultType; return resultType;
} }
public void setResultType(String resultType) { public void setResultType(Class resultType) {
this.resultType = resultType; this.resultType = resultType;
} }
public Integer getObjKey() { public Integer getHashKey() {
objKey = calculateKey(beanMap); return hashKey;
return objKey; }
public void setHashKey(Integer hashKey) {
this.hashKey = hashKey;
}
public boolean isHasContainer() {
return hasContainer;
}
public void setHasContainer(boolean hasContainer) {
this.hasContainer = hasContainer;
} }
public static Integer calculateKey(Map<String, Object> map) { public static Integer calculateHashKey(Map<String, Object> map) {
if (MapUtil.isEmpty(map)) { if (MapUtil.isEmpty(map)) {
return Integer.MIN_VALUE; return Integer.MIN_VALUE;
} }
...@@ -68,36 +84,70 @@ public class GridColumn implements Serializable { ...@@ -68,36 +84,70 @@ public class GridColumn implements Serializable {
return hs * 42; return hs * 42;
} }
public List<GridRow> getNestedRows() { public List<GridCell> getNestedCells() {
return nestedRows; return nestedCell;
}
public void setNestedCell(List<GridCell> nestedCell) {
this.nestedCell = nestedCell;
} }
public void setNestedRows(List<GridRow> nestedRows) { public GridCell getParentCell() {
this.nestedRows = nestedRows; return parentCell;
} }
public GridRow getBelongRow() { public void setParentCell(GridCell parentCell) {
return belongRow; this.parentCell = parentCell;
} }
public void setBelongRow(GridRow belongRow) { public void setRelationGridHeader(GridHeader relationGridHeader) {
this.belongRow = belongRow; this.relationGridHeader = relationGridHeader;
} }
public void setMappingHeader(GridHeader mappingHeader) { public GridHeader getRelationGridHeader() {
this.mappingHeader = mappingHeader; return this.relationGridHeader;
} }
public GridHeader getMappingHeader() { public GridCell addOrCreateNestedCell(GridHeader header, Map<String, Object> beanMap) {
return this.mappingHeader; GridCell contentCell = new GridCell();
contentCell.setHasContainer(false);
contentCell.setRelationGridHeader(header);
contentCell.setResultType(header.getResultType());
contentCell.setBeanMap(beanMap);
List<GridCell> realContainerCellList = this.getNestedCells();
for (GridCell cell : realContainerCellList) {
GridCell first = CollUtil.getFirst(cell.getNestedCells());
if (first.getHashKey().equals(contentCell.getHashKey())) {
return cell;
}
}
GridCell realContainerCell = new GridCell();
realContainerCell.setResultType(header.getResultType());
realContainerCell.setParentCell(this);
realContainerCell.setRelationGridHeader(header);
realContainerCell.setHasContainer(true);
realContainerCell.getNestedCells().add(contentCell);
this.getNestedCells().add(realContainerCell);
return realContainerCell;
} }
public GridRow findRowByKey(Integer objKey) { public GridCell findVirtualCell(GridHeader header) {
for (GridRow row : this.nestedRows) { for (GridCell cell : this.nestedCell) {
if (ObjectUtil.equal(row.getRowKey(), objKey)) { if (cell.getRelationGridHeader().equals(header)) {
return row; return cell;
} }
} }
return null;
GridCell virtualCell = new GridCell();
virtualCell.setParentCell(this);
virtualCell.setRelationGridHeader(header);
virtualCell.setHasContainer(true);
this.getNestedCells().add(virtualCell);
return virtualCell;
} }
} }
...@@ -7,11 +7,15 @@ import static java.util.Optional.ofNullable; ...@@ -7,11 +7,15 @@ import static java.util.Optional.ofNullable;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set; import java.util.Set;
/** /**
...@@ -21,10 +25,10 @@ import java.util.Set; ...@@ -21,10 +25,10 @@ import java.util.Set;
public class GridHeader implements Serializable { public class GridHeader implements Serializable {
/** java属性名与数据库列名的对应。顺序:prop:column */ /** java属性名与数据库列名的对应。顺序:prop:column */
Map<String, String> javaToJdbcMap; Map<JavaFieldProperty, DBColumnProperty> fieldToColumnMap = new HashMap<>();
/** 映射java类型,如果该值为空,代表为基础类型,并且忽视javaToJdbcMap中的key,因为此刻是基本类型的List, */ /** 当前网格头对应映射java类型,只有嵌套的是非基本类型和string才有值 */
String resultType; Class resultType;
/** 嵌套类型的网格头 */ /** 嵌套类型的网格头 */
List<GridHeader> nestedHeaders = CollUtil.<GridHeader>newArrayList(); List<GridHeader> nestedHeaders = CollUtil.<GridHeader>newArrayList();
...@@ -32,33 +36,30 @@ public class GridHeader implements Serializable { ...@@ -32,33 +36,30 @@ public class GridHeader implements Serializable {
/** 嵌套类型的网格头 */ /** 嵌套类型的网格头 */
GridHeader parentHeader; GridHeader parentHeader;
/** 嵌套字段属性名 */ /** 当前header所属上级的嵌套字段名。如果是第一级就说明没有嵌套,为null */
String nestedPropName; JavaFieldProperty belongNestedField;
/** 嵌套类型是否是一个集合 */
boolean isCollection = false;
/** 网格头所属的网格映射 */ /** 网格头所属的网格映射 */
GridMapping belongMapping; GridMapping belongMapping;
public GridHeader(Map<String, Object> resultMapping) { public GridHeader(Map<String, Object> resultMapping, GridMapping belongMapping) {
javaToJdbcMap = new HashMap<String, String>(); this.belongMapping = belongMapping;
processResultMapping(resultMapping); processResultMapping(resultMapping);
} }
public Map<String, String> getJavaToJdbcMap() { public Map<JavaFieldProperty, DBColumnProperty> getFieldToColumnMap() {
return javaToJdbcMap; return fieldToColumnMap;
} }
public void setJavaToJdbcMap(Map<String, String> javaToJdbcMap) { public void setFieldToColumnMap(Map<JavaFieldProperty, DBColumnProperty> fieldToColumnMap) {
this.javaToJdbcMap = javaToJdbcMap; this.fieldToColumnMap = fieldToColumnMap;
} }
public String getResultType() { public Class getResultType() {
return resultType; return resultType;
} }
public void setResultType(String resultType) { public void setResultType(Class resultType) {
this.resultType = resultType; this.resultType = resultType;
} }
...@@ -78,20 +79,12 @@ public class GridHeader implements Serializable { ...@@ -78,20 +79,12 @@ public class GridHeader implements Serializable {
this.parentHeader = parentHeader; this.parentHeader = parentHeader;
} }
public String getNestedPropName() { public JavaFieldProperty getBelongNestedField() {
return nestedPropName; return belongNestedField;
}
public void setNestedPropName(String nestedPropName) {
this.nestedPropName = nestedPropName;
} }
public boolean getIsCollection() { public void setBelongNestedField(JavaFieldProperty belongNestedField) {
return isCollection; this.belongNestedField = belongNestedField;
}
public void setIsCollection(boolean isCollection) {
this.isCollection = isCollection;
} }
public GridMapping getBelongMapping() { public GridMapping getBelongMapping() {
...@@ -102,35 +95,52 @@ public class GridHeader implements Serializable { ...@@ -102,35 +95,52 @@ public class GridHeader implements Serializable {
this.belongMapping = belongMapping; this.belongMapping = belongMapping;
} }
/**
* Method processResultMapping ...<br>
* 根据json格式的映射mapping,转换成gridheader结构
*
* @param resultMapping of type Map<String, Object>
*/
private void processResultMapping(Map<String, Object> resultMapping) { private void processResultMapping(Map<String, Object> resultMapping) {
Set<Entry<String, Object>> entrySet = resultMapping.entrySet(); String resultType = ofNullable(resultMapping.get("resultType")).orElse("").toString();
this.setResultType(ofNullable(resultMapping.get("resultType")).orElse(EMPTY).toString()); if (StrUtil.isNotBlank(resultType)) {
this.setResultType(ClassUtil.loadClass(resultType));
}
resultMapping.remove("resultType"); resultMapping.remove("resultType");
Set<Entry<String, Object>> entrySet = resultMapping.entrySet();
for (Entry<String, Object> objectEntry : entrySet) { for (Entry<String, Object> objectEntry : entrySet) {
/*bean的字段名*/
String key = objectEntry.getKey(); String key = objectEntry.getKey();
/*key字段名对应的数据库列名或者为复杂类型的json object*/
Object value = objectEntry.getValue(); Object value = objectEntry.getValue();
JavaFieldProperty keyField = JavaFieldProperty.UNKOWN;
if (StrUtil.isNotBlank(resultType)) {
keyField = new JavaFieldProperty(ReflectUtil.getField(this.getResultType(), key));
}
keyField.setKey(key);
Class<?> valClass = ClassUtil.getClass(value); Class<?> valClass = ClassUtil.getClass(value);
if (List.class.isAssignableFrom(valClass)) { if (Collection.class.isAssignableFrom(valClass)) {
/*生成嵌套网格头,此嵌套网格头的类型对应集合字段*/ /*生成嵌套网格头,此嵌套的类型对应集合字段*/
Map<String, Object> nestedMapping = Map<String, Object> nestedMapping =
(Map<String, Object>) ((List) value).stream().findFirst().orElse(MapUtil.newHashMap(0)); (Map<String, Object>)
GridHeader nestedHeader = new GridHeader(nestedMapping); ((Collection) value).stream().findFirst().orElse(MapUtil.newHashMap(0));
nestedHeader.setIsCollection(true); GridHeader nestedHeader = new GridHeader(nestedMapping, this.getBelongMapping());
nestedHeader.setNestedPropName(key);
nestedHeader.setBelongMapping(this.getBelongMapping());
this.getNestedHeaders().add(nestedHeader);
nestedHeader.setParentHeader(this); nestedHeader.setParentHeader(this);
nestedHeader.setBelongNestedField(keyField);
this.getNestedHeaders().add(nestedHeader);
} else if (Map.class.isAssignableFrom(valClass)) { } else if (Map.class.isAssignableFrom(valClass)) {
/*生成嵌套网格头,此嵌套网格头的类型对应单个对象字段*/ /*生成嵌套网格头,此嵌套的类型对应单个对象字段*/
Map<String, Object> nestedMapping = (Map<String, Object>) value; Map<String, Object> nestedMapping = (Map<String, Object>) value;
GridHeader nestedHeader = new GridHeader(nestedMapping); GridHeader nestedHeader = new GridHeader(nestedMapping, this.getBelongMapping());
nestedHeader.setIsCollection(false);
nestedHeader.setNestedPropName(key);
nestedHeader.setBelongMapping(this.getBelongMapping());
this.getNestedHeaders().add(nestedHeader);
nestedHeader.setParentHeader(this); nestedHeader.setParentHeader(this);
} else if (isNotBlank(key) || (null != value && isNotBlank(String.valueOf(value)))) { nestedHeader.setBelongNestedField(keyField);
javaToJdbcMap.put(key, String.valueOf(value)); this.getNestedHeaders().add(nestedHeader);
} else if (isNotBlank(key)
|| (null != value && value instanceof String && isNotBlank(String.valueOf(value)))) {
/*非集合,非map类型的字段*/
DBColumnProperty columnProperty = new DBColumnProperty(String.valueOf(value));
columnProperty.setValue(String.valueOf(value));
fieldToColumnMap.put(keyField, columnProperty);
} }
} }
} }
......
...@@ -11,7 +11,7 @@ import java.io.Serializable; ...@@ -11,7 +11,7 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** 网格映射数据结构: 包含一个网格头 {@link GridHeader}和多个网格行{@link GridRow} */ /** 网格映射数据结构: 包含一个网格头 {@link GridHeader}和一个虚拟网格单元格 */
public class GridMapping implements Serializable { public class GridMapping implements Serializable {
/** 映射id */ /** 映射id */
String mappingId; String mappingId;
...@@ -22,7 +22,7 @@ public class GridMapping implements Serializable { ...@@ -22,7 +22,7 @@ public class GridMapping implements Serializable {
/** 网格头 */ /** 网格头 */
GridHeader header; GridHeader header;
List<GridRow> nestedRows = CollUtil.newArrayList(); GridCell virtualCell;
public GridMapping(Map<String, Object> resultMapping) { public GridMapping(Map<String, Object> resultMapping) {
JSON parse = JSONUtil.parse(resultMapping); JSON parse = JSONUtil.parse(resultMapping);
...@@ -32,7 +32,10 @@ public class GridMapping implements Serializable { ...@@ -32,7 +32,10 @@ public class GridMapping implements Serializable {
Assert.notBlank(resultType, "result mapping must have [resultType]."); Assert.notBlank(resultType, "result mapping must have [resultType].");
this.mappingId = id; this.mappingId = id;
this.resultType = resultType; this.resultType = resultType;
this.header = new GridHeader((Map<String, Object>) parse.getByPath("mapping")); this.setHeader(new GridHeader((Map<String, Object>) parse.getByPath("mapping"), this));
this.virtualCell=new GridCell();
this.virtualCell.setHasContainer(true);
this.virtualCell.setRelationGridHeader(this.getHeader());
} }
public GridHeader getHeader() { public GridHeader getHeader() {
...@@ -60,20 +63,11 @@ public class GridMapping implements Serializable { ...@@ -60,20 +63,11 @@ public class GridMapping implements Serializable {
this.resultType = resultType; this.resultType = resultType;
} }
public List<GridRow> getNestedRows() { public GridCell getVirtualCell() {
return nestedRows; return virtualCell;
} }
public void setNestedRows(List<GridRow> nestedRows) { public void setVirtualCell(GridCell virtualCell) {
this.nestedRows = nestedRows; this.virtualCell = virtualCell;
}
public GridRow nextRow(GridColumn column){
GridRow row = GridRow.generateRowByHeader(this.header);
/*给最外层的row设置一个空的列,为了后面的算法便利。可以理解成仅仅只是一个容器而已*/
column.getNestedRows().add(row);
row.setBelongColumn(column);
this.nestedRows.add(row);
return row;
} }
} }
package com.ibeetl.admin.core.conf.beetl.resultmap;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import java.io.Serializable;
import java.util.List;
/**
* 网格行,包含一个个网格列<br>
* 一个网格行,对应着SQL select查询出的一个Java的逻辑对象
*/
public class GridRow implements Serializable {
/** 包含的列,第0个列代表的是当前整个类的映射,从0列之后是内部对象字段的映射 */
List<GridColumn> nestedColumns = CollUtil.<GridColumn>newArrayList();
/** 所属的列 */
GridColumn belongColumn;
/** 映射对象的类型名 */
String resultType;
/** 通过每个列的key进行hash得到一个唯一row id */
Integer rowKey;
public GridRow() {}
public List<GridColumn> getNestedColumns() {
return nestedColumns;
}
public void setNestedColumns(List<GridColumn> nestedColumns) {
this.nestedColumns = nestedColumns;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public Integer getRowKey() {
return this.nestedColumns.get(0).getObjKey();
}
public GridColumn getBelongColumn() {
return belongColumn;
}
public void setBelongColumn(GridColumn belongColumn) {
this.belongColumn = belongColumn;
}
/**
* 根据网格头,生成对应的网格行结构。 行套列或者列套行再套列两种。
*
* @return
*/
public static GridRow generateRowByHeader(GridHeader gridHeader) {
if (ObjectUtil.isNull(gridHeader)) {
return null;
}
/*这是外层*/
GridRow gridRow = new GridRow();
/*这个列才是真正的存储数据值的*/
GridColumn gridColumn = new GridColumn();
gridRow.getNestedColumns().add(gridColumn);
gridColumn.setBelongRow(gridRow);
List<GridHeader> headers = gridHeader.getNestedHeaders();
for (GridHeader header : headers) {
/*这只是外部的一个容器性质的列,这个是内层*/
GridColumn containerColumn = new GridColumn();
GridRow nestedRow = generateRowByHeader(header);
containerColumn.getNestedRows().add(nestedRow);
nestedRow.setBelongColumn(containerColumn);
gridRow.getNestedColumns().add(containerColumn);
containerColumn.setBelongRow(gridRow);
containerColumn.setMappingHeader(header);
}
gridColumn.setMappingHeader(gridHeader);
gridColumn.setResultType(gridHeader.getResultType());
gridRow.setResultType(gridHeader.getResultType());
return gridRow;
}
public GridColumn findColumnByHeader(GridHeader header) {
for (GridColumn column : this.nestedColumns) {
if (ObjectUtil.equal(column.getMappingHeader(), header)) {
return column;
}
}
return null;
}
}
package com.ibeetl.admin.core.conf.beetl.resultmap; package com.ibeetl.admin.core.conf.beetl.resultmap;
import cn.hutool.core.util.ClassUtil; import static cn.hutool.core.util.ClassUtil.isAssignable;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.TypeUtil;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Set;
/**
* Class JavaFieldProperty : <br>
* 描述:对一个java bean 中的字段的简单描述
*
* @author 一日看尽长安花 Created on 2020/2/10
*/
public class JavaFieldProperty { public class JavaFieldProperty {
private String fieldName; /** 对应的字段 */
private Class fieldType; Field field;
private boolean isCollection; /** json映射中的key */
String key;
/*对应字段的属性描述*/
PropertyDescriptor propertyDescriptor;
/** 字段所在的bean type */
Class beanType;
/** 如果是集合字段,集合的泛型类型 */
Type listElementType;
/** 是否是集合字段 */
boolean isList;
static final JavaFieldProperty UNKOWN = new JavaFieldProperty();
private JavaFieldProperty() {}
public JavaFieldProperty(Field field) {
this.field = field;
Type genericType = this.getField().getGenericType();
listElementType = TypeUtil.getTypeArgument(genericType);
Class rawType = TypeUtil.getClass(genericType);
if (isAssignable(Collection.class, rawType)) {
isList = true;
} else if (isAssignable(Set.class, rawType)) {
isList = true;
} else {
isList = false;
}
beanType = this.getField().getDeclaringClass();
propertyDescriptor = BeanUtil.getPropertyDescriptor(beanType, field.getName());
}
public Field getField() {
return field;
}
public void setField(Field field) {
this.field = field;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public PropertyDescriptor getPropertyDescriptor() {
return propertyDescriptor;
}
public void setPropertyDescriptor(PropertyDescriptor propertyDescriptor) {
this.propertyDescriptor = propertyDescriptor;
}
public Class getBeanType() {
return beanType;
}
public void setBeanType(Class beanType) {
this.beanType = beanType;
}
public Type getListElementType() {
return listElementType;
}
public void setListElementType(Type listElementType) {
this.listElementType = listElementType;
}
public boolean isList() {
return isList;
}
public void setIsList(boolean isList) {
this.isList = isList;
}
} }
...@@ -23,25 +23,25 @@ RouteMapping ...@@ -23,25 +23,25 @@ RouteMapping
=== ===
```javascript ```javascript
var route_mapping_var={ var route_mapping_var={
"id": "core_route_map",
"mapping": { "mapping": {
"resultType": "com.ibeetl.admin.core.entity.CoreRoute",
"path": "path", "path": "path",
"name": "name",
"id": "id",
"parentId": "parent_id",
"seq": "seq",
"meta": { "meta": {
"resultType": "com.ibeetl.admin.core.entity.CoreRouteMeta",
"icon": "icon",
"title": "title",
"roles": [ "roles": [
{ {
"id": "role_id" "id": "role_id"
} }
], ]
"icon": "icon", }
"title": "title", }
"resultType": "com.ibeetl.admin.core.entity.CoreRouteMeta"
},
"name": "name",
"id": "id",
"resultType": "com.ibeetl.admin.core.entity.CoreRoute",
"parentId": "parent_id",
"seq": "seq"
},
"id": "core_route_map"
}; };
``` ```
......
<!-- <!--
* @Author: 一日看尽长安花 * @Author: 一日看尽长安花
* @since: 2019-10-12 16:14:37 * @since: 2019-10-12 16:14:37
* @LastEditTime : 2020-02-06 11:32:07 * @LastEditTime : 2020-02-22 17:32:45
* @LastEditors : 一日看尽长安花 * @LastEditors : 一日看尽长安花
* @Description: * @Description:
--> -->
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<el-table-column <el-table-column
v-for="(val, key) in visibleMetadata" v-for="(val, key) in visibleMetadata"
:key="key" :key="key"
:prop="val.json_path" :prop="val.json_path + '$' + val.type"
:label="val.name" :label="val.name"
:sortable="val.sortable" :sortable="val.sortable"
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
...@@ -139,11 +139,13 @@ export default { ...@@ -139,11 +139,13 @@ export default {
}, },
methods: { methods: {
handleTableSlot(scope) { handleTableSlot(scope) {
let val = this.$lodash.get(scope.row, scope.column.property); const splitProps = scope.column.property.split('$');
const isTimestamp = const valType = splitProps[1];
scope.column.property.endsWith('_time') && typeof val === 'number'; let val = this.$lodash.get(scope.row, splitProps[0]);
if (isTimestamp) { if (valType === 'date') {
val = parseTime(val / 1000, '{y}-{m}-{d} {h}:{i}:{s}'); val = parseTime(val / 1000, '{y}-{m}-{d} {h}:{i}:{s}');
} else if (valType === 'dict') {
val = val.name;
} }
return val; return val;
}, },
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment