Commit c95491fc authored by zengchao's avatar zengchao
Browse files

将复杂结果集映射移入正式使用中,进行逐渐完善

parent a94f992a
...@@ -5,4 +5,4 @@ DELIMITER_STATEMENT_END= ...@@ -5,4 +5,4 @@ DELIMITER_STATEMENT_END=
#\u51FD\u6570\u6CE8\u518C #\u51FD\u6570\u6CE8\u518C
FN.isEmpty=org.beetl.ext.fn.EmptyExpressionFunction FN.isEmpty=org.beetl.ext.fn.EmptyExpressionFunction
FN.isNotEmpty=org.beetl.ext.fn.IsNotEmptyExpressionFunction FN.isNotEmpty=org.beetl.ext.fn.IsNotEmptyExpressionFunction
FN.mapping=com.ibeetl.admin.core.util.beetl.MappingFunction FN.mapping=com.ibeetl.admin.core.conf.handler.MappingFunction
package com.ibeetl.admin.core.conf; package com.ibeetl.admin.core.conf;
import cn.hutool.core.util.CharsetUtil;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.ibeetl.admin.core.conf.handler.DateTypeHandler; import com.ibeetl.admin.core.conf.handler.DateTypeHandler;
import com.ibeetl.admin.core.conf.handler.ZonedDateTimeTypeHandler; import com.ibeetl.admin.core.conf.handler.ZonedDateTimeTypeHandler;
import com.ibeetl.admin.core.conf.processor.JsonBeanProcessor;
import com.ibeetl.admin.core.rbac.DataAccess; import com.ibeetl.admin.core.rbac.DataAccess;
import com.ibeetl.admin.core.rbac.DataAccessFactory; import com.ibeetl.admin.core.rbac.DataAccessFactory;
import com.ibeetl.admin.core.service.CorePlatformService; import com.ibeetl.admin.core.service.CorePlatformService;
...@@ -10,7 +12,6 @@ import com.ibeetl.admin.core.util.beetl.DictQueryFunction; ...@@ -10,7 +12,6 @@ import com.ibeetl.admin.core.util.beetl.DictQueryFunction;
import com.ibeetl.admin.core.util.beetl.FileFunction; import com.ibeetl.admin.core.util.beetl.FileFunction;
import com.ibeetl.admin.core.util.beetl.FunAccessUrlFunction; import com.ibeetl.admin.core.util.beetl.FunAccessUrlFunction;
import com.ibeetl.admin.core.util.beetl.FunFunction; import com.ibeetl.admin.core.util.beetl.FunFunction;
import com.ibeetl.admin.core.util.beetl.MappingFunction;
import com.ibeetl.admin.core.util.beetl.MenuFunction; import com.ibeetl.admin.core.util.beetl.MenuFunction;
import com.ibeetl.admin.core.util.beetl.OrgFunction; import com.ibeetl.admin.core.util.beetl.OrgFunction;
import com.ibeetl.admin.core.util.beetl.RoleFunction; import com.ibeetl.admin.core.util.beetl.RoleFunction;
...@@ -28,22 +29,17 @@ import java.util.Date; ...@@ -28,22 +29,17 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.apache.commons.jexl2.internal.MapGetExecutor;
import org.beetl.core.Context; import org.beetl.core.Context;
import org.beetl.core.Function; import org.beetl.core.Function;
import org.beetl.core.GroupTemplate; import org.beetl.core.GroupTemplate;
import org.beetl.ext.simulate.WebSimulate; import org.beetl.ext.simulate.WebSimulate;
import org.beetl.sql.core.Interceptor; import org.beetl.sql.core.Interceptor;
import org.beetl.sql.core.InterceptorContext;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.engine.SQLPlaceholderST; import org.beetl.sql.core.engine.SQLPlaceholderST;
import org.beetl.sql.core.mapping.type.JavaSqlTypeHandler; import org.beetl.sql.core.mapping.type.JavaSqlTypeHandler;
import org.beetl.sql.ext.DebugInterceptor; import org.beetl.sql.ext.DebugInterceptor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -88,21 +84,34 @@ public class BeetlConf { ...@@ -88,21 +84,34 @@ public class BeetlConf {
}; };
} }
/**
* BeetlSql 多数据源
*
* @return
*/
@Bean @Bean
public BeetlSqlMutipleSourceCustomize beetlSqlMutipleSourceCustomize(){ public BeetlSqlMutipleSourceCustomize beetlSqlMutipleSourceCustomize() {
SQLPlaceholderST.textFunList.add("mapping"); SQLPlaceholderST.textFunList.add("mapping");
return (dataSource, manager) -> { return (dataSource, manager) -> {
/*bean转换处理器*/
JsonBeanProcessor jsonBeanProcessor = new JsonBeanProcessor(manager);
manager.setDefaultBeanProcessors(jsonBeanProcessor);
/*类型处理器*/
Map<Class, JavaSqlTypeHandler> typeHandlerMap = Map<Class, JavaSqlTypeHandler> typeHandlerMap =
manager.getDefaultBeanProcessors().getHandlers(); manager.getDefaultBeanProcessors().getHandlers();
/*Java bean的属性类型处理器,从数据库类型转化到属性Date类型*/ /*Java bean的属性类型处理器,从数据库类型转化到属性Date类型*/
typeHandlerMap.remove(Date.class); typeHandlerMap.remove(Date.class);
typeHandlerMap.put(Date.class, new DateTypeHandler()); typeHandlerMap.put(Date.class, new DateTypeHandler());
typeHandlerMap.put(ZonedDateTime.class, new ZonedDateTimeTypeHandler()); typeHandlerMap.put(ZonedDateTime.class, new ZonedDateTimeTypeHandler());
manager.setInters(new Interceptor[]{new StarterDebugInterceptor()}); /*拦截器*/
manager.setInters(new Interceptor[] {new StarterDebugInterceptor()});
}; };
} }
/**
* Beetl模板引擎的自定义配置
* @return
* */
@Bean @Bean
public BeetlTemplateCustomize beetlTemplateCustomize() { public BeetlTemplateCustomize beetlTemplateCustomize() {
return groupTemplate -> { return groupTemplate -> {
...@@ -128,16 +137,6 @@ public class BeetlConf { ...@@ -128,16 +137,6 @@ public class BeetlConf {
return platFormService.canAcessFunction(userId, orgId, functionCode); return platFormService.canAcessFunction(userId, orgId, functionCode);
}); });
groupTemplate.registerFunction(
"abcd",
new Function() {
@Override
public Boolean call(Object[] paras, Context ctx) {
return true;
}
});
groupTemplate.registerFunction( groupTemplate.registerFunction(
"env", "env",
new Function() { new Function() {
...@@ -157,7 +156,7 @@ public class BeetlConf { ...@@ -157,7 +156,7 @@ public class BeetlConf {
protected String getStr(String str) { protected String getStr(String str) {
try { try {
return new String(str.getBytes("iso8859-1"), "UTF-8"); return new String(str.getBytes(CharsetUtil.ISO_8859_1), CharsetUtil.UTF_8);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
...@@ -177,8 +176,13 @@ public class BeetlConf { ...@@ -177,8 +176,13 @@ public class BeetlConf {
} }
static class StarterDebugInterceptor extends DebugInterceptor { static class StarterDebugInterceptor extends DebugInterceptor {
private Logger logger= LoggerFactory.getLogger("beetlsql"); private Logger logger = LoggerFactory.getLogger("beetlsql");
/**
* 将内置生成的SQL排除打印
* @param sqlId
* @return
*/
@Override @Override
protected boolean isSimple(String sqlId) { protected boolean isSimple(String sqlId) {
if (sqlId.indexOf("_gen_") != -1) { if (sqlId.indexOf("_gen_") != -1) {
......
package com.ibeetl.admin.core.util.beetl; package com.ibeetl.admin.core.conf.handler;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil; import com.ibeetl.admin.core.conf.resultmap.GridMapping;
import com.ibeetl.admin.core.util.CacheUtil; import com.ibeetl.admin.core.util.CacheUtil;
import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.beetl.core.Context; import org.beetl.core.Context;
import org.beetl.core.Function; import org.beetl.core.Function;
import org.beetl.core.GroupTemplate; import org.beetl.core.GroupTemplate;
import org.beetl.core.ResourceLoader;
import org.beetl.core.resource.StringTemplateResourceLoader; import org.beetl.core.resource.StringTemplateResourceLoader;
import org.beetl.sql.core.SQLManager; import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.SQLResult; import org.beetl.sql.core.SQLResult;
...@@ -20,13 +18,14 @@ import org.beetl.sql.core.SQLResult; ...@@ -20,13 +18,14 @@ import org.beetl.sql.core.SQLResult;
public class MappingFunction implements Function { public class MappingFunction implements Function {
private static final StringWriter STRING_WRITER = new StringWriter(); private static final StringWriter STRING_WRITER = new StringWriter();
private static final StringTemplateResourceLoader STRING_TEMPLATE_RESOURCE_LOADER = new StringTemplateResourceLoader(); private static final StringTemplateResourceLoader STRING_TEMPLATE_RESOURCE_LOADER =
new StringTemplateResourceLoader();
@Override @Override
public Object call(Object[] paras, Context ctx) { public Object call(Object[] paras, Context ctx) {
String currentSqlId = ctx.getGlobal("_id").toString(); String currentSqlId = ctx.getGlobal("_id").toString();
Object cache = CacheUtil.get(currentSqlId); Object cache = CacheUtil.get(currentSqlId);
if(ObjectUtil.isNotNull(cache)){ if (ObjectUtil.isNotNull(cache)) {
return StrUtil.EMPTY; return StrUtil.EMPTY;
} }
String sqlSegmentId = (String) paras[0]; String sqlSegmentId = (String) paras[0];
...@@ -43,10 +42,10 @@ public class MappingFunction implements Function { ...@@ -43,10 +42,10 @@ public class MappingFunction implements Function {
/*获取参数指定的sqlid所在的md文件名*/ /*获取参数指定的sqlid所在的md文件名*/
String file = this.getParentId(ctx); String file = this.getParentId(ctx);
SQLResult result; SQLResult result;
if(sqlSegmentId.indexOf(".")==-1){ if (sqlSegmentId.indexOf(".") == -1) {
/*同一个md文件的sql段*/ /*同一个md文件的sql段*/
result = sm.getSQLResult(file + "." + sqlSegmentId, inputParas, ctx); result = sm.getSQLResult(file + "." + sqlSegmentId, inputParas, ctx);
}else { } else {
/*另一个md文件的sql段*/ /*另一个md文件的sql段*/
result = sm.getSQLResult(sqlSegmentId, inputParas, ctx); result = sm.getSQLResult(sqlSegmentId, inputParas, ctx);
} }
...@@ -61,8 +60,9 @@ public class MappingFunction implements Function { ...@@ -61,8 +60,9 @@ public class MappingFunction implements Function {
result.jdbcSql, inputParas, STRING_WRITER, STRING_TEMPLATE_RESOURCE_LOADER); result.jdbcSql, inputParas, STRING_WRITER, STRING_TEMPLATE_RESOURCE_LOADER);
if (MapUtil.isNotEmpty(rsMap)) { if (MapUtil.isNotEmpty(rsMap)) {
/*TODO 待移到非测试代码中,重写为保持GridMapping,而不是保持Map*/ GridMapping mapping =
CacheUtil.put(currentSqlId, rsMap.values().stream().findFirst().get()); new GridMapping((Map<String, Object>) rsMap.values().stream().findFirst().get());
CacheUtil.put(currentSqlId, mapping);
} }
return StrUtil.EMPTY; return StrUtil.EMPTY;
......
package com.ibeetl.admin.core.conf.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.conf.resultmap.GridColumn;
import com.ibeetl.admin.core.conf.resultmap.GridHeader;
import com.ibeetl.admin.core.conf.resultmap.GridMapping;
import com.ibeetl.admin.core.conf.resultmap.GridRow;
import com.ibeetl.admin.core.util.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;
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();
}
}
/**
* 将ResultSet映射为一个POJO对象
*
* @param rs
* @param type
* @return
* @throws SQLException
*/
@Override
public <T> T toBean(String sqlId, ResultSet rs, Class<T> type) throws SQLException {
List<T> results = new ArrayList<T>();
PropertyDescriptor[] props = this.propertyDescriptors(type);
ResultSetMetaData rsmd = rs.getMetaData();
int[] columnToProperty = this.mapColumnsToProperties(type, rsmd, props);
GridMapping mapping = (GridMapping) CacheUtil.get(sqlId);
if (null == mapping) {
/*无映射的情况下使用beetlsql默认自带的映射*/
do {
super.createBean(sqlId, rs, type, props, columnToProperty);
} while (rs.next());
} else {
/*复杂结果集映射,取消TailBean的便利性*/
rs.absolute(0);
fillMappingRow(rs, mapping);
results = convertMapping(mapping, type);
}
return CollUtil.getFirst(results);
}
/**
*
* 将ResultSet映射为一个List&lt;POJO&gt;集合
* @param sqlId
* @param rs
* @param type
* @param <T>
* @return
* @throws SQLException
*/
@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);
GridMapping mapping = (GridMapping) CacheUtil.get(sqlId);
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 com.ibeetl.admin.core.conf.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 com.ibeetl.admin.core.conf.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 com.ibeetl.admin.core.conf.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 com.ibeetl.admin.core.conf.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;
}
}
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