mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 18:46:36 +08:00
commit:同步1.3版本
This commit is contained in:
@@ -98,12 +98,12 @@
|
||||
<orderEntry type="library" name="Maven: tk.mybatis:mapper-spring:1.1.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: tk.mybatis:mapper-extra:1.1.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: tk.mybatis:mapper-spring-boot-autoconfigure:2.1.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.2.13" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.2.13" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.1.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:2.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.2.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:3.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-freemarker:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.29" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.2.4.RELEASE" level="project" />
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.orange.demo.common.core.advice;
|
||||
|
||||
import com.orange.demo.common.core.exception.*;
|
||||
import com.orange.demo.common.core.constant.ErrorCodeEnum;
|
||||
import com.orange.demo.common.core.exception.RedisCacheAccessException;
|
||||
import com.orange.demo.common.core.object.ResponseResult;
|
||||
import com.orange.demo.common.core.util.ContextUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -52,11 +52,19 @@ public @interface RelationDict {
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象名称。
|
||||
* 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。
|
||||
*
|
||||
* @return 被关联的本地Service对象名称。
|
||||
*/
|
||||
String slaveServiceName() default "";
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象CLass类型。
|
||||
*
|
||||
* @return 被关联的本地Service对象CLass类型。
|
||||
*/
|
||||
Class<?> slaveServiceClass() default DummyClass.class;
|
||||
|
||||
/**
|
||||
* 在同一个实体对象中,如果有一对一关联和字典关联,都是基于相同的主表字段,并关联到
|
||||
* 相同关联表的同一关联字段时,可以在字典关联的注解中引用被一对一注解标准的对象属性。
|
||||
|
||||
@@ -24,11 +24,19 @@ public @interface RelationManyToManyAggregation {
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象名称。
|
||||
* 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。
|
||||
*
|
||||
* @return 被关联的本地Service对象名称。
|
||||
*/
|
||||
String slaveServiceName() default "";
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象CLass类型。
|
||||
*
|
||||
* @return 被关联的本地Service对象CLass类型。
|
||||
*/
|
||||
Class<?> slaveServiceClass() default DummyClass.class;
|
||||
|
||||
/**
|
||||
* 多对多从表Model对象的Class对象。
|
||||
*
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.orange.demo.common.core.annotation;
|
||||
|
||||
import com.orange.demo.common.core.object.DummyClass;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 标识Model之间的一对多关联关系。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-08-08
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RelationOneToMany {
|
||||
|
||||
/**
|
||||
* 当前对象的关联Id字段名称。
|
||||
*
|
||||
* @return 当前对象的关联Id字段名称。
|
||||
*/
|
||||
String masterIdField();
|
||||
|
||||
/**
|
||||
* 被关联Model对象的Class对象。
|
||||
*
|
||||
* @return 被关联Model对象的Class对象。
|
||||
*/
|
||||
Class<?> slaveModelClass();
|
||||
|
||||
/**
|
||||
* 被关联Model对象的关联Id字段名称。
|
||||
*
|
||||
* @return 被关联Model对象的关联Id字段名称。
|
||||
*/
|
||||
String slaveIdField();
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象名称。
|
||||
* 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。
|
||||
*
|
||||
* @return 被关联的本地Service对象名称。
|
||||
*/
|
||||
String slaveServiceName() default "";
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象CLass类型。
|
||||
*
|
||||
* @return 被关联的本地Service对象CLass类型。
|
||||
*/
|
||||
Class<?> slaveServiceClass() default DummyClass.class;
|
||||
}
|
||||
@@ -24,11 +24,19 @@ public @interface RelationOneToManyAggregation {
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象名称。
|
||||
* 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。
|
||||
*
|
||||
* @return 被关联的本地Service对象名称。
|
||||
*/
|
||||
String slaveServiceName() default "";
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象CLass类型。
|
||||
*
|
||||
* @return 被关联的本地Service对象CLass类型。
|
||||
*/
|
||||
Class<?> slaveServiceClass() default DummyClass.class;
|
||||
|
||||
/**
|
||||
* 被关联Model对象的Class对象。
|
||||
*
|
||||
|
||||
@@ -45,11 +45,19 @@ public @interface RelationOneToOne {
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象名称。
|
||||
* 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。
|
||||
*
|
||||
* @return 被关联的本地Service对象名称。
|
||||
*/
|
||||
String slaveServiceName() default "";
|
||||
|
||||
/**
|
||||
* 被关联的本地Service对象CLass类型。
|
||||
*
|
||||
* @return 被关联的本地Service对象CLass类型。
|
||||
*/
|
||||
Class<?> slaveServiceClass() default DummyClass.class;
|
||||
|
||||
/**
|
||||
* 在一对一关联时,是否加载从表的字典关联。
|
||||
*
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.orange.demo.common.core.aop;
|
||||
|
||||
import com.orange.demo.common.core.base.service.BaseDictService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 字典缓存同步的AOP。该AOP的优先级必须比事务切面的优先级高,因此会在事务外执行该切面的代码。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-08-08
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 1)
|
||||
@Slf4j
|
||||
public class DictCacheSyncAop {
|
||||
|
||||
/**
|
||||
* BaseDictService 字典服务父类中的字典数据增删改的方法。
|
||||
*/
|
||||
@Pointcut("execution(public * com.orange.demo..BaseDictService.saveNew (..)) " +
|
||||
"|| execution(public * com.orange.demo..BaseDictService.update (..)) " +
|
||||
"|| execution(public * com.orange.demo..BaseDictService.remove (..))" )
|
||||
public void baseDictServicePointCut() {
|
||||
// 空注释,避免sonar警告
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Around("baseDictServicePointCut()")
|
||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
String methodName = joinPoint.getSignature().getName();
|
||||
Object arg = joinPoint.getArgs()[0];
|
||||
if ("saveNew".equals(methodName)) {
|
||||
Object data = joinPoint.proceed();
|
||||
BaseDictService<Object, Object> service =
|
||||
(BaseDictService<Object, Object>) joinPoint.getTarget();
|
||||
// 这里参数必须使用saveNew方法的返回对象,因为里面包含实际主键值。
|
||||
service.putDictionaryCache(data);
|
||||
return data;
|
||||
} else if ("update".equals(methodName)) {
|
||||
Object data = joinPoint.proceed();
|
||||
BaseDictService<Object, Object> service =
|
||||
(BaseDictService<Object, Object>) joinPoint.getTarget();
|
||||
// update的方法返回的是boolean,因此这里的参数需要使用第一个参数即可。
|
||||
service.putDictionaryCache(arg);
|
||||
return data;
|
||||
} else {
|
||||
// remove
|
||||
BaseDictService<Object, Object> service =
|
||||
(BaseDictService<Object, Object>) joinPoint.getTarget();
|
||||
service.removeDictionaryCache(arg);
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package com.orange.demo.common.core.base.controller;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.orange.demo.common.core.base.mapper.BaseModelMapper;
|
||||
import com.orange.demo.common.core.base.service.BaseService;
|
||||
import com.orange.demo.common.core.base.service.IBaseService;
|
||||
import com.orange.demo.common.core.constant.AggregationKind;
|
||||
import com.orange.demo.common.core.constant.AggregationType;
|
||||
import com.orange.demo.common.core.constant.ErrorCodeEnum;
|
||||
@@ -42,22 +42,22 @@ public abstract class BaseController<M, V, K> {
|
||||
/**
|
||||
* 当前Service关联的主Model实体对象的Class。
|
||||
*/
|
||||
protected Class<M> modelClass;
|
||||
protected final Class<M> modelClass;
|
||||
/**
|
||||
* 当前Service关联的主model的VO对象的Class。
|
||||
*/
|
||||
protected Class<V> domainVoClass;
|
||||
protected final Class<V> domainVoClass;
|
||||
/**
|
||||
* 当前Service关联的主Model对象主键字段名称。
|
||||
*/
|
||||
protected String idFieldName;
|
||||
|
||||
/**
|
||||
* 获取子类中注入的BaseService类。
|
||||
* 获取子类中注入的IBaseService接口。
|
||||
*
|
||||
* @return 子类中注入的BaseService类。
|
||||
*/
|
||||
protected abstract BaseService<M, K> service();
|
||||
protected abstract IBaseService<M, K> service();
|
||||
|
||||
/**
|
||||
* 构造函数。
|
||||
@@ -95,7 +95,7 @@ public abstract class BaseController<M, V, K> {
|
||||
return ResponseResult.success(resultVoList);
|
||||
}
|
||||
if (Boolean.TRUE.equals(withDict)) {
|
||||
service().buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null);
|
||||
service().buildRelationForDataList(resultList, MyRelationParam.dictOnly());
|
||||
}
|
||||
resultVoList = convertToVoList(resultList, modelMapper);
|
||||
return ResponseResult.success(resultVoList);
|
||||
@@ -120,7 +120,7 @@ public abstract class BaseController<M, V, K> {
|
||||
return ResponseResult.success(resultVoObject);
|
||||
}
|
||||
if (Boolean.TRUE.equals(withDict)) {
|
||||
service().buildRelationForData(resultObject, MyRelationParam.dictOnly(), null);
|
||||
service().buildRelationForData(resultObject, MyRelationParam.dictOnly());
|
||||
}
|
||||
resultVoObject = this.convertToVo(resultObject, modelMapper);
|
||||
return ResponseResult.success(resultVoObject);
|
||||
@@ -197,7 +197,7 @@ public abstract class BaseController<M, V, K> {
|
||||
totalCount = resultList.size();
|
||||
}
|
||||
if (queryParam.getWithDict()) {
|
||||
service().buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null);
|
||||
service().buildRelationForDataList(resultList, MyRelationParam.dictOnly());
|
||||
}
|
||||
List<V> resultVoList = convertToVoList(resultList, modelMapper);
|
||||
return ResponseResult.success(new MyPageData<>(resultVoList, totalCount));
|
||||
|
||||
@@ -86,7 +86,7 @@ public interface BaseModelMapper<D, M> {
|
||||
* @return 转换后的bean对象。
|
||||
*/
|
||||
default <T> T mapToBean(Map<String, Object> map, Class<T> beanClazz) {
|
||||
return BeanUtil.mapToBean(map, beanClazz, true);
|
||||
return BeanUtil.toBeanIgnoreError(map, beanClazz);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +102,7 @@ public interface BaseModelMapper<D, M> {
|
||||
return new LinkedList<>();
|
||||
}
|
||||
return mapList.stream()
|
||||
.map(m -> BeanUtil.mapToBean(m, beanClazz, true))
|
||||
.map(m -> BeanUtil.toBeanIgnoreError(m, beanClazz))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package com.orange.demo.common.core.base.service;
|
||||
|
||||
import com.orange.demo.common.core.cache.DictionaryCache;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.orange.demo.common.core.constant.GlobalDeletedFlag;
|
||||
import com.orange.demo.common.core.exception.MyRuntimeException;
|
||||
import com.orange.demo.common.core.cache.DictionaryCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import tk.mybatis.mapper.entity.Example;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 带有缓存功能的字典Service基类,需要留意的是,由于缓存基于Key/Value方式存储,
|
||||
@@ -19,7 +21,7 @@ import java.util.List;
|
||||
* @date 2020-08-08
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseDictService<M, K> extends BaseService<M, K> {
|
||||
public abstract class BaseDictService<M, K> extends BaseService<M, K> implements IBaseDictService<M, K> {
|
||||
|
||||
/**
|
||||
* 缓存池对象。
|
||||
@@ -38,6 +40,7 @@ public abstract class BaseDictService<M, K> extends BaseService<M, K> {
|
||||
*
|
||||
* @return true表示启动即可加载数据,false需要手动调用loadCachedData进行加载。
|
||||
*/
|
||||
@Override
|
||||
public boolean loadOnStartup() {
|
||||
return true;
|
||||
}
|
||||
@@ -45,6 +48,7 @@ public abstract class BaseDictService<M, K> extends BaseService<M, K> {
|
||||
/**
|
||||
* 加载全部数据到内存,缓存的key只能为映射表的主键。
|
||||
*/
|
||||
@Override
|
||||
public void loadCachedData() {
|
||||
if (loadOnStartup()) {
|
||||
reloadCachedData(false);
|
||||
@@ -56,6 +60,7 @@ public abstract class BaseDictService<M, K> extends BaseService<M, K> {
|
||||
*
|
||||
* @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。
|
||||
*/
|
||||
@Override
|
||||
public void reloadCachedData(boolean force) {
|
||||
// 在非强制刷新情况下。
|
||||
// 先行判断缓存中是否存在数据,如果有就不加载了。
|
||||
@@ -67,14 +72,76 @@ public abstract class BaseDictService<M, K> extends BaseService<M, K> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接从缓存池中获取主键Id关联的数据。
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param data 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public M saveNew(M data) {
|
||||
if (deletedFlagFieldName != null) {
|
||||
try {
|
||||
setDeletedFlagMethod.invoke(data, GlobalDeletedFlag.NORMAL);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call reflection [setDeletedFlagMethod] in BaseDictService.saveNew.", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
mapper().insert(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据对象。
|
||||
*
|
||||
* @param data 更新的对象。
|
||||
* @param originalData 原有数据对象。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean update(M data, M originalData) {
|
||||
if (deletedFlagFieldName != null) {
|
||||
try {
|
||||
setDeletedFlagMethod.invoke(data, GlobalDeletedFlag.NORMAL);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call reflection [setDeletedFlagMethod] in BaseDictService.update.", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
return mapper().updateByPrimaryKey(data) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param id 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean remove(K id) {
|
||||
return this.removeById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接从缓存池中获取主键Id关联的数据。如果缓存中不存在,再从数据库中取出并回写到缓存。
|
||||
*
|
||||
* @param id 主键Id。
|
||||
* @return 主键关联的数据,不存在返回null。
|
||||
*/
|
||||
@Override
|
||||
public M getById(K id) {
|
||||
return dictionaryCache.get(id);
|
||||
M data = dictionaryCache.get(id);
|
||||
if (data != null) {
|
||||
return data;
|
||||
}
|
||||
data = super.getById(id);
|
||||
if (data != null) {
|
||||
this.dictionaryCache.put(id, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,19 +150,54 @@ public abstract class BaseDictService<M, K> extends BaseService<M, K> {
|
||||
* @return 返回所有数据。
|
||||
*/
|
||||
@Override
|
||||
public List<M> getAllList() {
|
||||
public List<M> getAllListFromCache() {
|
||||
return dictionaryCache.getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接从缓存池中返回符合主键 in (idValues) 条件的所有数据。
|
||||
* 对于缓存中不存在的数据,从数据库中获取并回写入缓存。
|
||||
*
|
||||
* @param idValues 主键值集合。
|
||||
* @param idValues 主键值列表。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<M> getInList(Set<K> idValues) {
|
||||
return dictionaryCache.getInList(idValues);
|
||||
List<M> resultList = dictionaryCache.getInList(idValues);
|
||||
if (resultList.size() == idValues.size()) {
|
||||
return resultList;
|
||||
}
|
||||
Set<K> cachedIdList = new HashSet<>();
|
||||
for (M data : resultList) {
|
||||
try {
|
||||
cachedIdList.add((K) getIdFieldMethod.invoke(data));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call reflection method in BaseDictService.getInList.", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
// 找到未缓存的数据,然后从数据库读取后缓存。
|
||||
Set<K> uncachedIdList = new HashSet<>();
|
||||
for (K id : idValues) {
|
||||
if (!cachedIdList.contains(id)) {
|
||||
uncachedIdList.add(id);
|
||||
}
|
||||
}
|
||||
List<M> uncachedResultList = super.getInList(uncachedIdList);
|
||||
if (CollectionUtils.isNotEmpty(uncachedResultList)) {
|
||||
for (M data : uncachedResultList) {
|
||||
try {
|
||||
K id = (K) getIdFieldMethod.invoke(data);
|
||||
this.dictionaryCache.put(id, data);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call reflection method in BaseDictService.getInList.", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
resultList.addAll(uncachedResultList);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,13 +207,13 @@ public abstract class BaseDictService<M, K> extends BaseService<M, K> {
|
||||
* @param inFilterValues 参与(In-list)过滤的Java字段值集合。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> List<M> getInList(String inFilterField, Set<T> inFilterValues) {
|
||||
if (inFilterField.equals(this.idFieldName)) {
|
||||
return this.getInList((Set<K>) inFilterValues);
|
||||
}
|
||||
return this.getInList(inFilterField, inFilterValues, (String) null);
|
||||
return this.getInList(inFilterField, inFilterValues);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,28 +223,48 @@ public abstract class BaseDictService<M, K> extends BaseService<M, K> {
|
||||
* @param inFilterValues 数据值集合。
|
||||
* @return 全部存在返回true,否则false。
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> boolean existUniqueKeyList(String inFilterField, Set<T> inFilterValues) {
|
||||
if (CollectionUtils.isEmpty(inFilterValues)) {
|
||||
return true;
|
||||
}
|
||||
if (inFilterField.equals(this.idFieldName)) {
|
||||
List<M> dataList = dictionaryCache.getInList((Set<K>) inFilterValues);
|
||||
List<M> dataList = this.getInList((Set<K>) inFilterValues);
|
||||
return dataList.size() == inFilterValues.size();
|
||||
}
|
||||
Example e = this.makeDefaultInListExample(inFilterField, inFilterValues, null);
|
||||
if (deletedFlagFieldName != null) {
|
||||
e.and().andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL);
|
||||
}
|
||||
return mapper().selectCountByExample(e) == inFilterValues.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 存入缓存。
|
||||
*
|
||||
* @param data 新增或更新数据。
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void putDictionaryCache(M data) {
|
||||
K key = (K) ReflectUtil.getFieldValue(data, idFieldName);
|
||||
this.dictionaryCache.put(key, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典主键将数据从缓存中删除。
|
||||
*
|
||||
* @param id 字典主键。
|
||||
*/
|
||||
@Override
|
||||
public void removeDictionaryCache(K id) {
|
||||
this.dictionaryCache.invalidate(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存中的数据数量。
|
||||
*
|
||||
* @return 缓存中的数据总量。
|
||||
*/
|
||||
@Override
|
||||
public int getCachedCount() {
|
||||
return dictionaryCache.getCount();
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@ import com.orange.demo.common.core.util.AopTargetUtil;
|
||||
import com.orange.demo.common.core.util.ApplicationContextHolder;
|
||||
import com.orange.demo.common.core.util.MyModelUtil;
|
||||
import com.orange.demo.common.core.util.LogMessageUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import tk.mybatis.mapper.entity.Example;
|
||||
|
||||
import javax.persistence.Column;
|
||||
@@ -43,16 +45,20 @@ import static java.util.stream.Collectors.*;
|
||||
* @date 2020-08-08
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseService<M, K> {
|
||||
|
||||
public abstract class BaseService<M, K> implements IBaseService<M, K> {
|
||||
/**
|
||||
* 当前Service关联的主Model实体对象的Class。
|
||||
*/
|
||||
protected Class<M> modelClass;
|
||||
@Getter
|
||||
protected final Class<M> modelClass;
|
||||
/**
|
||||
* 当前Service关联的主Model实体对象主键字段的Class。
|
||||
*/
|
||||
protected final Class<K> idFieldClass;
|
||||
/**
|
||||
* 当前Service关联的主Model对象的实际表名称。
|
||||
*/
|
||||
protected String tableName;
|
||||
protected final String tableName;
|
||||
/**
|
||||
* 当前Service关联的主Model对象主键字段名称。
|
||||
*/
|
||||
@@ -78,57 +84,61 @@ public abstract class BaseService<M, K> {
|
||||
*/
|
||||
protected String updateTimeColumnName;
|
||||
/**
|
||||
* 当前Service关联的主Model对象主键字段反射对象。
|
||||
* 当前Service关联的主Model对象主键字段赋值方法的反射对象。
|
||||
*/
|
||||
protected Field idField;
|
||||
protected Method setIdFieldMethod;
|
||||
/**
|
||||
* 当前Service关联的主Model对象逻辑删除字段反射对象。
|
||||
* 当前Service关联的主Model对象主键字段访问方法的反射对象。
|
||||
*/
|
||||
protected Field deletedFlagField;
|
||||
protected Method getIdFieldMethod;
|
||||
/**
|
||||
* 当前Service关联的主Model对象逻辑字段赋值方法的反射对象。
|
||||
* 当前Service关联的主Model对象逻辑删除字段赋值方法的反射对象。
|
||||
*/
|
||||
private Method setDeletedFlagMethod;
|
||||
protected Method setDeletedFlagMethod;
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有本地服务常量字典关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<LocalRelationStruct> relationConstDictStructList = new LinkedList<>();
|
||||
private final List<LocalRelationStruct> relationConstDictStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有本地服务字典关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<LocalRelationStruct> localRelationDictStructList = new LinkedList<>();
|
||||
private final List<LocalRelationStruct> localRelationDictStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有本地服务一对一关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<LocalRelationStruct> localRelationOneToOneStructList = new LinkedList<>();
|
||||
private final List<LocalRelationStruct> localRelationOneToOneStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有本地服务一对多关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private final List<LocalRelationStruct> localRelationOneToManyStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有多对多关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<LocalRelationStruct> localRelationManyToManyStructList = new LinkedList<>();
|
||||
private final List<LocalRelationStruct> localRelationManyToManyStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有本地服务一对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<LocalRelationStruct> localRelationOneToManyAggrStructList = new LinkedList<>();
|
||||
private final List<LocalRelationStruct> localRelationOneToManyAggrStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有本地服务多对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<LocalRelationStruct> localRelationManyToManyAggrStructList = new LinkedList<>();
|
||||
private final List<LocalRelationStruct> localRelationManyToManyAggrStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有远程字典关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<RemoteRelationStruct> remoteRelationDictStructList = new LinkedList<>();
|
||||
private final List<RemoteRelationStruct> remoteRelationDictStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有远程一对一关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<RemoteRelationStruct> remoteRelationOneToOneStructList = new LinkedList<>();
|
||||
private final List<RemoteRelationStruct> remoteRelationOneToOneStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有远程一对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<RemoteRelationStruct> remoteRelationOneToManyAggrStructList = new LinkedList<>();
|
||||
private final List<RemoteRelationStruct> remoteRelationOneToManyAggrStructList = new LinkedList<>();
|
||||
/**
|
||||
* 当前Service关联的主Model对象的所有远程多对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。
|
||||
*/
|
||||
private List<RemoteRelationStruct> remoteRelationManyToManyAggrStructList = new LinkedList<>();
|
||||
private final List<RemoteRelationStruct> remoteRelationManyToManyAggrStructList = new LinkedList<>();
|
||||
|
||||
private static final String AND_OP = " AND ";
|
||||
|
||||
@@ -138,6 +148,7 @@ public abstract class BaseService<M, K> {
|
||||
@SuppressWarnings("unchecked")
|
||||
public BaseService() {
|
||||
modelClass = (Class<M>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
idFieldClass = (Class<K>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
|
||||
this.tableName = modelClass.getAnnotation(Table.class).name();
|
||||
Field[] fields = ReflectUtil.getFields(modelClass);
|
||||
for (Field field : fields) {
|
||||
@@ -148,9 +159,12 @@ public abstract class BaseService<M, K> {
|
||||
private void initializeField(Field field) {
|
||||
if (idFieldName == null && null != field.getAnnotation(Id.class)) {
|
||||
idFieldName = field.getName();
|
||||
idField = field;
|
||||
Column c = field.getAnnotation(Column.class);
|
||||
idColumnName = c == null ? idFieldName : c.name();
|
||||
setIdFieldMethod = ReflectUtil.getMethod(
|
||||
modelClass, "set" + StringUtils.capitalize(idFieldName), idFieldClass);
|
||||
getIdFieldMethod = ReflectUtil.getMethod(
|
||||
modelClass, "get" + StringUtils.capitalize(idFieldName));
|
||||
}
|
||||
if (updateTimeFieldName == null && null != field.getAnnotation(JobUpdateTimeColumn.class)) {
|
||||
updateTimeFieldName = field.getName();
|
||||
@@ -161,7 +175,6 @@ public abstract class BaseService<M, K> {
|
||||
deletedFlagFieldName = field.getName();
|
||||
Column c = field.getAnnotation(Column.class);
|
||||
deletedFlagColumnName = c == null ? deletedFlagFieldName : c.name();
|
||||
deletedFlagField = field;
|
||||
setDeletedFlagMethod = ReflectUtil.getMethod(
|
||||
modelClass, "set" + StringUtils.capitalize(deletedFlagFieldName), Integer.class);
|
||||
}
|
||||
@@ -186,14 +199,39 @@ public abstract class BaseService<M, K> {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于主键Id删除数据。如果包含逻辑删除字段,则进行逻辑删除。
|
||||
*
|
||||
* @param id 主键Id值。
|
||||
* @return true删除成功,false数据不存在。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean removeById(K id) {
|
||||
if (this.deletedFlagFieldName == null) {
|
||||
return mapper().deleteByPrimaryKey(id) == 1;
|
||||
}
|
||||
try {
|
||||
M data = modelClass.newInstance();
|
||||
setDeletedFlagMethod.invoke(data, GlobalDeletedFlag.DELETED);
|
||||
setIdFieldMethod.invoke(data, id);
|
||||
return mapper().updateByPrimaryKeySelective(data) == 1;
|
||||
} catch (Exception ex) {
|
||||
log.error("Failed to call reflection method in BaseService.removeById.", ex);
|
||||
throw new MyRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据过滤条件删除数据。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @return 删除数量。
|
||||
*/
|
||||
public Integer removeBy(M filter) throws Exception {
|
||||
if (deletedFlagField == null) {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Integer removeBy(M filter) {
|
||||
if (deletedFlagFieldName == null) {
|
||||
return mapper().delete(filter);
|
||||
}
|
||||
Example e = new Example(modelClass);
|
||||
@@ -204,9 +242,14 @@ public abstract class BaseService<M, K> {
|
||||
this.assembleCriteriaByFilter(filter, field, c);
|
||||
}
|
||||
}
|
||||
M deletedObject = modelClass.newInstance();
|
||||
this.setDeletedFlagMethod.invoke(deletedObject, GlobalDeletedFlag.DELETED);
|
||||
return mapper().updateByExampleSelective(deletedObject, e);
|
||||
try {
|
||||
M deletedObject = modelClass.newInstance();
|
||||
this.setDeletedFlagMethod.invoke(deletedObject, GlobalDeletedFlag.DELETED);
|
||||
return mapper().updateByExampleSelective(deletedObject, e);
|
||||
} catch (Exception ex) {
|
||||
log.error("Failed to call reflection method in BaseService.removeBy.", ex);
|
||||
throw new MyRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,6 +258,7 @@ public abstract class BaseService<M, K> {
|
||||
* @param id 主键Id
|
||||
* @return 存在返回true,否则false
|
||||
*/
|
||||
@Override
|
||||
public boolean existId(K id) {
|
||||
return this.getById(id) != null;
|
||||
}
|
||||
@@ -228,6 +272,7 @@ public abstract class BaseService<M, K> {
|
||||
* @return 存在且仅存在一条返回true,否则false。
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean existOne(String fieldName, Object fieldValue) {
|
||||
if (fieldName.equals(this.idFieldName)) {
|
||||
return this.existId((K) fieldValue);
|
||||
@@ -243,8 +288,9 @@ public abstract class BaseService<M, K> {
|
||||
* @param id 主键Id
|
||||
* @return 主键关联的数据,不存在返回null。
|
||||
*/
|
||||
@Override
|
||||
public M getById(K id) {
|
||||
if (deletedFlagField == null) {
|
||||
if (deletedFlagFieldName == null) {
|
||||
return mapper().selectByPrimaryKey(id);
|
||||
}
|
||||
Example e = new Example(modelClass);
|
||||
@@ -254,6 +300,27 @@ public abstract class BaseService<M, K> {
|
||||
return mapper().selectOneByExample(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回符合 filterField = filterValue 条件的一条数据。
|
||||
*
|
||||
* @param filterField 过滤的Java字段。
|
||||
* @param filterValue 过滤的Java字段值。
|
||||
* @return 查询后的数据对象。
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public M getOne(String filterField, Object filterValue) {
|
||||
if (filterField.equals(idFieldName)) {
|
||||
return this.getById((K) filterValue);
|
||||
}
|
||||
Example e = new Example(modelClass);
|
||||
Example.Criteria c = e.createCriteria().andEqualTo(filterField, filterValue);
|
||||
if (deletedFlagFieldName != null) {
|
||||
c.andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL);
|
||||
}
|
||||
return mapper().selectOneByExample(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
|
||||
*
|
||||
@@ -262,10 +329,11 @@ public abstract class BaseService<M, K> {
|
||||
* @return 查询结果对象。
|
||||
* @throws RemoteDataBuildException ignoreRpcError()方法返回false,同时远程服务调用出现错误时抛出此异常。
|
||||
*/
|
||||
public M getByIdWithRelation(K id, MyRelationParam relationParam) {
|
||||
M dataObject = this.getById(id);
|
||||
this.buildRelationForData(dataObject, relationParam, buildAggregationAdditionalWhereCriteria());
|
||||
return dataObject;
|
||||
@Override
|
||||
public M getByIdWithRelation(K id, MyRelationParam relationParam) {
|
||||
M dataObject = this.getById(id);
|
||||
this.buildRelationForData(dataObject, relationParam);
|
||||
return dataObject;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,8 +341,9 @@ public abstract class BaseService<M, K> {
|
||||
*
|
||||
* @return 返回所有数据。
|
||||
*/
|
||||
@Override
|
||||
public List<M> getAllList() {
|
||||
if (deletedFlagField == null) {
|
||||
if (deletedFlagFieldName == null) {
|
||||
return mapper().selectAll();
|
||||
}
|
||||
Example e = new Example(modelClass);
|
||||
@@ -288,6 +357,7 @@ public abstract class BaseService<M, K> {
|
||||
* @param orderByProperties 需要排序的字段属性,这里使用Java对象中的属性名,而不是数据库字段名。
|
||||
* @return 返回排序后所有数据。
|
||||
*/
|
||||
@Override
|
||||
public List<M> getAllListByOrder(String... orderByProperties) {
|
||||
Example e = new Example(modelClass);
|
||||
for (String orderByProperty : orderByProperties) {
|
||||
@@ -299,25 +369,13 @@ public abstract class BaseService<M, K> {
|
||||
return mapper().selectByExample(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有主数据及其关联数据。
|
||||
*
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @return 返回所有主数据,及其关联数据。
|
||||
* @throws RemoteDataBuildException ignoreRpcError()方法返回false,同时远程服务调用出现错误时抛出此异常。
|
||||
*/
|
||||
public List<M> getAllListWithRelation(MyRelationParam relationParam) {
|
||||
List<M> resultList = getAllList();
|
||||
this.buildRelationForDataList(resultList, relationParam, null);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数值主键集合中的所有数据,是否全部存在
|
||||
*
|
||||
* @param idSet 待校验的主键集合。
|
||||
* @return 全部存在返回true,否则false。
|
||||
*/
|
||||
@Override
|
||||
public boolean existAllPrimaryKeys(Set<K> idSet) {
|
||||
if (CollectionUtils.isEmpty(idSet)) {
|
||||
return true;
|
||||
@@ -332,52 +390,24 @@ public abstract class BaseService<M, K> {
|
||||
* @param inFilterValues 数据值集合。
|
||||
* @return 全部存在返回true,否则false。
|
||||
*/
|
||||
@Override
|
||||
public <T> boolean existUniqueKeyList(String inFilterField, Set<T> inFilterValues) {
|
||||
if (CollectionUtils.isEmpty(inFilterValues)) {
|
||||
return true;
|
||||
}
|
||||
Example e = this.makeDefaultInListExample(inFilterField, inFilterValues, null);
|
||||
if (deletedFlagFieldName != null) {
|
||||
e.and().andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL);
|
||||
}
|
||||
return mapper().selectCountByExample(e) == inFilterValues.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有数据的指定字段的数据列表。单表查询,不进行任何数据关联。
|
||||
*
|
||||
* @param getterFunc 指定字段的getter方法。
|
||||
* @param <T> 指定字段的类型。
|
||||
* @return 指定字段的列表。
|
||||
*/
|
||||
public <T> List<T> getAllListWithField(Function<M, T> getterFunc) {
|
||||
List<M> allList = this.getAllList();
|
||||
// 即使没有符合filter条件的item存在,也会返回空列表对象,而不是null。
|
||||
return allList.stream().filter(x -> getterFunc.apply(x) != null).map(getterFunc).collect(toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回符合主键 in (idValues) 条件的所有数据。单表查询,不进行任何数据关联。
|
||||
*
|
||||
* @param idValues 主键值列表。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
@Override
|
||||
public List<M> getInList(Set<K> idValues) {
|
||||
return this.getInList(idFieldName, idValues, (String) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过getIdFunc函数,获取主对象列表masterList中的主键列表。在基于该Id列表作为主键查询的in list条件,获取数据。
|
||||
* 单表查询,不进行任何数据关联。
|
||||
*
|
||||
* @param masterList 主对象列表,通过应用getIdFunc函数,获取查询条件中的主键in list条件。
|
||||
* @param getIdFunc 获取主对象中符合查询条件主键的id值。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
public <T> List<M> getInList(List<T> masterList, Function<T, K> getIdFunc) {
|
||||
// 即使没有符合filter条件的item存在,也会返回空列表对象,而不是null。
|
||||
return this.getInList(masterList.stream()
|
||||
.filter(x -> getIdFunc.apply(x) != null).map(getIdFunc).collect(toSet()));
|
||||
return this.getInList(idFieldName, idValues, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,8 +417,9 @@ public abstract class BaseService<M, K> {
|
||||
* @param inFilterValues 参与(In-list)过滤的字段值集合。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
@Override
|
||||
public <T> List<M> getInList(String inFilterField, Set<T> inFilterValues) {
|
||||
return this.getInList(inFilterField, inFilterValues, (String) null);
|
||||
return this.getInList(inFilterField, inFilterValues, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,42 +427,25 @@ public abstract class BaseService<M, K> {
|
||||
*
|
||||
* @param inFilterField 参与(In-list)过滤的Java对象字段。
|
||||
* @param inFilterValues 参与(In-list)过滤的字段值集合。
|
||||
* @param orderBy 排序字段。
|
||||
* @param orderBy SQL的ORDER BY排序从句。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
@Override
|
||||
public <T> List<M> getInList(String inFilterField, Set<T> inFilterValues, String orderBy) {
|
||||
if (CollectionUtils.isEmpty(inFilterValues)) {
|
||||
return new LinkedList<>();
|
||||
}
|
||||
Example e = this.makeDefaultInListExample(inFilterField, inFilterValues, orderBy);
|
||||
if (deletedFlagFieldName != null) {
|
||||
e.and().andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL);
|
||||
}
|
||||
return mapper().selectByExample(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于对象集合(masterList),并通过masterIdFunction函数对象获取inFilterField字段的数据列表,
|
||||
* 最后返回inFilterField in (inFilterValues)的所有数据。单表查询,不进行任何数据关联。
|
||||
*
|
||||
* @param inFilterField 参与(In-list)过滤的Java对象字段。
|
||||
* @param masterList 主对象数据集合。
|
||||
* @param masterIdFunction 获取主对象中,inFilterField字段数值的函数对象。
|
||||
* @param <T> 主对象类型。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
public <T> List<M> getInList(String inFilterField, Collection<T> masterList, Function<T, K> masterIdFunction) {
|
||||
// 即使没有符合filter条件的item存在,也会返回空列表对象,而不是null。
|
||||
return this.getInList(inFilterField, masterList.stream()
|
||||
.filter(x -> masterIdFunction.apply(x) != null).map(masterIdFunction).collect(toSet()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用参数对象作为过滤条件,获取数据数量。
|
||||
*
|
||||
* @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。
|
||||
* @return 返回过滤后的数据数量。
|
||||
*/
|
||||
@Override
|
||||
public int getCountByFilter(M filter) {
|
||||
if (deletedFlagFieldName == null) {
|
||||
return mapper().selectCount(filter);
|
||||
@@ -440,7 +454,7 @@ public abstract class BaseService<M, K> {
|
||||
setDeletedFlagMethod.invoke(filter, GlobalDeletedFlag.NORMAL);
|
||||
return mapper().selectCount(filter);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call reflection code of BaseService.getCountByFilter.", e);
|
||||
log.error("Failed to call reflection [setDeletedFlagMethod] in BaseService.getCountByFilter.", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
@@ -451,6 +465,7 @@ public abstract class BaseService<M, K> {
|
||||
* @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件
|
||||
* @return 存在返回true,否则false
|
||||
*/
|
||||
@Override
|
||||
public boolean existByFilter(M filter) {
|
||||
return this.getCountByFilter(filter) > 0;
|
||||
}
|
||||
@@ -461,7 +476,8 @@ public abstract class BaseService<M, K> {
|
||||
* @param filter 该方法基于mybatis的通用mapper,如果参数为null,则返回全部数据。
|
||||
* @return 返回过滤后的数据。
|
||||
*/
|
||||
private List<M> getListByFilter(M filter) {
|
||||
@Override
|
||||
public List<M> getListByFilter(M filter) {
|
||||
if (filter == null) {
|
||||
return this.getAllList();
|
||||
}
|
||||
@@ -477,33 +493,6 @@ public abstract class BaseService<M, K> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用参数对象作为过滤条件,获取查询结果。
|
||||
*
|
||||
* @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。
|
||||
* @param orderBy SQL中ORDER BY从句。
|
||||
* @return 返回过滤后的数据。
|
||||
*/
|
||||
public List<M> getListByFilter(M filter, String orderBy) {
|
||||
if (StringUtils.isBlank(orderBy)) {
|
||||
return this.getListByFilter(filter);
|
||||
}
|
||||
Example e = new Example(modelClass);
|
||||
if (StringUtils.isNotBlank(orderBy)) {
|
||||
e.setOrderByClause(orderBy);
|
||||
}
|
||||
if (filter != null) {
|
||||
Example.Criteria c = e.createCriteria();
|
||||
Field[] fields = ReflectUtil.getFields(modelClass);
|
||||
for (Field field : fields) {
|
||||
if (field.getAnnotation(Transient.class) == null) {
|
||||
assembleCriteriaByFilter(filter, field, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapper().selectByExample(e);
|
||||
}
|
||||
|
||||
private void assembleCriteriaByFilter(M filter, Field field, Example.Criteria c) {
|
||||
int modifiers = field.getModifiers();
|
||||
// transient类型的字段不能作为查询条件
|
||||
@@ -527,22 +516,6 @@ public abstract class BaseService<M, K> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用参数对象作为过滤条件,获取查询结果。同时组装实体对象中基于RelationXXXX注解关联的数据。
|
||||
*
|
||||
* @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。
|
||||
* @param orderBy SQL中ORDER BY从句。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @return 返回过滤后的数据。
|
||||
* @throws RemoteDataBuildException ignoreRpcError()方法返回false,同时远程服务调用出现错误时抛出此异常。
|
||||
*/
|
||||
public List<M> getListWithRelationByFilter(M filter, String orderBy, MyRelationParam relationParam) {
|
||||
List<M> resultList = this.getListByFilter(filter, orderBy);
|
||||
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
|
||||
this.buildRelationForDataList(resultList, relationParam, criteriaMap);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父主键Id下的所有子数据列表。单表查询,不进行任何数据关联。
|
||||
*
|
||||
@@ -550,6 +523,7 @@ public abstract class BaseService<M, K> {
|
||||
* @param parentId 父主键的值。
|
||||
* @return 父主键Id下的所有子数据列表。
|
||||
*/
|
||||
@Override
|
||||
public List<M> getListByParentId(String parentIdFieldName, K parentId) {
|
||||
Example e = new Example(modelClass);
|
||||
Example.Criteria c = e.createCriteria();
|
||||
@@ -574,6 +548,7 @@ public abstract class BaseService<M, K> {
|
||||
* @param groupBy SQL常量形式分组字段列表,逗号分隔。
|
||||
* @return 聚合计算后的数据结果集。
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getGroupedListByCondition(
|
||||
String selectFields, String whereClause, String groupBy) {
|
||||
return mapper().getGroupedListByCondition(tableName, selectFields, whereClause, groupBy);
|
||||
@@ -588,6 +563,7 @@ public abstract class BaseService<M, K> {
|
||||
* @param orderBy SQL常量形式排序字段列表,逗号分隔。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
@Override
|
||||
public List<M> getListByCondition(List<String> selectList, M filter, String whereClause, String orderBy) {
|
||||
Example e = new Example(modelClass);
|
||||
Example.Criteria c = null;
|
||||
@@ -623,6 +599,7 @@ public abstract class BaseService<M, K> {
|
||||
* @param whereClause SQL常量形式的条件从句。
|
||||
* @return 返回过滤后的数据数量。
|
||||
*/
|
||||
@Override
|
||||
public Integer getCountByCondition(String whereClause) {
|
||||
return mapper().getCountByCondition(this.tableName, whereClause);
|
||||
}
|
||||
@@ -633,11 +610,10 @@ public abstract class BaseService<M, K> {
|
||||
*
|
||||
* @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param criteriaListMap 仅仅用于一对多和多对多聚合计算的附加过滤条件。如果没有可以为NULL。
|
||||
* @throws RemoteDataBuildException ignoreRpcError()方法返回false,同时远程服务调用出现错误时抛出此异常。
|
||||
*/
|
||||
public void buildRelationForDataList(
|
||||
List<M> resultList, MyRelationParam relationParam, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
@Override
|
||||
public void buildRelationForDataList(List<M> resultList, MyRelationParam relationParam) {
|
||||
if (relationParam == null || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
@@ -666,16 +642,16 @@ public abstract class BaseService<M, K> {
|
||||
// 组装本地聚合计算关联数据
|
||||
if (relationParam.isBuildAggregation()) {
|
||||
// 处理多一多场景下,根据主表的结果,进行从表聚合数据的计算。
|
||||
this.buildOneToManyAggregationForDataList(resultList, criteriaListMap);
|
||||
this.buildOneToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria());
|
||||
// 处理多对多场景下,根据主表的结果,进行从表聚合数据的计算。
|
||||
this.buildManyToManyAggregationForDataList(resultList, criteriaListMap);
|
||||
this.buildManyToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria());
|
||||
}
|
||||
// 组装远程聚合计算关联数据
|
||||
if (relationParam.isBuildRemoteAggregation()) {
|
||||
// 一对多场景。
|
||||
this.buildRemoteOneToManyAggregationForDataList(resultList, criteriaListMap);
|
||||
this.buildRemoteOneToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria());
|
||||
// 处理多对多场景。
|
||||
this.buildRemoteManyToManyAggregationForDataList(resultList, criteriaListMap);
|
||||
this.buildRemoteManyToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,12 +661,11 @@ public abstract class BaseService<M, K> {
|
||||
*
|
||||
* @param dataObject 主表实体对象。数据集成将直接作用于该对象。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param criteriaListMap 仅仅用于一对多和多对多聚合计算的附加过滤条件。如果没有可以为NULL。
|
||||
* @param <T> 实体对象类型。
|
||||
* @throws RemoteDataBuildException ignoreRpcError()方法返回false,同时远程服务调用出现错误时抛出此异常。
|
||||
*/
|
||||
public <T extends M> void buildRelationForData(
|
||||
T dataObject, MyRelationParam relationParam, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
@Override
|
||||
public <T extends M> void buildRelationForData(T dataObject, MyRelationParam relationParam) {
|
||||
if (dataObject == null || relationParam == null) {
|
||||
return;
|
||||
}
|
||||
@@ -716,18 +691,18 @@ public abstract class BaseService<M, K> {
|
||||
// 组装本地聚合计算关联数据
|
||||
if (relationParam.isBuildAggregation()) {
|
||||
// 构建一对多场景
|
||||
buildOneToManyAggregationForData(dataObject, criteriaListMap);
|
||||
buildOneToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria());
|
||||
// 开始处理多对多场景。
|
||||
buildManyToManyAggregationForData(dataObject, criteriaListMap);
|
||||
buildManyToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria());
|
||||
}
|
||||
// 组装远程聚合计算关联数据
|
||||
if (relationParam.isBuildRemoteAggregation()) {
|
||||
// 处理一对多场景
|
||||
this.buildRemoteOneToManyAggregationForData(dataObject, criteriaListMap);
|
||||
this.buildRemoteOneToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria());
|
||||
// 处理多对多场景
|
||||
this.buildRemoteManyToManyAggregationForData(dataObject, criteriaListMap);
|
||||
this.buildRemoteManyToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria());
|
||||
}
|
||||
if (relationParam.isBuildManyToManyRelation()) {
|
||||
if (relationParam.isBuildRelationManyToMany()) {
|
||||
this.buildRelationManyToMany(dataObject);
|
||||
}
|
||||
}
|
||||
@@ -738,8 +713,7 @@ public abstract class BaseService<M, K> {
|
||||
* @param resultList 主表数据列表。
|
||||
*/
|
||||
private void buildConstDictForDataList(List<M> resultList) {
|
||||
if (CollectionUtils.isEmpty(this.relationConstDictStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.relationConstDictStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (LocalRelationStruct relationStruct : this.relationConstDictStructList) {
|
||||
@@ -807,8 +781,7 @@ public abstract class BaseService<M, K> {
|
||||
* @throws RemoteDataBuildException ignoreRpcError()方法返回false,同时远程服务调用出现错误时抛出此异常。
|
||||
*/
|
||||
private void buildRemoteOneToOneForDataList(List<M> resultList, boolean withDict) {
|
||||
if (CollectionUtils.isEmpty(this.remoteRelationOneToOneStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.remoteRelationOneToOneStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (RemoteRelationStruct relationStruct : this.remoteRelationOneToOneStructList) {
|
||||
@@ -879,8 +852,7 @@ public abstract class BaseService<M, K> {
|
||||
* @throws RemoteDataBuildException ignoreRpcError()方法返回false,同时远程服务调用出现错误时抛出此异常。
|
||||
*/
|
||||
private void buildRemoteDictForDataList(List<M> resultList, boolean hasBuiltOneToOne) {
|
||||
if (CollectionUtils.isEmpty(this.remoteRelationDictStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.remoteRelationDictStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (RemoteRelationStruct relationStruct : this.remoteRelationDictStructList) {
|
||||
@@ -963,8 +935,7 @@ public abstract class BaseService<M, K> {
|
||||
*/
|
||||
private void buildRemoteOneToManyAggregationForDataList(
|
||||
List<M> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
if (CollectionUtils.isEmpty(this.remoteRelationOneToManyAggrStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.remoteRelationOneToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
if (criteriaListMap == null) {
|
||||
@@ -1058,8 +1029,7 @@ public abstract class BaseService<M, K> {
|
||||
*/
|
||||
private void buildRemoteManyToManyAggregationForDataList(
|
||||
List<M> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
if (CollectionUtils.isEmpty(this.remoteRelationManyToManyAggrStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.remoteRelationManyToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
if (criteriaListMap == null) {
|
||||
@@ -1136,8 +1106,7 @@ public abstract class BaseService<M, K> {
|
||||
* @throws RemoteDataBuildException ignoreRpcError()方法返回false,同时远程服务调用出现错误时抛出此异常。
|
||||
*/
|
||||
private void buildOneToOneForDataList(List<M> resultList, boolean withDict) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationOneToOneStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationOneToOneStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (LocalRelationStruct relationStruct : this.localRelationOneToOneStructList) {
|
||||
@@ -1185,7 +1154,7 @@ public abstract class BaseService<M, K> {
|
||||
Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (id != null) {
|
||||
BaseService<Object, Object> relationService = relationStruct.localService;
|
||||
Object relationObject = relationService.getById(id);
|
||||
Object relationObject = relationService.getOne(relationStruct.relationOneToOne.slaveIdField(), id);
|
||||
ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, relationObject);
|
||||
// 仅仅当需要加载从表字典关联时,才去加载。
|
||||
if (withDict && relationStruct.relationOneToOne.loadSlaveDict() && relationObject != null) {
|
||||
@@ -1203,6 +1172,53 @@ public abstract class BaseService<M, K> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为实体对象参数列表数据集成本地一对多关联数据。
|
||||
*
|
||||
* @param resultList 实体对象数据列表。
|
||||
*/
|
||||
private void buildOneToManyForDataList(List<M> resultList) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationOneToManyStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (LocalRelationStruct relationStruct : this.localRelationOneToManyStructList) {
|
||||
Set<Object> masterIdSet = resultList.stream()
|
||||
.map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(toSet());
|
||||
// 从主表集合中,抽取主表关联字段的集合,再以in list形式去从表中查询。
|
||||
if (CollectionUtils.isNotEmpty(masterIdSet)) {
|
||||
BaseService<Object, Object> relationService = relationStruct.localService;
|
||||
List<Object> relationList =
|
||||
relationService.getInList(relationStruct.relationOneToMany.slaveIdField(), masterIdSet);
|
||||
MyModelUtil.makeOneToManyRelation(
|
||||
modelClass, resultList, relationList, relationStruct.relationField.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为实体对象数据集成本地一对多关联数据。
|
||||
*
|
||||
* @param dataObject 实体对象。
|
||||
*/
|
||||
private void buildOneToManyForData(M dataObject) {
|
||||
if (dataObject == null || CollectionUtils.isEmpty(this.localRelationOneToManyStructList)) {
|
||||
return;
|
||||
}
|
||||
for (LocalRelationStruct relationStruct : this.localRelationOneToManyStructList) {
|
||||
Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (id != null) {
|
||||
BaseService<Object, Object> relationService = relationStruct.localService;
|
||||
Set<Object> masterIdSet = new HashSet<>(1);
|
||||
masterIdSet.add(id);
|
||||
List<Object> relationObject = relationService.getInList(
|
||||
relationStruct.relationOneToMany.slaveIdField(), masterIdSet);
|
||||
ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, relationObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为实体对象参数列表数据集成本地字典关联数据。
|
||||
*
|
||||
@@ -1211,8 +1227,7 @@ public abstract class BaseService<M, K> {
|
||||
* 不为空,则直接从已经完成一对一数据关联的从表对象中获取数据,减少一次数据库交互。
|
||||
*/
|
||||
private void buildDictForDataList(List<M> resultList, boolean hasBuiltOneToOne) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationDictStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationDictStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (LocalRelationStruct relationStruct : this.localRelationDictStructList) {
|
||||
@@ -1255,7 +1270,7 @@ public abstract class BaseService<M, K> {
|
||||
} else {
|
||||
Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField);
|
||||
if (id != null) {
|
||||
relationObject = relationStruct.localService.getById(id);
|
||||
relationObject = relationStruct.localService.getOne(relationStruct.relationDict.slaveIdField(), id);
|
||||
}
|
||||
}
|
||||
MyModelUtil.makeDictRelation(
|
||||
@@ -1271,8 +1286,7 @@ public abstract class BaseService<M, K> {
|
||||
*/
|
||||
private void buildManyToManyAggregationForDataList(
|
||||
List<M> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationManyToManyAggrStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationManyToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
if (criteriaListMap == null) {
|
||||
@@ -1343,8 +1357,7 @@ public abstract class BaseService<M, K> {
|
||||
*/
|
||||
private void buildOneToManyAggregationForDataList(
|
||||
List<M> resultList, Map<String, List<MyWhereCriteria>> criteriaListMap) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationOneToManyAggrStructList)
|
||||
|| CollectionUtils.isEmpty(resultList)) {
|
||||
if (CollectionUtils.isEmpty(this.localRelationOneToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
if (criteriaListMap == null) {
|
||||
@@ -1479,6 +1492,7 @@ public abstract class BaseService<M, K> {
|
||||
/**
|
||||
* 仅仅在spring boot 启动后的监听器事件中调用,缓存所有远程调用Client的关联关系,加速后续的数据绑定效率。
|
||||
*/
|
||||
@Override
|
||||
public void loadRemoteRelationStruct() {
|
||||
Field[] fields = ReflectUtil.getFields(modelClass);
|
||||
for (Field f : fields) {
|
||||
@@ -1491,6 +1505,7 @@ public abstract class BaseService<M, K> {
|
||||
/**
|
||||
* 仅仅在spring boot 启动后的监听器事件中调用,缓存所有service的关联关系,加速后续的数据绑定效率。
|
||||
*/
|
||||
@Override
|
||||
public void loadLocalRelationStruct() {
|
||||
Field[] fields = ReflectUtil.getFields(modelClass);
|
||||
for (Field f : fields) {
|
||||
@@ -1567,7 +1582,11 @@ public abstract class BaseService<M, K> {
|
||||
inFilterValueSet = new HashSet<>(inFilterValues.size());
|
||||
inFilterValueSet.addAll(inFilterValues);
|
||||
}
|
||||
e.createCriteria().andIn(inFilterField, inFilterValueSet);
|
||||
Example.Criteria c = e.createCriteria();
|
||||
c.andIn(inFilterField, inFilterValueSet);
|
||||
if (deletedFlagFieldName != null) {
|
||||
c.andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -1643,6 +1662,7 @@ public abstract class BaseService<M, K> {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initializeLocalRelationStruct(Field f) {
|
||||
RelationOneToOne relationOneToOne = f.getAnnotation(RelationOneToOne.class);
|
||||
if (relationOneToOne != null) {
|
||||
@@ -1653,11 +1673,32 @@ public abstract class BaseService<M, K> {
|
||||
relationStruct.relationField = f;
|
||||
relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToOne.masterIdField());
|
||||
relationStruct.relationOneToOne = relationOneToOne;
|
||||
relationStruct.localService =
|
||||
ApplicationContextHolder.getBean(StringUtils.uncapitalize(relationOneToOne.slaveServiceName()));
|
||||
if (StringUtils.isNotBlank(relationOneToOne.slaveServiceName())) {
|
||||
relationStruct.localService = ApplicationContextHolder.getBean(
|
||||
StringUtils.uncapitalize(relationOneToOne.slaveServiceName()));
|
||||
} else {
|
||||
relationStruct.localService = (BaseService<Object, Object>)
|
||||
ApplicationContextHolder.getBean(relationOneToOne.slaveServiceClass());
|
||||
}
|
||||
localRelationOneToOneStructList.add(relationStruct);
|
||||
return;
|
||||
}
|
||||
RelationOneToMany relationOneToMany = f.getAnnotation(RelationOneToMany.class);
|
||||
if (relationOneToMany != null) {
|
||||
LocalRelationStruct relationStruct = new LocalRelationStruct();
|
||||
relationStruct.relationField = f;
|
||||
relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToMany.masterIdField());
|
||||
relationStruct.relationOneToMany = relationOneToMany;
|
||||
if (StringUtils.isNotBlank(relationOneToMany.slaveServiceName())) {
|
||||
relationStruct.localService = ApplicationContextHolder.getBean(
|
||||
StringUtils.uncapitalize(relationOneToMany.slaveServiceName()));
|
||||
} else {
|
||||
relationStruct.localService = (BaseService<Object, Object>)
|
||||
ApplicationContextHolder.getBean(relationOneToMany.slaveServiceClass());
|
||||
}
|
||||
localRelationOneToManyStructList.add(relationStruct);
|
||||
return;
|
||||
}
|
||||
RelationManyToMany relationManyToMany = f.getAnnotation(RelationManyToMany.class);
|
||||
if (relationManyToMany != null) {
|
||||
LocalRelationStruct relationStruct = new LocalRelationStruct();
|
||||
@@ -1695,15 +1736,20 @@ public abstract class BaseService<M, K> {
|
||||
relationStruct.equalOneToOneRelationField =
|
||||
ReflectUtil.getField(modelClass, relationDict.equalOneToOneRelationField());
|
||||
}
|
||||
relationStruct.localService =
|
||||
ApplicationContextHolder.getBean(StringUtils.uncapitalize(relationDict.slaveServiceName()));
|
||||
if (StringUtils.isNotBlank(relationDict.slaveServiceName())) {
|
||||
relationStruct.localService =
|
||||
ApplicationContextHolder.getBean(StringUtils.uncapitalize(relationDict.slaveServiceName()));
|
||||
} else {
|
||||
relationStruct.localService = (BaseService<Object, Object>)
|
||||
ApplicationContextHolder.getBean(relationDict.slaveServiceClass());
|
||||
}
|
||||
localRelationDictStructList.add(relationStruct);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initializeLocalRelationAggregationStruct(Field f) {
|
||||
RelationOneToManyAggregation relationOneToManyAggregation =
|
||||
f.getAnnotation(RelationOneToManyAggregation.class);
|
||||
RelationOneToManyAggregation relationOneToManyAggregation = f.getAnnotation(RelationOneToManyAggregation.class);
|
||||
if (relationOneToManyAggregation != null) {
|
||||
if (!relationOneToManyAggregation.slaveClientClass().equals(DummyClass.class)) {
|
||||
return;
|
||||
@@ -1712,13 +1758,17 @@ public abstract class BaseService<M, K> {
|
||||
relationStruct.relationField = f;
|
||||
relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToManyAggregation.masterIdField());
|
||||
relationStruct.relationOneToManyAggregation = relationOneToManyAggregation;
|
||||
relationStruct.localService = ApplicationContextHolder.getBean(
|
||||
StringUtils.uncapitalize(relationOneToManyAggregation.slaveServiceName()));
|
||||
if (StringUtils.isNotBlank(relationOneToManyAggregation.slaveServiceName())) {
|
||||
relationStruct.localService = ApplicationContextHolder.getBean(
|
||||
StringUtils.uncapitalize(relationOneToManyAggregation.slaveServiceName()));
|
||||
} else {
|
||||
relationStruct.localService = (BaseService<Object, Object>)
|
||||
ApplicationContextHolder.getBean(relationOneToManyAggregation.slaveServiceClass());
|
||||
}
|
||||
localRelationOneToManyAggrStructList.add(relationStruct);
|
||||
return;
|
||||
}
|
||||
RelationManyToManyAggregation relationManyToManyAggregation =
|
||||
f.getAnnotation(RelationManyToManyAggregation.class);
|
||||
RelationManyToManyAggregation relationManyToManyAggregation = f.getAnnotation(RelationManyToManyAggregation.class);
|
||||
if (relationManyToManyAggregation != null) {
|
||||
if (!relationManyToManyAggregation.slaveClientClass().equals(DummyClass.class)) {
|
||||
return;
|
||||
@@ -1727,8 +1777,13 @@ public abstract class BaseService<M, K> {
|
||||
relationStruct.relationField = f;
|
||||
relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationManyToManyAggregation.masterIdField());
|
||||
relationStruct.relationManyToManyAggregation = relationManyToManyAggregation;
|
||||
relationStruct.localService = ApplicationContextHolder.getBean(
|
||||
StringUtils.uncapitalize(relationManyToManyAggregation.slaveServiceName()));
|
||||
if (StringUtils.isNotBlank(relationManyToManyAggregation.slaveServiceName())) {
|
||||
relationStruct.localService = ApplicationContextHolder.getBean(
|
||||
StringUtils.uncapitalize(relationManyToManyAggregation.slaveServiceName()));
|
||||
} else {
|
||||
relationStruct.localService = (BaseService<Object, Object>)
|
||||
ApplicationContextHolder.getBean(relationManyToManyAggregation.slaveServiceClass());
|
||||
}
|
||||
localRelationManyToManyAggrStructList.add(relationStruct);
|
||||
}
|
||||
}
|
||||
@@ -2121,6 +2176,7 @@ public abstract class BaseService<M, K> {
|
||||
private Map<Object, String> dictMap;
|
||||
private RelationDict relationDict;
|
||||
private RelationOneToOne relationOneToOne;
|
||||
private RelationOneToMany relationOneToMany;
|
||||
private RelationManyToMany relationManyToMany;
|
||||
private RelationOneToManyAggregation relationOneToManyAggregation;
|
||||
private RelationManyToManyAggregation relationManyToManyAggregation;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.orange.demo.common.core.base.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 带有缓存功能的字典Service接口。
|
||||
*
|
||||
* @param <M> Model实体对象的类型。
|
||||
* @param <K> Model对象主键的类型。
|
||||
* @author Jerry
|
||||
* @date 2020-08-08
|
||||
*/
|
||||
public interface IBaseDictService<M, K> extends IBaseService<M, K> {
|
||||
/**
|
||||
* 是否在服务启动的时候加载。子类可以重载该方法,并在需要的时候手工调用loadCachedData加载数据。
|
||||
*
|
||||
* @return true表示启动即可加载数据,false需要手动调用loadCachedData进行加载。
|
||||
*/
|
||||
boolean loadOnStartup();
|
||||
|
||||
/**
|
||||
* 在系统启动时,加载全部数据到内存,缓存的key只能为映射表的主键。
|
||||
*/
|
||||
void loadCachedData();
|
||||
|
||||
/**
|
||||
* 重新加载数据库中所有当前表数据到系统内存。
|
||||
*
|
||||
* @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。
|
||||
*/
|
||||
void reloadCachedData(boolean force);
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param data 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
M saveNew(M data);
|
||||
|
||||
/**
|
||||
* 更新数据对象。
|
||||
*
|
||||
* @param data 更新的对象。
|
||||
* @param originalData 原有数据对象。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean update(M data, M originalData);
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param id 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean remove(K id);
|
||||
|
||||
/**
|
||||
* 直接从缓存池中获取所有数据。
|
||||
*
|
||||
* @return 返回所有数据。
|
||||
*/
|
||||
List<M> getAllListFromCache();
|
||||
|
||||
/**
|
||||
* 存入缓存。
|
||||
*
|
||||
* @param data 新增或更新数据。
|
||||
*/
|
||||
void putDictionaryCache(M data);
|
||||
|
||||
/**
|
||||
* 根据字典主键将数据从缓存中删除。
|
||||
*
|
||||
* @param id 字典主键。
|
||||
*/
|
||||
void removeDictionaryCache(K id);
|
||||
|
||||
/**
|
||||
* 获取缓存中的数据数量。
|
||||
*
|
||||
* @return 缓存中的数据总量。
|
||||
*/
|
||||
int getCachedCount();
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package com.orange.demo.common.core.base.service;
|
||||
|
||||
import com.orange.demo.common.core.object.MyRelationParam;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 所有Service的接口。
|
||||
*
|
||||
* @param <M> Model对象的类型。
|
||||
* @param <K> Model对象主键的类型。
|
||||
* @author Jerry
|
||||
* @date 2020-08-08
|
||||
*/
|
||||
public interface IBaseService<M, K> {
|
||||
|
||||
/**
|
||||
* 基于主键Id删除数据。如果包含逻辑删除字段,则进行逻辑删除。
|
||||
*
|
||||
* @param id 主键Id值。
|
||||
* @return true删除成功,false数据不存在。
|
||||
*/
|
||||
boolean removeById(K id);
|
||||
|
||||
/**
|
||||
* 根据过滤条件删除数据。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @return 删除数量。
|
||||
*/
|
||||
Integer removeBy(M filter);
|
||||
|
||||
/**
|
||||
* 判断指定字段的数据是否存在,且仅仅存在一条记录。
|
||||
* 如果是基于主键的过滤,会直接调用existId过滤函数,提升性能。在有缓存的场景下,也可以利用缓存。
|
||||
*
|
||||
* @param fieldName 待过滤的字段名(Java 字段)。
|
||||
* @param fieldValue 字段值。
|
||||
* @return 存在且仅存在一条返回true,否则false。
|
||||
*/
|
||||
boolean existOne(String fieldName, Object fieldValue);
|
||||
|
||||
/**
|
||||
* 判断主键Id关联的数据是否存在。
|
||||
*
|
||||
* @param id 主键Id。
|
||||
* @return 存在返回true,否则false。
|
||||
*/
|
||||
boolean existId(K id);
|
||||
|
||||
/**
|
||||
* 获取主键Id关联的数据。
|
||||
*
|
||||
* @param id 主键Id。
|
||||
* @return 主键关联的数据,不存在返回null。
|
||||
*/
|
||||
M getById(K id);
|
||||
|
||||
/**
|
||||
* 返回符合 filterField = filterValue 条件的一条数据。
|
||||
*
|
||||
* @param filterField 过滤的Java字段。
|
||||
* @param filterValue 过滤的Java字段值。
|
||||
* @return 查询后的数据对象。
|
||||
*/
|
||||
M getOne(String filterField, Object filterValue);
|
||||
|
||||
/**
|
||||
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
|
||||
*
|
||||
* @param id 主表主键Id。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @return 查询结果对象。
|
||||
*/
|
||||
M getByIdWithRelation(K id, MyRelationParam relationParam);
|
||||
|
||||
/**
|
||||
* 获取所有数据。
|
||||
*
|
||||
* @return 返回所有数据。
|
||||
*/
|
||||
List<M> getAllList();
|
||||
|
||||
/**
|
||||
* 获取排序后所有数据。
|
||||
*
|
||||
* @param orderByProperties 需要排序的字段属性,这里使用Java对象中的属性名,而不是数据库字段名。
|
||||
* @return 返回排序后所有数据。
|
||||
*/
|
||||
List<M> getAllListByOrder(String... orderByProperties);
|
||||
|
||||
/**
|
||||
* 判断参数值主键集合中的所有数据,是否全部存在
|
||||
*
|
||||
* @param idSet 待校验的主键集合。
|
||||
* @return 全部存在返回true,否则false。
|
||||
*/
|
||||
boolean existAllPrimaryKeys(Set<K> idSet);
|
||||
|
||||
/**
|
||||
* 判断参数值列表中的所有数据,是否全部存在。另外,keyName字段在数据表中必须是唯一键值,否则返回结果会出现误判。
|
||||
*
|
||||
* @param inFilterField 待校验的数据字段,这里使用Java对象中的属性,如courseId,而不是数据字段名course_id
|
||||
* @param inFilterValues 数据值列表。
|
||||
* @return 全部存在返回true,否则false。
|
||||
*/
|
||||
<T> boolean existUniqueKeyList(String inFilterField, Set<T> inFilterValues);
|
||||
|
||||
/**
|
||||
* 返回符合主键 in (idValues) 条件的所有数据。
|
||||
*
|
||||
* @param idValues 主键值集合。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
List<M> getInList(Set<K> idValues);
|
||||
|
||||
/**
|
||||
* 返回符合 inFilterField in (inFilterValues) 条件的所有数据。
|
||||
*
|
||||
* @param inFilterField 参与(In-list)过滤的Java字段。
|
||||
* @param inFilterValues 参与(In-list)过滤的Java字段值集合。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
<T> List<M> getInList(String inFilterField, Set<T> inFilterValues);
|
||||
|
||||
/**
|
||||
* 返回符合 inFilterField in (inFilterValues) 条件的所有数据,并根据orderBy字段排序。
|
||||
*
|
||||
* @param inFilterField 参与(In-list)过滤的Java字段。
|
||||
* @param inFilterValues 参与(In-list)过滤的Java字段值集合。
|
||||
* @param orderBy 排序字段。
|
||||
* @return 检索后的数据列表。
|
||||
*/
|
||||
<T> List<M> getInList(String inFilterField, Set<T> inFilterValues, String orderBy);
|
||||
|
||||
/**
|
||||
* 用参数对象作为过滤条件,获取数据数量。
|
||||
*
|
||||
* @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。
|
||||
* @return 返回过滤后的数据数量。
|
||||
*/
|
||||
int getCountByFilter(M filter);
|
||||
|
||||
/**
|
||||
* 用参数对象作为过滤条件,判断是否存在过滤数据。
|
||||
*
|
||||
* @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。
|
||||
* @return 存在返回true,否则false。
|
||||
*/
|
||||
boolean existByFilter(M filter);
|
||||
|
||||
/**
|
||||
* 用参数对象作为过滤条件,获取查询结果。
|
||||
*
|
||||
* @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。
|
||||
* @return 返回过滤后的数据。
|
||||
*/
|
||||
List<M> getListByFilter(M filter);
|
||||
|
||||
/**
|
||||
* 获取父主键Id下的所有子数据列表。
|
||||
*
|
||||
* @param parentIdFieldName 父主键字段名字,如"courseId"。
|
||||
* @param parentId 父主键的值。
|
||||
* @return 父主键Id下的所有子数据列表。
|
||||
*/
|
||||
List<M> getListByParentId(String parentIdFieldName, K parentId);
|
||||
|
||||
/**
|
||||
* 根据指定的显示字段列表、过滤条件字符串和分组字符串,返回聚合计算后的查询结果。(基本是内部框架使用,不建议外部接口直接使用)。
|
||||
*
|
||||
* @param selectFields 选择的字段列表,多个字段逗号分隔。
|
||||
* NOTE: 如果数据表字段和Java对象字段名字不同,Java对象字段应该以别名的形式出现。
|
||||
* 如: table_column_name modelFieldName。否则无法被反射回Bean对象。
|
||||
* @param whereClause SQL常量形式的条件从句。
|
||||
* @param groupBy SQL常量形式分组字段列表,逗号分隔。
|
||||
* @return 聚合计算后的数据结果集。
|
||||
*/
|
||||
List<Map<String, Object>> getGroupedListByCondition(String selectFields, String whereClause, String groupBy);
|
||||
|
||||
/**
|
||||
* 根据指定的显示字段列表、过滤条件字符串和排序字符串,返回查询结果。(基本是内部框架使用,不建议外部接口直接使用)。
|
||||
*
|
||||
* @param selectList 选择的Java字段列表。如果为空表示返回全部字段。
|
||||
* @param filter 过滤对象。
|
||||
* @param whereClause SQL常量形式的条件从句。
|
||||
* @param orderBy SQL常量形式排序字段列表,逗号分隔。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
List<M> getListByCondition(List<String> selectList, M filter, String whereClause, String orderBy);
|
||||
|
||||
/**
|
||||
* 用指定过滤条件,计算记录数量。(基本是内部框架使用,不建议外部接口直接使用)。
|
||||
*
|
||||
* @param whereClause SQL常量形式的条件从句。
|
||||
* @return 返回过滤后的数据数量。
|
||||
*/
|
||||
Integer getCountByCondition(String whereClause);
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
*/
|
||||
void buildRelationForDataList(List<M> resultList, MyRelationParam relationParam);
|
||||
|
||||
/**
|
||||
* 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。
|
||||
* 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。
|
||||
* NOTE: 该方法内执行的SQL将禁用数据权限过滤。
|
||||
*
|
||||
* @param dataObject 主表实体对象。数据集成将直接作用于该对象。
|
||||
* @param relationParam 实体对象数据组装的参数构建器。
|
||||
* @param <T> 实体对象类型。
|
||||
*/
|
||||
<T extends M> void buildRelationForData(T dataObject, MyRelationParam relationParam);
|
||||
|
||||
/**
|
||||
* 仅仅在spring boot 启动后的监听器事件中调用,缓存所有远程调用Client的关联关系,加速后续的数据绑定效率。
|
||||
*/
|
||||
void loadRemoteRelationStruct();
|
||||
|
||||
/**
|
||||
* 仅仅在spring boot 启动后的监听器事件中调用,缓存所有service的关联关系,加速后续的数据绑定效率。
|
||||
*/
|
||||
void loadLocalRelationStruct();
|
||||
}
|
||||
@@ -24,15 +24,15 @@ public class MapDictionaryCache<K, V> implements DictionaryCache<K, V> {
|
||||
/**
|
||||
* 存储字典数据的Map。
|
||||
*/
|
||||
protected LinkedHashMap<K, V> dataMap = new LinkedHashMap<>();
|
||||
protected final LinkedHashMap<K, V> dataMap = new LinkedHashMap<>();
|
||||
/**
|
||||
* 获取字典主键数据的函数对象。
|
||||
*/
|
||||
protected Function<V, K> idGetter;
|
||||
protected final Function<V, K> idGetter;
|
||||
/**
|
||||
* 由于大部分场景是读取操作,所以使用读写锁提高并发的伸缩性。
|
||||
*/
|
||||
protected ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
protected final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
/**
|
||||
* 超时时长。单位毫秒。
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@ public class MapTreeDictionaryCache<K, V> extends MapDictionaryCache<K, V> {
|
||||
/**
|
||||
* 获取字典父主键数据的函数对象。
|
||||
*/
|
||||
protected Function<V, K> parentIdGetter;
|
||||
protected final Function<V, K> parentIdGetter;
|
||||
|
||||
/**
|
||||
* 当前对象的构造器函数。
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.orange.demo.common.core.config;
|
||||
|
||||
/**
|
||||
* 通过线程本地存储的方式,保存当前数据库操作所需的数据源类型,动态数据源会根据该值,进行动态切换。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-08-08
|
||||
*/
|
||||
public class DataSourceContextHolder {
|
||||
|
||||
private static final ThreadLocal<Integer> CONTEXT_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 设置数据源类型
|
||||
* @param type 数据源类型
|
||||
*/
|
||||
public static void setDataSourceType(Integer type) {
|
||||
CONTEXT_HOLDER.set(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前数据库操作执行线程的数据源类型,同时由动态数据源的路由函数调用。
|
||||
* @return 数据源类型。
|
||||
*/
|
||||
public static Integer getDataSourceType() {
|
||||
return CONTEXT_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除线程本地变量,以免内存泄漏
|
||||
*/
|
||||
public static void clear() {
|
||||
CONTEXT_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private DataSourceContextHolder() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.orange.demo.common.core.config;
|
||||
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
/**
|
||||
* 动态数据源对象。当存在多个数据连接时使用。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-08-08
|
||||
*/
|
||||
public class DynamicDataSource extends AbstractRoutingDataSource {
|
||||
|
||||
@Override
|
||||
protected Object determineCurrentLookupKey() {
|
||||
return DataSourceContextHolder.getDataSourceType();
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,10 @@ public enum ErrorCodeEnum {
|
||||
INVALID_CLASS_FIELD("数据验证失败,无效的类对象字段!"),
|
||||
SERVER_INTERNAL_ERROR("服务器内部错误,请联系管理员!"),
|
||||
REDIS_CACHE_ACCESS_TIMEOUT("Redis缓存数据访问超时,请刷新后重试!"),
|
||||
REDIS_CACHE_ACCESS_STATE_ERROR("Redis缓存数据访问状态错误,请刷新后重试!");
|
||||
REDIS_CACHE_ACCESS_STATE_ERROR("Redis缓存数据访问状态错误,请刷新后重试!"),
|
||||
MESSAGE_SEND_FAIL("消息发送失败!"),
|
||||
TRANSACTION_MESSAGE_LOCAL_STATUS_ROLLBACK("本地数据操作失败,请联系管理员!"),
|
||||
TRANSACTION_MESSAGE_LOCAL_STATUS_UNKNOW("本地数据操作结果未知,请刷新后重试!");
|
||||
|
||||
// 下面的枚举值为特定枚举值,即开发者可以根据自己的项目需求定义更多的非通用枚举值
|
||||
|
||||
@@ -72,7 +75,7 @@ public enum ErrorCodeEnum {
|
||||
/**
|
||||
* 错误信息。
|
||||
*/
|
||||
private String errorMessage;
|
||||
private final String errorMessage;
|
||||
|
||||
/**
|
||||
* 获取错误信息。
|
||||
|
||||
@@ -36,18 +36,18 @@ public class MyRequestArgumentResolver implements HandlerMethodArgumentResolver
|
||||
|
||||
private static final String JSONBODY_ATTRIBUTE = "MY_REQUEST_BODY_ATTRIBUTE_XX";
|
||||
|
||||
private static Set<Class<?>> classSet = new HashSet<>();
|
||||
private static final Set<Class<?>> CLASS_SET = new HashSet<>();
|
||||
|
||||
static {
|
||||
classSet.add(Integer.class);
|
||||
classSet.add(Long.class);
|
||||
classSet.add(Short.class);
|
||||
classSet.add(Float.class);
|
||||
classSet.add(Double.class);
|
||||
classSet.add(Boolean.class);
|
||||
classSet.add(Byte.class);
|
||||
classSet.add(BigDecimal.class);
|
||||
classSet.add(Character.class);
|
||||
CLASS_SET.add(Integer.class);
|
||||
CLASS_SET.add(Long.class);
|
||||
CLASS_SET.add(Short.class);
|
||||
CLASS_SET.add(Float.class);
|
||||
CLASS_SET.add(Double.class);
|
||||
CLASS_SET.add(Boolean.class);
|
||||
CLASS_SET.add(Byte.class);
|
||||
CLASS_SET.add(BigDecimal.class);
|
||||
CLASS_SET.add(Character.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,7 +214,7 @@ public class MyRequestArgumentResolver implements HandlerMethodArgumentResolver
|
||||
}
|
||||
|
||||
private boolean isBasicDataTypes(Class<?> clazz) {
|
||||
return classSet.contains(clazz);
|
||||
return CLASS_SET.contains(clazz);
|
||||
}
|
||||
|
||||
private JSONObject getRequestBody(NativeWebRequest webRequest) throws IOException {
|
||||
|
||||
@@ -52,11 +52,17 @@ public class MyRelationParam {
|
||||
*/
|
||||
private boolean buildRemoteOneToOneWithDict;
|
||||
|
||||
/**
|
||||
* 是否组装本地一对多关联的标记。
|
||||
* 组装RelationOneToMany注解标记的字段。
|
||||
*/
|
||||
private boolean buildOneToMany;
|
||||
|
||||
/**
|
||||
* 是否组装主表对多对多中间表关联的标记。
|
||||
* 组装RelationManyToMany注解标记的字段。
|
||||
*/
|
||||
private boolean buildManyToManyRelation;
|
||||
private boolean buildRelationManyToMany;
|
||||
|
||||
/**
|
||||
* 是否组装聚合计算关联的标记。
|
||||
@@ -93,6 +99,7 @@ public class MyRelationParam {
|
||||
.buildRemoteOneToOneWithDict(true)
|
||||
.buildAggregation(true)
|
||||
.buildRemoteAggregation(true)
|
||||
.buildOneToMany(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -109,7 +116,8 @@ public class MyRelationParam {
|
||||
.buildRemoteOneToOneWithDict(true)
|
||||
.buildAggregation(true)
|
||||
.buildRemoteAggregation(true)
|
||||
.buildManyToManyRelation(true)
|
||||
.buildRelationManyToMany(true)
|
||||
.buildOneToMany(true)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.Map;
|
||||
@Component
|
||||
public class UpDownloaderFactory {
|
||||
|
||||
private Map<UploadStoreTypeEnum, BaseUpDownloader> upDownloaderMap = new HashMap<>();
|
||||
private final Map<UploadStoreTypeEnum, BaseUpDownloader> upDownloaderMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 根据存储类型获取上传下载对象。
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ApplicationContextHolder implements ApplicationContextAware {
|
||||
/**
|
||||
* 根据Bean的ClassType,获取Bean对象。
|
||||
*
|
||||
* @param beanType Bean的Class类型。。
|
||||
* @param beanType Bean的Class类型。
|
||||
* @param <T> 返回的Bean类型。
|
||||
* @return Bean对象。
|
||||
*/
|
||||
@@ -68,7 +68,7 @@ public class ApplicationContextHolder implements ApplicationContextAware {
|
||||
/**
|
||||
* 根据Bean的ClassType,获取Bean对象列表。
|
||||
*
|
||||
* @param beanType Bean的Class类型。。
|
||||
* @param beanType Bean的Class类型。
|
||||
* @param <T> 返回的Bean类型。
|
||||
* @return Bean对象列表。
|
||||
*/
|
||||
|
||||
@@ -101,11 +101,11 @@ public class ImportUtil {
|
||||
* @param <T> 导入数据对象类型。
|
||||
*/
|
||||
public abstract static class BaseImporter<T> {
|
||||
private Class<T> beanType;
|
||||
private List<T> batchRowList = new LinkedList<>();
|
||||
private int batchSize;
|
||||
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;
|
||||
private Map<String, String> headerColumnMap;
|
||||
|
||||
public BaseImporter(int batchSize, Class<T> beanType, Map<String, String> headerColumnMap) {
|
||||
if (batchSize <= 0) {
|
||||
@@ -185,7 +185,7 @@ public class ImportUtil {
|
||||
}
|
||||
|
||||
static class MyExcel07SaxReader<T> extends Excel07SaxReader {
|
||||
private BaseImporter<T> importer;
|
||||
private final BaseImporter<T> importer;
|
||||
|
||||
MyExcel07SaxReader(BaseImporter<T> importer) {
|
||||
super((sheetIndex, rowIndex, rowList) -> importer.doImport(rowIndex, rowList));
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.orange.demo.common.core.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
@@ -20,10 +20,10 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class MyCommonUtil {
|
||||
|
||||
private static Validator validator;
|
||||
private static final Validator VALIDATOR;
|
||||
|
||||
static {
|
||||
validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,9 +85,9 @@ public class MyCommonUtil {
|
||||
*/
|
||||
public static boolean isBlankOrNull(Object obj) {
|
||||
if (obj instanceof Collection) {
|
||||
return CollectionUtils.isEmpty((Collection<?>) obj);
|
||||
return CollUtil.isEmpty((Collection<?>) obj);
|
||||
}
|
||||
return obj == null || (obj instanceof CharSequence && StringUtils.isBlank((CharSequence) obj));
|
||||
return obj == null || (obj instanceof CharSequence && StrUtil.isBlank((CharSequence) obj));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +108,7 @@ public class MyCommonUtil {
|
||||
* @return 没有错误返回null,否则返回具体的错误信息。
|
||||
*/
|
||||
public static <T> String getModelValidationError(T model, Class<?>...groups) {
|
||||
Set<ConstraintViolation<T>> constraintViolations = validator.validate(model, groups);
|
||||
Set<ConstraintViolation<T>> constraintViolations = VALIDATOR.validate(model, groups);
|
||||
if (!constraintViolations.isEmpty()) {
|
||||
Iterator<ConstraintViolation<T>> it = constraintViolations.iterator();
|
||||
ConstraintViolation<T> constraint = it.next();
|
||||
@@ -136,6 +136,19 @@ public class MyCommonUtil {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将SQL Like中的通配符替换为字符本身的含义,以便于比较。
|
||||
*
|
||||
* @param str 待替换的字符串。
|
||||
* @return 替换后的字符串。
|
||||
*/
|
||||
public static String replaceSqlWildcard(String str) {
|
||||
if (StrUtil.isBlank(str)) {
|
||||
return str;
|
||||
}
|
||||
return StrUtil.replaceChars(StrUtil.replaceChars(str, "_", "\\_"), "%", "\\%");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象中,非空字段的名字列表。
|
||||
*
|
||||
@@ -149,7 +162,7 @@ public class MyCommonUtil {
|
||||
List<String> fieldNameList = Arrays.stream(fields)
|
||||
.filter(f -> ReflectUtil.getFieldValue(object, f) != null)
|
||||
.map(Field::getName).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(fieldNameList)) {
|
||||
if (CollUtil.isNotEmpty(fieldNameList)) {
|
||||
return fieldNameList.toArray(new String[]{});
|
||||
}
|
||||
return new String[]{};
|
||||
|
||||
@@ -2,11 +2,9 @@ package com.orange.demo.common.core.util;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.orange.demo.common.core.annotation.RelationConstDict;
|
||||
import com.orange.demo.common.core.annotation.RelationDict;
|
||||
import com.orange.demo.common.core.annotation.RelationOneToOne;
|
||||
import com.orange.demo.common.core.annotation.UploadFlagColumn;
|
||||
import com.orange.demo.common.core.annotation.*;
|
||||
import com.orange.demo.common.core.exception.MyRuntimeException;
|
||||
import com.orange.demo.common.core.object.TokenData;
|
||||
import com.orange.demo.common.core.object.Tuple2;
|
||||
import com.orange.demo.common.core.upload.UploadStoreInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -18,8 +16,8 @@ import tk.mybatis.mapper.entity.Example;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
@@ -46,10 +44,26 @@ public class MyModelUtil {
|
||||
* 日期型字段。
|
||||
*/
|
||||
public static final Integer DATE_FIELD_TYPE = 2;
|
||||
/**
|
||||
* 整个工程的实体对象中,创建者Id字段的Java对象名。
|
||||
*/
|
||||
public static final String CREATE_USER_ID_FIELD_NAME = "createUserId";
|
||||
/**
|
||||
* 整个工程的实体对象中,创建时间字段的Java对象名。
|
||||
*/
|
||||
public static final String CREATE_TIME_FIELD_NAME = "createTime";
|
||||
/**
|
||||
* 整个工程的实体对象中,更新者Id字段的Java对象名。
|
||||
*/
|
||||
public static final String UPDATE_USER_ID_FIELD_NAME = "updateUserId";
|
||||
/**
|
||||
* 整个工程的实体对象中,更新时间字段的Java对象名。
|
||||
*/
|
||||
public static final String UPDATE_TIME_FIELD_NAME = "updateTime";
|
||||
/**
|
||||
* mapToColumnName和mapToColumnInfo使用的缓存。
|
||||
*/
|
||||
private static Map<String, Tuple2<String, Integer>> cachedColumnInfoMap = new ConcurrentHashMap<>();
|
||||
private static final Map<String, Tuple2<String, Integer>> CACHED_COLUMNINFO_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 拷贝源类型的集合数据到目标类型的集合中,其中源类型和目标类型中的对象字段类型完全相同。
|
||||
@@ -140,17 +154,17 @@ public class MyModelUtil {
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append(modelClazz.getName()).append("-#-").append(fieldName);
|
||||
Tuple2<String, Integer> columnInfo = cachedColumnInfoMap.get(sb.toString());
|
||||
Tuple2<String, Integer> columnInfo = CACHED_COLUMNINFO_MAP.get(sb.toString());
|
||||
if (columnInfo == null) {
|
||||
Field field = ReflectUtil.getField(modelClazz, fieldName);
|
||||
if (field == null) {
|
||||
return null;
|
||||
}
|
||||
Column c = field.getAnnotation(Column.class);
|
||||
String typeName = field.getType().getSimpleName();
|
||||
String columnName = c == null ? fieldName : c.name();
|
||||
// 这里缺省情况下都是按照整型去处理,因为他覆盖太多的类型了。
|
||||
// 如Integer/Long/Double/BigDecimal,可根据实际情况完善和扩充。
|
||||
String typeName = field.getType().getSimpleName();
|
||||
Integer type = NUMERIC_FIELD_TYPE;
|
||||
if (String.class.getSimpleName().equals(typeName)) {
|
||||
type = STRING_FIELD_TYPE;
|
||||
@@ -158,7 +172,7 @@ public class MyModelUtil {
|
||||
type = DATE_FIELD_TYPE;
|
||||
}
|
||||
columnInfo = new Tuple2<>(columnName, type);
|
||||
cachedColumnInfoMap.put(sb.toString(), columnInfo);
|
||||
CACHED_COLUMNINFO_MAP.put(sb.toString(), columnInfo);
|
||||
}
|
||||
return columnInfo;
|
||||
}
|
||||
@@ -460,6 +474,43 @@ public class MyModelUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在主Model类型中,根据thisRelationField字段的RelationOneToMany注解参数,将被关联对象列表thatModelList中的数据,
|
||||
* 逐个关联到thisModelList每一个元素的thisRelationField字段中。
|
||||
*
|
||||
* @param thisClazz 主对象的Class对象。
|
||||
* @param thisModelList 主对象列表。
|
||||
* @param thatModelList 一对多关联对象列表。
|
||||
* @param thisRelationField 主表对象中保存被关联对象的字段名称。
|
||||
* @param <T> 主表对象类型。
|
||||
* @param <R> 从表对象类型。
|
||||
*/
|
||||
public static <T, R> void makeOneToManyRelation(
|
||||
Class<T> thisClazz, List<T> thisModelList, List<R> thatModelList, String thisRelationField) {
|
||||
if (CollectionUtils.isEmpty(thatModelList) || CollectionUtils.isEmpty(thisModelList)) {
|
||||
return;
|
||||
}
|
||||
// 这里不做任何空值判断,从而让配置错误在调试期间即可抛出
|
||||
Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField);
|
||||
RelationOneToMany r = thisTargetField.getAnnotation(RelationOneToMany.class);
|
||||
Field masterIdField = ReflectUtil.getField(thisClazz, r.masterIdField());
|
||||
Class<?> thatClass = r.slaveModelClass();
|
||||
Field slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField());
|
||||
Map<Object, List<R>> thatMap = new HashMap<>(20);
|
||||
thatModelList.forEach(thatModel -> {
|
||||
Object id = ReflectUtil.getFieldValue(thatModel, slaveIdField);
|
||||
List<R> thatModelSubList = thatMap.computeIfAbsent(id, k -> new LinkedList<>());
|
||||
thatModelSubList.add(thatModel);
|
||||
});
|
||||
thisModelList.forEach(thisModel -> {
|
||||
Object id = ReflectUtil.getFieldValue(thisModel, masterIdField);
|
||||
List<R> thatModel = thatMap.get(id);
|
||||
if (thatModel != null) {
|
||||
ReflectUtil.setFieldValue(thisModel, thisTargetField, thatModel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <M> Object normalize(boolean isMap, M model) {
|
||||
return isMap ? BeanUtil.beanToMap(model) : model;
|
||||
}
|
||||
@@ -525,6 +576,86 @@ public class MyModelUtil {
|
||||
return uploadStoreInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在插入实体对象数据之前,可以调用该方法,初始化通用字段的数据。
|
||||
*
|
||||
* @param data 实体对象。
|
||||
* @param <M> 实体对象类型。
|
||||
*/
|
||||
public static <M> void fillCommonsForInsert(M data) {
|
||||
try {
|
||||
Field createdByField = ReflectUtil.getField(data.getClass(), CREATE_USER_ID_FIELD_NAME);
|
||||
if (createdByField != null) {
|
||||
ReflectUtil.setAccessible(createdByField);
|
||||
createdByField.set(data, TokenData.takeFromRequest().getUserId());
|
||||
}
|
||||
Field createTimeField = ReflectUtil.getField(data.getClass(), CREATE_TIME_FIELD_NAME);
|
||||
if (createTimeField != null) {
|
||||
ReflectUtil.setAccessible(createTimeField);
|
||||
createTimeField.set(data, new Date());
|
||||
}
|
||||
Field updatedByField = ReflectUtil.getField(data.getClass(), UPDATE_USER_ID_FIELD_NAME);
|
||||
if (updatedByField != null) {
|
||||
ReflectUtil.setAccessible(updatedByField);
|
||||
updatedByField.set(data, TokenData.takeFromRequest().getUserId());
|
||||
}
|
||||
Field updateTimeField = ReflectUtil.getField(data.getClass(), UPDATE_TIME_FIELD_NAME);
|
||||
if (updateTimeField != null) {
|
||||
ReflectUtil.setAccessible(updateTimeField);
|
||||
updateTimeField.set(data, new Date());
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在更新实体对象数据之前,可以调用该方法,更新通用字段的数据。
|
||||
*
|
||||
* @param data 实体对象。
|
||||
* @param originalData 原有实体对象。
|
||||
* @param <M> 实体对象类型。
|
||||
*/
|
||||
public static <M> void fillCommonsForUpdate(M data, M originalData) {
|
||||
try {
|
||||
Object createdByValue = ReflectUtil.getFieldValue(originalData, CREATE_USER_ID_FIELD_NAME);
|
||||
if (createdByValue != null) {
|
||||
ReflectUtil.setFieldValue(data, CREATE_USER_ID_FIELD_NAME, createdByValue);
|
||||
}
|
||||
Object createTimeValue = ReflectUtil.getFieldValue(originalData, CREATE_TIME_FIELD_NAME);
|
||||
if (createTimeValue != null) {
|
||||
ReflectUtil.setFieldValue(data, CREATE_TIME_FIELD_NAME, createTimeValue);
|
||||
}
|
||||
Field updatedByField = ReflectUtil.getField(data.getClass(), UPDATE_USER_ID_FIELD_NAME);
|
||||
if (updatedByField != null) {
|
||||
ReflectUtil.setAccessible(updatedByField);
|
||||
updatedByField.set(data, TokenData.takeFromRequest().getUserId());
|
||||
}
|
||||
Field updateTimeField = ReflectUtil.getField(data.getClass(), UPDATE_TIME_FIELD_NAME);
|
||||
if (updateTimeField != null) {
|
||||
ReflectUtil.setAccessible(updateTimeField);
|
||||
updateTimeField.set(data, new Date());
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为实体对象字段设置缺省值。如果data对象中指定字段的值为NULL,则设置缺省值,否则跳过。
|
||||
* @param data 实体对象。
|
||||
* @param fieldName 实体对象字段名。
|
||||
* @param defaultValue 缺省值。
|
||||
* @param <M> 实体对象类型。
|
||||
* @param <V> 缺省值类型。
|
||||
*/
|
||||
public static <M, V> void setDefaultValue(M data, String fieldName, V defaultValue) {
|
||||
Object v = ReflectUtil.getFieldValue(data, fieldName);
|
||||
if (v == null) {
|
||||
ReflectUtil.setFieldValue(data, fieldName, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,7 @@ public class RsaUtil {
|
||||
/**
|
||||
* 用于封装随机产生的公钥与私钥
|
||||
*/
|
||||
private static Map<Integer, String> keyMap = new HashMap<>();
|
||||
private static final Map<Integer, String> KEY_MAP = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 随机生成密钥对。
|
||||
@@ -47,9 +47,9 @@ public class RsaUtil {
|
||||
String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
|
||||
// 将公钥和私钥保存到Map
|
||||
// 0表示公钥
|
||||
keyMap.put(0, publicKeyString);
|
||||
KEY_MAP.put(0, publicKeyString);
|
||||
// 1表示私钥
|
||||
keyMap.put(1, privateKeyString);
|
||||
KEY_MAP.put(1, privateKeyString);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,8 +96,8 @@ public class RsaUtil {
|
||||
// 生成公钥和私钥
|
||||
genKeyPair();
|
||||
// 加密字符串
|
||||
System.out.println("公钥:" + keyMap.get(0));
|
||||
System.out.println("私钥:" + keyMap.get(1));
|
||||
System.out.println("公钥:" + KEY_MAP.get(0));
|
||||
System.out.println("私钥:" + KEY_MAP.get(1));
|
||||
System.out.println("生成密钥消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒");
|
||||
System.out.println("生成后的公钥前端使用!");
|
||||
System.out.println("生成后的私钥后台使用!");
|
||||
@@ -105,11 +105,11 @@ public class RsaUtil {
|
||||
String message = "RSA测试ABCD~!@#$";
|
||||
System.out.println("原文:" + message);
|
||||
temp = System.currentTimeMillis();
|
||||
String messageEn = encrypt(message, keyMap.get(0));
|
||||
String messageEn = encrypt(message, KEY_MAP.get(0));
|
||||
System.out.println("密文:" + messageEn);
|
||||
System.out.println("加密消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒");
|
||||
temp = System.currentTimeMillis();
|
||||
String messageDe = decrypt(messageEn, keyMap.get(1));
|
||||
String messageDe = decrypt(messageEn, KEY_MAP.get(1));
|
||||
System.out.println("解密:" + messageDe);
|
||||
System.out.println("解密消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user