mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 18:46:36 +08:00
同步到1.7版本
This commit is contained in:
@@ -48,7 +48,7 @@ public class DataSourceResolveAspect {
|
||||
resolver = ApplicationContextHolder.getBean(resolverClass);
|
||||
resolverMap.put(resolverClass, resolver);
|
||||
}
|
||||
int type = resolver.resolve(dsr.arg());
|
||||
int type = resolver.resolve(dsr.arg(), point.getArgs());
|
||||
// 通过判断 DataSource 中的值来判断当前方法应用哪个数据源
|
||||
DataSourceContextHolder.setDataSourceType(type);
|
||||
log.debug("set datasource is " + type);
|
||||
|
||||
@@ -560,16 +560,31 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
return mapper().getCountByCondition(this.tableName, whereClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据列表。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
*/
|
||||
@Override
|
||||
public void buildRelationForDataList(List<M> resultList, MyRelationParam relationParam) {
|
||||
this.buildRelationForDataList(resultList, relationParam, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
@Override
|
||||
public void buildRelationForDataList(List<M> resultList, MyRelationParam relationParam) {
|
||||
public void buildRelationForDataList(
|
||||
List<M> resultList, MyRelationParam relationParam, Set<String> ignoreFields) {
|
||||
if (relationParam == null || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
@@ -579,24 +594,24 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
boolean buildOneToOne = relationParam.isBuildOneToOne() || relationParam.isBuildOneToOneWithDict();
|
||||
// 这里集成一对一关联。
|
||||
if (buildOneToOne) {
|
||||
this.buildOneToOneForDataList(resultList, relationParam.isBuildOneToOneWithDict());
|
||||
this.buildOneToOneForDataList(resultList, relationParam.isBuildOneToOneWithDict(), ignoreFields);
|
||||
}
|
||||
// 集成一对多关联
|
||||
if (relationParam.isBuildOneToMany()) {
|
||||
this.buildOneToManyForDataList(resultList);
|
||||
this.buildOneToManyForDataList(resultList, ignoreFields);
|
||||
}
|
||||
// 这里集成字典关联
|
||||
if (relationParam.isBuildDict()) {
|
||||
// 构建常量字典关联关系
|
||||
this.buildConstDictForDataList(resultList);
|
||||
this.buildDictForDataList(resultList, buildOneToOne);
|
||||
this.buildConstDictForDataList(resultList, ignoreFields);
|
||||
this.buildDictForDataList(resultList, buildOneToOne, ignoreFields);
|
||||
}
|
||||
// 组装本地聚合计算关联数据
|
||||
if (relationParam.isBuildRelationAggregation()) {
|
||||
// 处理多对多场景下,根据主表的结果,进行从表聚合数据的计算。
|
||||
this.buildManyToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria());
|
||||
this.buildManyToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria(), ignoreFields);
|
||||
// 处理多一多场景下,根据主表的结果,进行从表聚合数据的计算。
|
||||
this.buildOneToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria());
|
||||
this.buildOneToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria(), ignoreFields);
|
||||
}
|
||||
} finally {
|
||||
GlobalThreadLocal.setDataFilter(dataFilterValue);
|
||||
@@ -621,6 +636,29 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
*/
|
||||
@Override
|
||||
public void buildRelationForDataList(List<M> resultList, MyRelationParam relationParam, int batchSize) {
|
||||
this.buildRelationForDataList(resultList, relationParam, batchSize, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询,批量导出没有分页机制,
|
||||
* 因此在导出数据量较大的情况下,很容易给数据库的内存、CPU和IO带来较大的压力。而通过
|
||||
* 我们的分批处理,可以极大的规避该问题的出现几率。调整batchSize的大小,也可以有效的
|
||||
* 改善运行效率。
|
||||
* 我们目前的处理机制是,先从主表取出所有符合条件的主表数据,这样可以避免分批处理时,
|
||||
* 后面几批数据,因为skip过多而带来的效率问题。因为是单表过滤,不会给数据库带来过大的压力。
|
||||
* 之后再在主表结果集数据上进行分批级联处理。
|
||||
* 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param batchSize 每批集成的记录数量。小于等于时将不做分批处理。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
@Override
|
||||
public void buildRelationForDataList(
|
||||
List<M> resultList, MyRelationParam relationParam, int batchSize, Set<String> ignoreFields) {
|
||||
if (CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
@@ -633,23 +671,38 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
int toIndex = Math.min(batchSize, totalCount);
|
||||
while (toIndex > fromIndex) {
|
||||
List<M> subResultList = resultList.subList(fromIndex, toIndex);
|
||||
this.buildRelationForDataList(subResultList, relationParam);
|
||||
this.buildRelationForDataList(subResultList, relationParam, ignoreFields);
|
||||
fromIndex = toIndex;
|
||||
toIndex = Math.min(batchSize + fromIndex, totalCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据对象。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param dataObject 主表实体对象。数据集成将直接作用于该对象。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param <T> 实体对象类型。
|
||||
*/
|
||||
@Override
|
||||
public <T extends M> void buildRelationForData(T dataObject, MyRelationParam relationParam) {
|
||||
this.buildRelationForData(dataObject, relationParam, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param dataObject 主表实体对象。数据集成将直接作用于该对象。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param <T> 实体对象类型。
|
||||
* @param dataObject 主表实体对象。数据集成将直接作用于该对象。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
* @param <T> 实体对象类型。
|
||||
*/
|
||||
@Override
|
||||
public <T extends M> void buildRelationForData(T dataObject, MyRelationParam relationParam) {
|
||||
public <T extends M> void buildRelationForData(T dataObject, MyRelationParam relationParam, Set<String> ignoreFields) {
|
||||
if (dataObject == null || relationParam == null) {
|
||||
return;
|
||||
}
|
||||
@@ -658,27 +711,27 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
// 集成本地一对一和字段级别的数据关联。
|
||||
boolean buildOneToOne = relationParam.isBuildOneToOne() || relationParam.isBuildOneToOneWithDict();
|
||||
if (buildOneToOne) {
|
||||
this.buildOneToOneForData(dataObject, relationParam.isBuildOneToOneWithDict());
|
||||
this.buildOneToOneForData(dataObject, relationParam.isBuildOneToOneWithDict(), ignoreFields);
|
||||
}
|
||||
// 集成一对多关联
|
||||
if (relationParam.isBuildOneToMany()) {
|
||||
this.buildOneToManyForData(dataObject);
|
||||
this.buildOneToManyForData(dataObject, ignoreFields);
|
||||
}
|
||||
if (relationParam.isBuildDict()) {
|
||||
// 构建常量字典关联关系
|
||||
this.buildConstDictForData(dataObject);
|
||||
this.buildConstDictForData(dataObject, ignoreFields);
|
||||
// 构建本地数据字典关联关系。
|
||||
this.buildDictForData(dataObject, buildOneToOne);
|
||||
this.buildDictForData(dataObject, buildOneToOne, ignoreFields);
|
||||
}
|
||||
// 组装本地聚合计算关联数据
|
||||
if (relationParam.isBuildRelationAggregation()) {
|
||||
// 开始处理多对多场景。
|
||||
buildManyToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria());
|
||||
buildManyToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria(), ignoreFields);
|
||||
// 构建一对多场景
|
||||
buildOneToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria());
|
||||
buildOneToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria(), ignoreFields);
|
||||
}
|
||||
if (relationParam.isBuildRelationManyToMany()) {
|
||||
this.buildRelationManyToMany(dataObject);
|
||||
this.buildRelationManyToMany(dataObject, ignoreFields);
|
||||
}
|
||||
} finally {
|
||||
GlobalThreadLocal.setDataFilter(dataFilterValue);
|
||||
@@ -688,13 +741,17 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
/**
|
||||
* 集成主表和多对多中间表之间的关联关系。
|
||||
*
|
||||
* @param dataObject 关联后的主表数据对象。
|
||||
* @param dataObject 关联后的主表数据对象。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private <T extends M> void buildRelationManyToMany(T dataObject) {
|
||||
private <T extends M> void buildRelationManyToMany(T dataObject, Set<String> ignoreFields) {
|
||||
if (dataObject == null || CollectionUtils.isEmpty(this.relationManyToManyStructList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationManyToManyStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
Example e = new Example(relationStruct.relationManyToMany.relationModelClass());
|
||||
e.createCriteria().andEqualTo(relationStruct.masterIdField.getName(), masterIdValue);
|
||||
@@ -706,13 +763,17 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
/**
|
||||
* 为实体对象参数列表数据集成本地静态字典关联数据。
|
||||
*
|
||||
* @param resultList 主表数据列表。
|
||||
* @param resultList 主表数据列表。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private void buildConstDictForDataList(List<M> resultList) {
|
||||
private void buildConstDictForDataList(List<M> resultList, Set<String> ignoreFields) {
|
||||
if (CollectionUtils.isEmpty(this.relationConstDictStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationConstDictStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
for (M dataObject : resultList) {
|
||||
Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (id != null) {
|
||||
@@ -731,13 +792,17 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
/**
|
||||
* 为参数实体对象数据集成本地静态字典关联数据。
|
||||
*
|
||||
* @param dataObject 实体对象。
|
||||
* @param dataObject 实体对象。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private <T extends M> void buildConstDictForData(T dataObject) {
|
||||
private <T extends M> void buildConstDictForData(T dataObject, Set<String> ignoreFields) {
|
||||
if (dataObject == null || CollectionUtils.isEmpty(this.relationConstDictStructList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationConstDictStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (id != null) {
|
||||
String name = relationStruct.dictMap.get(id);
|
||||
@@ -757,12 +822,16 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
* @param resultList 实体对象数据列表。
|
||||
* @param hasBuiltOneToOne 性能优化参数。如果该值为true,同时注解参数RelationDict.equalOneToOneRelationField
|
||||
* 不为空,则直接从已经完成一对一数据关联的从表对象中获取数据,减少一次数据库交互。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private void buildDictForDataList(List<M> resultList, boolean hasBuiltOneToOne) {
|
||||
private void buildDictForDataList(List<M> resultList, boolean hasBuiltOneToOne, Set<String> ignoreFields) {
|
||||
if (CollectionUtils.isEmpty(this.relationDictStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationDictStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
List<Object> relationList = null;
|
||||
if (hasBuiltOneToOne && relationStruct.equalOneToOneRelationField != null) {
|
||||
relationList = resultList.stream()
|
||||
@@ -790,12 +859,16 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
* @param dataObject 实体对象。
|
||||
* @param hasBuiltOneToOne 性能优化参数。如果该值为true,同时注解参数RelationDict.equalOneToOneRelationField
|
||||
* 不为空,则直接从已经完成一对一数据关联的从表对象中获取数据,减少一次数据库交互。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private <T extends M> void buildDictForData(T dataObject, boolean hasBuiltOneToOne) {
|
||||
private <T extends M> void buildDictForData(T dataObject, boolean hasBuiltOneToOne, Set<String> ignoreFields) {
|
||||
if (dataObject == null || CollectionUtils.isEmpty(this.relationDictStructList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationDictStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Object relationObject = null;
|
||||
if (hasBuiltOneToOne && relationStruct.equalOneToOneRelationField != null) {
|
||||
relationObject = ReflectUtil.getFieldValue(dataObject, relationStruct.equalOneToOneRelationField);
|
||||
@@ -813,14 +886,18 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
/**
|
||||
* 为实体对象参数列表数据集成本地一对一关联数据。
|
||||
*
|
||||
* @param resultList 实体对象数据列表。
|
||||
* @param withDict 关联从表数据后,是否把从表的字典数据也一起关联了。
|
||||
* @param resultList 实体对象数据列表。
|
||||
* @param withDict 关联从表数据后,是否把从表的字典数据也一起关联了。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private void buildOneToOneForDataList(List<M> resultList, boolean withDict) {
|
||||
private void buildOneToOneForDataList(List<M> resultList, boolean withDict, Set<String> ignoreFields) {
|
||||
if (CollectionUtils.isEmpty(this.relationOneToOneStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationOneToOneStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Set<Object> masterIdSet = resultList.stream()
|
||||
.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
|
||||
.filter(Objects::nonNull)
|
||||
@@ -839,9 +916,9 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
BaseService<Object, Object> proxyTarget =
|
||||
(BaseService<Object, Object>) AopTargetUtil.getTarget(relationService);
|
||||
// 关联本地字典。
|
||||
proxyTarget.buildDictForDataList(relationList, false);
|
||||
proxyTarget.buildDictForDataList(relationList, false, ignoreFields);
|
||||
// 关联常量字典
|
||||
proxyTarget.buildConstDictForDataList(relationList);
|
||||
proxyTarget.buildConstDictForDataList(relationList, ignoreFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -850,14 +927,18 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
/**
|
||||
* 为实体对象数据集成本地一对一关联数据。
|
||||
*
|
||||
* @param dataObject 实体对象。
|
||||
* @param withDict 关联从表数据后,是否把从表的字典数据也一起关联了。
|
||||
* @param dataObject 实体对象。
|
||||
* @param withDict 关联从表数据后,是否把从表的字典数据也一起关联了。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private void buildOneToOneForData(M dataObject, boolean withDict) {
|
||||
private void buildOneToOneForData(M dataObject, boolean withDict, Set<String> ignoreFields) {
|
||||
if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToOneStructList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationOneToOneStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (id != null) {
|
||||
BaseService<Object, Object> relationService = relationStruct.service;
|
||||
@@ -869,9 +950,9 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
BaseService<Object, Object> proxyTarget =
|
||||
(BaseService<Object, Object>) AopTargetUtil.getTarget(relationService);
|
||||
// 关联本地字典
|
||||
proxyTarget.buildDictForData(relationObject, false);
|
||||
proxyTarget.buildDictForData(relationObject, false, ignoreFields);
|
||||
// 关联常量字典
|
||||
proxyTarget.buildConstDictForData(relationObject);
|
||||
proxyTarget.buildConstDictForData(relationObject, ignoreFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -880,13 +961,17 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
/**
|
||||
* 为实体对象参数列表数据集成本地一对多关联数据。
|
||||
*
|
||||
* @param resultList 实体对象数据列表。
|
||||
* @param resultList 实体对象数据列表。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private void buildOneToManyForDataList(List<M> resultList) {
|
||||
private void buildOneToManyForDataList(List<M> resultList, Set<String> ignoreFields) {
|
||||
if (CollectionUtils.isEmpty(this.relationOneToManyStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationOneToManyStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Set<Object> masterIdSet = resultList.stream()
|
||||
.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
|
||||
.filter(Objects::nonNull)
|
||||
@@ -905,13 +990,17 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
/**
|
||||
* 为实体对象数据集成本地一对多关联数据。
|
||||
*
|
||||
* @param dataObject 实体对象。
|
||||
* @param dataObject 实体对象。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private void buildOneToManyForData(M dataObject) {
|
||||
private void buildOneToManyForData(M dataObject, Set<String> ignoreFields) {
|
||||
if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToManyStructList)) {
|
||||
return;
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationOneToManyStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (id != null) {
|
||||
BaseService<Object, Object> relationService = relationStruct.service;
|
||||
@@ -929,9 +1018,10 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
*
|
||||
* @param resultList 实体对象数据列表。
|
||||
* @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private void buildManyToManyAggregationForDataList(
|
||||
List<M> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
List<M> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap, Set<String> ignoreFields) {
|
||||
if (CollectionUtils.isEmpty(this.relationManyToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
@@ -939,6 +1029,9 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
criteriaListMap = new HashMap<>(this.relationManyToManyAggrStructList.size());
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Set<Object> masterIdSet = resultList.stream()
|
||||
.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
|
||||
.filter(Objects::nonNull)
|
||||
@@ -1000,9 +1093,10 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
*
|
||||
* @param dataObject 实体对象。
|
||||
* @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private <T extends M> void buildManyToManyAggregationForData(
|
||||
T dataObject, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
T dataObject, Map<String, List<MyWhereCriteria>> criteriaListMap, Set<String> ignoreFields) {
|
||||
if (dataObject == null || CollectionUtils.isEmpty(this.relationManyToManyAggrStructList)) {
|
||||
return;
|
||||
}
|
||||
@@ -1010,28 +1104,30 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
criteriaListMap = new HashMap<>(relationManyToManyAggrStructList.size());
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) {
|
||||
Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (masterIdValue == null) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
BasicAggregationRelationInfo basicRelationInfo =
|
||||
this.parseBasicAggregationRelationInfo(relationStruct, criteriaListMap);
|
||||
// 组装过滤条件
|
||||
String whereClause = this.makeManyToManyWhereClause(
|
||||
relationStruct, masterIdValue, basicRelationInfo, criteriaListMap);
|
||||
StringBuilder tableNames = new StringBuilder(64);
|
||||
tableNames.append(basicRelationInfo.relationTable);
|
||||
if (!basicRelationInfo.onlySelectRelationTable) {
|
||||
tableNames.append(", ").append(basicRelationInfo.slaveTable);
|
||||
}
|
||||
List<Map<String, Object>> aggregationMapList =
|
||||
mapper().getGroupedListByCondition(tableNames.toString(),
|
||||
basicRelationInfo.selectList, whereClause, basicRelationInfo.groupBy);
|
||||
// 将查询后的结果回填到主表数据中。
|
||||
if (CollectionUtils.isNotEmpty(aggregationMapList)) {
|
||||
Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE);
|
||||
if (value != null) {
|
||||
ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value);
|
||||
Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (masterIdValue != null) {
|
||||
BasicAggregationRelationInfo basicRelationInfo =
|
||||
this.parseBasicAggregationRelationInfo(relationStruct, criteriaListMap);
|
||||
// 组装过滤条件
|
||||
String whereClause = this.makeManyToManyWhereClause(
|
||||
relationStruct, masterIdValue, basicRelationInfo, criteriaListMap);
|
||||
StringBuilder tableNames = new StringBuilder(64);
|
||||
tableNames.append(basicRelationInfo.relationTable);
|
||||
if (!basicRelationInfo.onlySelectRelationTable) {
|
||||
tableNames.append(", ").append(basicRelationInfo.slaveTable);
|
||||
}
|
||||
List<Map<String, Object>> aggregationMapList =
|
||||
mapper().getGroupedListByCondition(tableNames.toString(),
|
||||
basicRelationInfo.selectList, whereClause, basicRelationInfo.groupBy);
|
||||
// 将查询后的结果回填到主表数据中。
|
||||
if (CollectionUtils.isNotEmpty(aggregationMapList)) {
|
||||
Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE);
|
||||
if (value != null) {
|
||||
ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1042,9 +1138,10 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
*
|
||||
* @param resultList 实体对象数据列表。
|
||||
* @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private void buildOneToManyAggregationForDataList(
|
||||
List<M> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
List<M> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap, Set<String> ignoreFields) {
|
||||
// 处理多一多场景下,根据主表的结果,进行从表聚合数据的计算。
|
||||
if (CollectionUtils.isEmpty(this.relationOneToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
@@ -1053,6 +1150,9 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size());
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
Set<Object> masterIdSet = resultList.stream()
|
||||
.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
|
||||
.filter(Objects::nonNull)
|
||||
@@ -1098,9 +1198,10 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
*
|
||||
* @param dataObject 实体对象。
|
||||
* @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
private <T extends M> void buildOneToManyAggregationForData(
|
||||
T dataObject, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
T dataObject, Map<String, List<MyWhereCriteria>> criteriaListMap, Set<String> ignoreFields) {
|
||||
if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToManyAggrStructList)) {
|
||||
return;
|
||||
}
|
||||
@@ -1108,29 +1209,31 @@ public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size());
|
||||
}
|
||||
for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) {
|
||||
Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (masterIdValue == null) {
|
||||
if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) {
|
||||
continue;
|
||||
}
|
||||
RelationOneToManyAggregation relation = relationStruct.relationOneToManyAggregation;
|
||||
String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass());
|
||||
String slaveColumnName =
|
||||
MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass());
|
||||
Tuple2<String, String> selectAndGroupByTuple = makeSelectListAndGroupByClause(
|
||||
slaveTable, slaveColumnName, relation.slaveModelClass(),
|
||||
slaveTable, relation.aggregationField(), relation.aggregationType());
|
||||
String selectList = selectAndGroupByTuple.getFirst();
|
||||
String groupBy = selectAndGroupByTuple.getSecond();
|
||||
String whereClause = this.makeOneToManyWhereClause(
|
||||
relationStruct, masterIdValue, slaveColumnName, criteriaListMap);
|
||||
// 获取分组聚合计算结果
|
||||
List<Map<String, Object>> aggregationMapList =
|
||||
mapper().getGroupedListByCondition(slaveTable, selectList, whereClause, groupBy);
|
||||
// 将计算结果回填到主表关联字段
|
||||
if (CollectionUtils.isNotEmpty(aggregationMapList)) {
|
||||
Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE);
|
||||
if (value != null) {
|
||||
ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value);
|
||||
Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (masterIdValue != null) {
|
||||
RelationOneToManyAggregation relation = relationStruct.relationOneToManyAggregation;
|
||||
String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass());
|
||||
String slaveColumnName =
|
||||
MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass());
|
||||
Tuple2<String, String> selectAndGroupByTuple = makeSelectListAndGroupByClause(
|
||||
slaveTable, slaveColumnName, relation.slaveModelClass(),
|
||||
slaveTable, relation.aggregationField(), relation.aggregationType());
|
||||
String selectList = selectAndGroupByTuple.getFirst();
|
||||
String groupBy = selectAndGroupByTuple.getSecond();
|
||||
String whereClause = this.makeOneToManyWhereClause(
|
||||
relationStruct, masterIdValue, slaveColumnName, criteriaListMap);
|
||||
// 获取分组聚合计算结果
|
||||
List<Map<String, Object>> aggregationMapList =
|
||||
mapper().getGroupedListByCondition(slaveTable, selectList, whereClause, groupBy);
|
||||
// 将计算结果回填到主表关联字段
|
||||
if (CollectionUtils.isNotEmpty(aggregationMapList)) {
|
||||
Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE);
|
||||
if (value != null) {
|
||||
ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,17 @@ public interface IBaseService<M, K> {
|
||||
*/
|
||||
void buildRelationForDataList(List<M> resultList, MyRelationParam relationParam);
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据列表。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
void buildRelationForDataList(List<M> resultList, MyRelationParam relationParam, Set<String> ignoreFields);
|
||||
|
||||
/**
|
||||
* 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询,批量导出没有分页机制,
|
||||
* 因此在导出数据量较大的情况下,很容易给数据库的内存、CPU和IO带来较大的压力。而通过
|
||||
@@ -217,6 +228,26 @@ public interface IBaseService<M, K> {
|
||||
*/
|
||||
void buildRelationForDataList(List<M> resultList, MyRelationParam relationParam, int batchSize);
|
||||
|
||||
/**
|
||||
* 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询,批量导出没有分页机制,
|
||||
* 因此在导出数据量较大的情况下,很容易给数据库的内存、CPU和IO带来较大的压力。而通过
|
||||
* 我们的分批处理,可以极大的规避该问题的出现几率。调整batchSize的大小,也可以有效的
|
||||
* 改善运行效率。
|
||||
* 我们目前的处理机制是,先从主表取出所有符合条件的主表数据,这样可以避免分批处理时,
|
||||
* 后面几批数据,因为skip过多而带来的效率问题。因为是单表过滤,不会给数据库带来过大的压力。
|
||||
* 之后再在主表结果集数据上进行分批级联处理。
|
||||
* 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param batchSize 每批集成的记录数量。小于等于时将不做分批处理。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
*/
|
||||
void buildRelationForDataList(
|
||||
List<M> resultList, MyRelationParam relationParam, int batchSize, Set<String> ignoreFields);
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
@@ -228,6 +259,18 @@ public interface IBaseService<M, K> {
|
||||
*/
|
||||
<T extends M> void buildRelationForData(T dataObject, MyRelationParam relationParam);
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据对象。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param dataObject 主表实体对象。数据集成将直接作用于该对象。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。
|
||||
* @param <T> 实体对象类型。
|
||||
*/
|
||||
<T extends M> void buildRelationForData(T dataObject, MyRelationParam relationParam, Set<String> ignoreFields);
|
||||
|
||||
/**
|
||||
* 仅仅在spring boot 启动后的监听器事件中调用,缓存所有service的关联关系,加速后续的数据绑定效率。
|
||||
*/
|
||||
|
||||
@@ -71,7 +71,6 @@ public class MyRelationParam {
|
||||
.buildDict(true)
|
||||
.buildOneToOneWithDict(true)
|
||||
.buildRelationAggregation(true)
|
||||
.buildOneToMany(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ public interface DataSourceResolver {
|
||||
/**
|
||||
* 动态解析方法。实现类可以根据当前的请求,或者上下文环境进行动态解析。
|
||||
*
|
||||
* @param arg 可选的入参。MyDataSourceResolver注解中的arg参数。
|
||||
* @param arg 可选的入参。MyDataSourceResolver注解中的arg参数。
|
||||
* @param methodArgs 被织入方法的所有参数。
|
||||
* @return 返回用于多数据源切换的类型值。DataSourceResolveAspect 切面方法会根据该返回值和配置信息,进行多数据源切换。
|
||||
*/
|
||||
int resolve(String arg);
|
||||
int resolve(String arg, Object[] methodArgs);
|
||||
}
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
package com.orange.demo.common.core.util;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.poi.excel.ExcelReader;
|
||||
import cn.hutool.poi.excel.ExcelUtil;
|
||||
import cn.hutool.poi.excel.sax.Excel07SaxReader;
|
||||
import com.orange.demo.common.core.constant.ApplicationConstant;
|
||||
import com.orange.demo.common.core.exception.MyRuntimeException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 导入工具类,目前支持xlsx和csv两种类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@Slf4j
|
||||
public class ImportUtil {
|
||||
|
||||
private static final String IMPORT_EXCEPTION_ERROR = "Failed to call ImportUtil.doImport";
|
||||
private static final String UNSUPPORT_FILE_EXT_ERROR = "不支持的导入文件类型!";
|
||||
/**
|
||||
* 同步导入方式。
|
||||
*
|
||||
* @param filename 导入文件名。
|
||||
* @return 导入数据列表。
|
||||
*/
|
||||
public static List<Map<String, Object>> doImport(String filename) {
|
||||
if (ApplicationConstant.XLSX_EXT.equals(FilenameUtils.getExtension(filename))) {
|
||||
try (ExcelReader reader = ExcelUtil.getReader(filename)) {
|
||||
return reader.readAll();
|
||||
}
|
||||
} else if (ApplicationConstant.CSV_EXT.equals(FilenameUtils.getExtension(filename))) {
|
||||
List<Map<String, Object>> resultList = new LinkedList<>();
|
||||
try (FileReader reader = new FileReader(filename)) {
|
||||
CSVParser parser = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader);
|
||||
Map<String, Integer> headerMap = parser.getHeaderMap();
|
||||
for (CSVRecord record : parser) {
|
||||
Map<String, Object> rowMap = new LinkedHashMap<>();
|
||||
for (final Map.Entry<String, Integer> header : headerMap.entrySet()) {
|
||||
int col = header.getValue();
|
||||
if (col < record.size()) {
|
||||
rowMap.put(header.getKey(), record.get(col));
|
||||
}
|
||||
}
|
||||
resultList.add(rowMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(IMPORT_EXCEPTION_ERROR, e);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
throw new MyRuntimeException(UNSUPPORT_FILE_EXT_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步导入方式,即SAX导入方式。
|
||||
*
|
||||
* @param filename 导入文件名。
|
||||
* @param importer 异步导入处理接口。
|
||||
* @throws IOException 文件处理异常。
|
||||
*/
|
||||
public static <T> void doImport(String filename, BaseImporter<T> importer) throws IOException {
|
||||
if (ApplicationConstant.XLSX_EXT.equals(FilenameUtils.getExtension(filename))) {
|
||||
Excel07SaxReader reader = new MyExcel07SaxReader<>(importer);
|
||||
try (InputStream in = new FileInputStream(filename)) {
|
||||
reader.read(in, 0);
|
||||
}
|
||||
} else if (ApplicationConstant.CSV_EXT.equals(FilenameUtils.getExtension(filename))) {
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
|
||||
int rowIndex = 0;
|
||||
do {
|
||||
String rowData = reader.readLine();
|
||||
if (StringUtils.isBlank(rowData)) {
|
||||
importer.doImport(-1, null);
|
||||
break;
|
||||
}
|
||||
String[] dataArray = StringUtils.split(rowData, ",");
|
||||
importer.doImport(rowIndex++, Arrays.asList(dataArray));
|
||||
} while (!importer.doInterrupt());
|
||||
} catch (Exception e) {
|
||||
log.error(IMPORT_EXCEPTION_ERROR, e);
|
||||
}
|
||||
}
|
||||
throw new MyRuntimeException(UNSUPPORT_FILE_EXT_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步导入抽象类。
|
||||
*
|
||||
* @param <T> 导入数据对象类型。
|
||||
*/
|
||||
public abstract static class BaseImporter<T> {
|
||||
private final Class<T> beanType;
|
||||
private final List<T> batchRowList = new LinkedList<>();
|
||||
private final int batchSize;
|
||||
private final Map<String, String> headerColumnMap;
|
||||
private Field[] fieldArray = null;
|
||||
|
||||
public BaseImporter(int batchSize, Class<T> beanType, Map<String, String> headerColumnMap) {
|
||||
if (batchSize <= 0) {
|
||||
batchSize = 100;
|
||||
}
|
||||
this.batchSize = batchSize;
|
||||
this.beanType = beanType;
|
||||
this.headerColumnMap = headerColumnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入操作执行函数。
|
||||
*
|
||||
* @param rowIndex 当前行号。
|
||||
* @param row 当前行数据列表对象。
|
||||
*/
|
||||
public void doImport(long rowIndex, List<Object> row) {
|
||||
if (row == null) {
|
||||
doProcess(batchRowList);
|
||||
doFinish();
|
||||
batchRowList.clear();
|
||||
return;
|
||||
}
|
||||
if (rowIndex <= 0) {
|
||||
fieldArray = new Field[row.size()];
|
||||
List<String> headerList = row.stream().map(Object::toString).collect(Collectors.toList());
|
||||
List<String> columnList = new ArrayList<>(row.size());
|
||||
for (String headerName : headerList) {
|
||||
String columnName = headerColumnMap.get(headerName);
|
||||
if (columnName != null) {
|
||||
columnList.add(columnName);
|
||||
}
|
||||
}
|
||||
columnList.stream()
|
||||
.map(columnName -> ReflectUtil.getField(beanType, columnName))
|
||||
.collect(Collectors.toList())
|
||||
.toArray(fieldArray);
|
||||
return;
|
||||
}
|
||||
T data;
|
||||
try {
|
||||
data = beanType.newInstance();
|
||||
for (int i = 0; i < row.size(); i++) {
|
||||
Object value = row.get(i);
|
||||
Field field = fieldArray[i];
|
||||
if (field != null) {
|
||||
ReflectUtil.setFieldValue(data, field, value);
|
||||
}
|
||||
}
|
||||
batchRowList.add(data);
|
||||
} catch (Exception e) {
|
||||
log.error(IMPORT_EXCEPTION_ERROR, e);
|
||||
}
|
||||
if (rowIndex % batchSize == 0) {
|
||||
doProcess(batchRowList);
|
||||
batchRowList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据处理进行中回调模板函数。
|
||||
*
|
||||
* @param batchRowList 一批数据行。
|
||||
*/
|
||||
public abstract void doProcess(List<T> batchRowList);
|
||||
|
||||
/**
|
||||
* 数据处理完毕回调模板函数。
|
||||
*/
|
||||
public abstract void doFinish();
|
||||
|
||||
/**
|
||||
* 数据处理终端标记模板函数。
|
||||
* @return 是否中断。true则中断后面的处理。
|
||||
*/
|
||||
public abstract boolean doInterrupt();
|
||||
}
|
||||
|
||||
static class MyExcel07SaxReader<T> extends Excel07SaxReader {
|
||||
private final BaseImporter<T> importer;
|
||||
|
||||
MyExcel07SaxReader(BaseImporter<T> importer) {
|
||||
super((sheetIndex, rowIndex, rowList) -> importer.doImport(rowIndex, rowList));
|
||||
this.importer = importer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
super.endElement(uri, localName, qName);
|
||||
if (importer.doInterrupt()) {
|
||||
throw new MyRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endDocument() {
|
||||
importer.doImport(-1, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private ImportUtil() {
|
||||
}
|
||||
}
|
||||
@@ -239,7 +239,8 @@ public class MyModelUtil {
|
||||
continue;
|
||||
}
|
||||
Field dictMapField = ReflectUtil.getField(r.constantDictClass(), "DICT_MAP");
|
||||
Map<Object, String> dictMap = (Map<Object, String>) ReflectUtil.getFieldValue(thisClazz, dictMapField);
|
||||
Map<Object, String> dictMap =
|
||||
(Map<Object, String>) ReflectUtil.getFieldValue(r.constantDictClass(), dictMapField);
|
||||
Object id = ReflectUtil.getFieldValue(thisModel, r.masterIdField());
|
||||
if (id != null) {
|
||||
String name = dictMap.get(id);
|
||||
@@ -253,6 +254,48 @@ public class MyModelUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 主Model类型中,遍历所有包含RelationConstDict注解的字段,并将关联的静态字典中的数据,
|
||||
* 填充到thisModelList集合元素对象的被注解字段中。
|
||||
*
|
||||
* @param thisClazz 主对象的Class对象。
|
||||
* @param thisModelList 主对象列表。
|
||||
* @param <T> 主表对象类型。
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> void makeConstDictRelation(Class<T> thisClazz, List<T> thisModelList) {
|
||||
if (CollectionUtils.isEmpty(thisModelList)) {
|
||||
return;
|
||||
}
|
||||
Field[] fields = ReflectUtil.getFields(thisClazz);
|
||||
for (Field field : fields) {
|
||||
// 这里不做任何空值判断,从而让配置错误在调试期间即可抛出
|
||||
Field thisTargetField = ReflectUtil.getField(thisClazz, field.getName());
|
||||
RelationConstDict r = thisTargetField.getAnnotation(RelationConstDict.class);
|
||||
if (r == null) {
|
||||
continue;
|
||||
}
|
||||
Field dictMapField = ReflectUtil.getField(r.constantDictClass(), "DICT_MAP");
|
||||
Map<Object, String> dictMap =
|
||||
(Map<Object, String>) ReflectUtil.getFieldValue(r.constantDictClass(), dictMapField);
|
||||
for (T thisModel : thisModelList) {
|
||||
if (thisModel == null) {
|
||||
continue;
|
||||
}
|
||||
Object id = ReflectUtil.getFieldValue(thisModel, r.masterIdField());
|
||||
if (id != null) {
|
||||
String name = dictMap.get(id);
|
||||
if (name != null) {
|
||||
Map<String, Object> m = new HashMap<>(2);
|
||||
m.put("id", id);
|
||||
m.put("name", name);
|
||||
ReflectUtil.setFieldValue(thisModel, thisTargetField, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在主Model类型中,根据thisRelationField字段的RelationDict注解参数,将被关联对象thatModel中的数据,
|
||||
* 关联到thisModel对象的thisRelationField字段中。
|
||||
|
||||
@@ -33,7 +33,7 @@ public class RedisKeyUtil {
|
||||
* @param sessionId 会话Id。
|
||||
* @return 会话存储于Redis中的键值。
|
||||
*/
|
||||
public static String makeSessionIdKeyForRedis(String sessionId) {
|
||||
public static String makeSessionIdKey(String sessionId) {
|
||||
return "SESSIONID__" + sessionId;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class RedisKeyUtil {
|
||||
* @param sessionId 会话Id。
|
||||
* @return 会话关联的权限数据存储于Redis中的键值。
|
||||
*/
|
||||
public static String makeSessionPermIdKeyForRedis(String sessionId) {
|
||||
public static String makeSessionPermIdKey(String sessionId) {
|
||||
return "PERM__" + sessionId;
|
||||
}
|
||||
|
||||
@@ -53,10 +53,20 @@ public class RedisKeyUtil {
|
||||
* @param sessionId 会话Id。
|
||||
* @return 会话关联的数据权限数据存储于Redis中的键值。
|
||||
*/
|
||||
public static String makeSessionDataPermIdKeyForRedis(String sessionId) {
|
||||
public static String makeSessionDataPermIdKey(String sessionId) {
|
||||
return "DATA_PERM__" + sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算在线表对象缓存在Redis中的键值。
|
||||
*
|
||||
* @param tableId 在线表主键Id。
|
||||
* @return 会话关联的数据权限数据存储于Redis中的键值。
|
||||
*/
|
||||
public static String makeOnlineTableKey(Long tableId) {
|
||||
return "ONLINE_TABLE_" + tableId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user