add
This commit is contained in:
@ -20,5 +20,6 @@
|
||||
<module>qiaoba-common-poi</module>
|
||||
</modules>
|
||||
|
||||
<description>qiaoba-common: 新建的common统一放在此模块下面</description>
|
||||
|
||||
</project>
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
<artifactId>qiaoba-common-base</artifactId>
|
||||
|
||||
<description>通用-基础模块</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
<artifactId>qiaoba-common-datasource</artifactId>
|
||||
|
||||
<description>通用-数据源模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Druid -->
|
||||
<dependency>
|
||||
@ -38,7 +40,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.qiaoba</groupId>
|
||||
<artifactId>qiaoba-common-web</artifactId>
|
||||
<artifactId>qiaoba-common-redis</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -1,16 +1,11 @@
|
||||
package com.qiaoba.common.database.interceptors;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
||||
import com.qiaoba.common.base.context.BaseContext;
|
||||
import com.qiaoba.common.database.handlers.schema.SchemaHandlerFactory;
|
||||
import org.apache.ibatis.executor.statement.StatementHandler;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -23,7 +18,6 @@ import java.util.Objects;
|
||||
public class SchemaInterceptor implements InnerInterceptor {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void beforePrepare(StatementHandler sh, Connection conn, Integer transactionTimeout) {
|
||||
|
||||
|
@ -1,308 +0,0 @@
|
||||
package com.qiaoba.common.database.mapper;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
||||
import com.qiaoba.common.web.utils.BeanCopyUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 自定义 Mapper 接口, 实现 自定义扩展
|
||||
*
|
||||
* @param <M> mapper 泛型
|
||||
* @param <T> table 泛型
|
||||
* @param <V> vo 泛型
|
||||
* @author ailanyin
|
||||
* @since 2023-04-23 17:20:32
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public interface BaseMapperPlus<M, T, V> extends BaseMapper<T> {
|
||||
|
||||
|
||||
/**
|
||||
* currentVoClass
|
||||
*
|
||||
* @return Vo
|
||||
*/
|
||||
default Class<V> currentVoClass() {
|
||||
return (Class<V>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* currentModelClass
|
||||
*
|
||||
* @return model
|
||||
*/
|
||||
default Class<T> currentModelClass() {
|
||||
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* currentMapperClass
|
||||
*
|
||||
* @return mapper
|
||||
*/
|
||||
default Class<M> currentMapperClass() {
|
||||
return (Class<M>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有
|
||||
*
|
||||
* @return all lst
|
||||
*/
|
||||
default List<T> selectList() {
|
||||
return this.selectList(new QueryWrapper<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量新增
|
||||
*
|
||||
* @param entityList list
|
||||
* @return 结果
|
||||
*/
|
||||
default boolean insertBatch(Collection<T> entityList) {
|
||||
return Db.saveBatch(entityList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新
|
||||
*
|
||||
* @param entityList list
|
||||
* @return 结果
|
||||
*/
|
||||
default boolean updateBatchById(Collection<T> entityList) {
|
||||
return Db.updateBatchById(entityList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量插入或更新
|
||||
*
|
||||
* @param entityList list
|
||||
* @return 结果
|
||||
*/
|
||||
default boolean insertOrUpdateBatch(Collection<T> entityList) {
|
||||
return Db.saveOrUpdateBatch(entityList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量插入(包含限制条数)
|
||||
*
|
||||
* @param entityList list
|
||||
* @param batchSize 最大调数
|
||||
* @return 结果
|
||||
*/
|
||||
default boolean insertBatch(Collection<T> entityList, int batchSize) {
|
||||
return Db.saveBatch(entityList, batchSize);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量更新(包含限制条数)
|
||||
*
|
||||
* @param entityList list
|
||||
* @param batchSize 最大调数
|
||||
* @return 结果
|
||||
*/
|
||||
default boolean updateBatchById(Collection<T> entityList, int batchSize) {
|
||||
return Db.updateBatchById(entityList, batchSize);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量插入或更新(包含限制条数)
|
||||
*
|
||||
* @param entityList list
|
||||
* @param batchSize 最大调数
|
||||
* @return 结果
|
||||
*/
|
||||
default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
|
||||
return Db.saveOrUpdateBatch(entityList, batchSize);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 插入或更新
|
||||
*
|
||||
* @param entity entity
|
||||
* @return 结果
|
||||
*/
|
||||
default boolean insertOrUpdate(T entity) {
|
||||
return Db.saveOrUpdate(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询Vo by id
|
||||
*
|
||||
* @param id 主键
|
||||
* @return Vo
|
||||
*/
|
||||
default V selectVoById(Serializable id) {
|
||||
return selectVoById(id, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 ID 查询
|
||||
*
|
||||
* @param id 主键
|
||||
* @param voClass Vo
|
||||
* @param <C> 泛型
|
||||
* @return Vo
|
||||
*/
|
||||
default <C> C selectVoById(Serializable id, Class<C> voClass) {
|
||||
T obj = this.selectById(id);
|
||||
if (ObjectUtil.isNull(obj)) {
|
||||
return null;
|
||||
}
|
||||
return BeanCopyUtil.copy(obj, voClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Ids 查询 list
|
||||
*
|
||||
* @param idList ids
|
||||
* @return list
|
||||
*/
|
||||
default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) {
|
||||
return selectVoBatchIds(idList, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Ids 查询 list
|
||||
*
|
||||
* @param idList ids
|
||||
* @param voClass Vo
|
||||
* @param <C> 泛型
|
||||
* @return list
|
||||
*/
|
||||
default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
|
||||
List<T> list = this.selectBatchIds(idList);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return BeanCopyUtil.copyList(list, voClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* selectVoByMap
|
||||
*
|
||||
* @param map map
|
||||
* @return Vo
|
||||
*/
|
||||
default List<V> selectVoByMap(Map<String, Object> map) {
|
||||
return selectVoByMap(map, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* selectVoByMap
|
||||
*
|
||||
* @param map map
|
||||
* @param voClass Vo
|
||||
* @param <C> 泛型
|
||||
* @return Vo
|
||||
*/
|
||||
default <C> List<C> selectVoByMap(Map<String, Object> map, Class<C> voClass) {
|
||||
List<T> list = this.selectByMap(map);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return BeanCopyUtil.copyList(list, voClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件查询一条记录
|
||||
*
|
||||
* @param wrapper 条件
|
||||
* @return Vo
|
||||
*/
|
||||
default V selectVoOne(Wrapper<T> wrapper) {
|
||||
return selectVoOne(wrapper, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件查询一条记录
|
||||
*
|
||||
* @param wrapper 条件
|
||||
* @param voClass Vo
|
||||
* @param <C> 泛型
|
||||
* @return Vo
|
||||
*/
|
||||
default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) {
|
||||
T obj = this.selectOne(wrapper);
|
||||
if (ObjectUtil.isNull(obj)) {
|
||||
return null;
|
||||
}
|
||||
return BeanCopyUtil.copy(obj, voClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件查询所有
|
||||
*
|
||||
* @param wrapper 条件
|
||||
* @return list
|
||||
*/
|
||||
default List<V> selectVoList(Wrapper<T> wrapper) {
|
||||
return selectVoList(wrapper, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件查询所有
|
||||
*
|
||||
* @param wrapper 条件
|
||||
* @param voClass Vo
|
||||
* @param <C> 泛型
|
||||
* @return list vo
|
||||
*/
|
||||
default <C> List<C> selectVoList(Wrapper<T> wrapper, Class<C> voClass) {
|
||||
List<T> list = this.selectList(wrapper);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return BeanCopyUtil.copyList(list, voClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询Vo
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param wrapper 条件
|
||||
* @param <P> 泛型
|
||||
* @return IPage
|
||||
*/
|
||||
default <P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper) {
|
||||
return selectVoPage(page, wrapper, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询Vo
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param wrapper 条件
|
||||
* @param voClass Vo
|
||||
* @param <C> 泛型
|
||||
* @param <P> 泛型
|
||||
* @return IPage
|
||||
*/
|
||||
default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) {
|
||||
IPage<T> pageData = this.selectPage(page, wrapper);
|
||||
IPage<C> voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
|
||||
if (CollUtil.isEmpty(pageData.getRecords())) {
|
||||
return (P) voPage;
|
||||
}
|
||||
voPage.setRecords(BeanCopyUtil.copyList(pageData.getRecords(), voClass));
|
||||
return (P) voPage;
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,8 @@ package com.qiaoba.common.database.monitor;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import com.qiaoba.common.base.constants.TenantConstant;
|
||||
import com.qiaoba.common.base.enums.DataBaseEnum;
|
||||
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
|
||||
@ -34,12 +36,16 @@ public class DatasourceConnectionMonitor {
|
||||
private DynamicDataSourceConfig dynamicDataSourceConfig;
|
||||
@Resource
|
||||
private DynamicDatasourceService dynamicDatasourceService;
|
||||
@Resource
|
||||
private LockTemplate lockTemplate;
|
||||
|
||||
private static Map<String, String> WAIT_UPDATE_DATASOURCE_STATUS = new ConcurrentHashMap<>();
|
||||
|
||||
private static final String LOCK_KEY = "lock4j:datasourceConnectionMonitor";
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// 1s钟运行一次
|
||||
// 1s 运行一次
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -47,47 +53,77 @@ public class DatasourceConnectionMonitor {
|
||||
if (!DynamicDataSourceConfig.COMPLETE_LOAD_DATASOURCE) {
|
||||
return;
|
||||
}
|
||||
log.trace("开始运行数据源监控线程, 时间: {}", new Date());
|
||||
for (String tenantId : DynamicDataSourceConfig.TENANT_IDS) {
|
||||
Object primary = DynamicDataSourceConfig.PRIMARY_DATASOURCE_MAP.get(tenantId);
|
||||
if (Objects.isNull(primary)) {
|
||||
// 说明初始化主要数据源的时候出错
|
||||
log.error("租户[{}]-目前主数据源异常, 开始切换备用数据源", tenantId);
|
||||
// 切换备用数据源
|
||||
changePrimary(tenantId);
|
||||
} else {
|
||||
DruidDataSource dataSource = (DruidDataSource) primary;
|
||||
try {
|
||||
Connection connection = dataSource.getConnection();
|
||||
if (check(connection, tenantId)) {
|
||||
// 说明数据源正常
|
||||
log.trace("租户[{}]-目前主数据源正常, 无需切换数据源", tenantId);
|
||||
// 主数据 处理任务
|
||||
if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId)) {
|
||||
handleJob();
|
||||
}
|
||||
IoUtil.close(connection);
|
||||
continue;
|
||||
}
|
||||
|
||||
log.error("租户[{}]-目前主数据源异常, 开始切换备用数据源", tenantId);
|
||||
IoUtil.close(connection);
|
||||
// 主数据源异常 切换备用数据源
|
||||
if (changePrimary(tenantId)) {
|
||||
// 备用切换成功, 关闭原有异常数据源
|
||||
IoUtil.close(dataSource);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// expire = -1 锁自动续期, 防止数据源过多或异常等待, 超过默认锁 30s
|
||||
final LockInfo lockInfo = lockTemplate.lock(LOCK_KEY, -1, 1000);
|
||||
//申请锁失败 说明集群中其他设备正在执行监控
|
||||
if (null == lockInfo) {
|
||||
return;
|
||||
}
|
||||
//申请锁成功
|
||||
try {
|
||||
// 执行监控
|
||||
datasourceConnectionMonitor();
|
||||
} finally {
|
||||
// 释放锁
|
||||
lockTemplate.releaseLock(lockInfo);
|
||||
}
|
||||
|
||||
log.trace("结束运行数据源监控线程, 时间: {}", new Date());
|
||||
}
|
||||
}, 0, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心监控内容
|
||||
*/
|
||||
private void datasourceConnectionMonitor() {
|
||||
log.trace("开始运行数据源监控线程, 时间: {}", new Date());
|
||||
for (String tenantId : DynamicDataSourceConfig.TENANT_IDS) {
|
||||
Object primary = DynamicDataSourceConfig.PRIMARY_DATASOURCE_MAP.get(tenantId);
|
||||
if (Objects.isNull(primary)) {
|
||||
// 说明初始化主要数据源的时候出错
|
||||
log.error("租户[{}]-目前主数据源异常, 开始切换备用数据源", tenantId);
|
||||
// 切换备用数据源
|
||||
changePrimary(tenantId);
|
||||
} else {
|
||||
DruidDataSource dataSource = (DruidDataSource) primary;
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
if (check(connection, tenantId)) {
|
||||
// 说明数据源正常
|
||||
log.trace("租户[{}]-目前主数据源正常, 无需切换数据源", tenantId);
|
||||
// 主数据 处理任务
|
||||
if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId)) {
|
||||
handleJob();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
log.error("租户[{}]-目前主数据源异常, 开始切换备用数据源", tenantId);
|
||||
// 主数据源异常 切换备用数据源
|
||||
if (changePrimary(tenantId)) {
|
||||
// 备用切换成功, 关闭原有异常数据源
|
||||
IoUtil.close(dataSource);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
|
||||
} finally {
|
||||
IoUtil.close(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.trace("结束运行数据源监控线程, 时间: {}", new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据源连接可用性
|
||||
*
|
||||
* @param conn 数据源
|
||||
* @param tenantId 租户ID
|
||||
* @return 结果
|
||||
*/
|
||||
private Boolean check(Connection conn, String tenantId) {
|
||||
Statement stmt = null;
|
||||
ResultSet rs = null;
|
||||
|
@ -8,7 +8,13 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* DataSourceProperties
|
||||
*
|
||||
* @author ailanyin
|
||||
* @version 1.0
|
||||
* @since 2022-09-22 04:20:28
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "qiaoba")
|
||||
@Data
|
||||
|
@ -5,7 +5,8 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.qiaoba.common.base.exceptions.ServiceException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.*;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
|
||||
/**
|
||||
* JdbcUtil
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
<artifactId>qiaoba-common-doc</artifactId>
|
||||
|
||||
<description>通用-文档(Knife4j)模块</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
@ -21,4 +23,4 @@
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
<artifactId>qiaoba-common-poi</artifactId>
|
||||
|
||||
<description>通用-poi(Excel, Word, Pdf等)模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- easypoi -->
|
||||
<dependency>
|
||||
|
@ -11,11 +11,13 @@
|
||||
|
||||
<artifactId>qiaoba-common-redis</artifactId>
|
||||
|
||||
<description>通用-Redis模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- lock4j -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>lock4j-redis-template-spring-boot-starter</artifactId>
|
||||
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.qiaoba</groupId>
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
<artifactId>qiaoba-common-web</artifactId>
|
||||
|
||||
<description>通用-Web模块(有controller的模块必须引入此模块)</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.qiaoba</groupId>
|
||||
|
@ -1,227 +0,0 @@
|
||||
package com.qiaoba.common.web.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.SimpleCache;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.cglib.beans.BeanCopier;
|
||||
import org.springframework.cglib.beans.BeanMap;
|
||||
import org.springframework.cglib.core.Converter;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* bean深拷贝工具(基于 cglib 性能优异)
|
||||
* <p>
|
||||
* 重点 cglib 不支持 拷贝到链式对象
|
||||
* 例如: 源对象 拷贝到 目标(链式对象)
|
||||
* 请区分好`浅拷贝`和`深拷贝`再做使用
|
||||
*
|
||||
* @author ailanyin
|
||||
* @version 1.0
|
||||
* @since 2023-04-23 15:34:59
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class BeanCopyUtil {
|
||||
|
||||
/**
|
||||
* 单对象基于class创建拷贝
|
||||
*
|
||||
* @param source 数据来源实体
|
||||
* @param desc 描述对象 转换后的对象
|
||||
* @return desc
|
||||
*/
|
||||
public static <T, V> V copy(T source, Class<V> desc) {
|
||||
if (ObjectUtil.isNull(source)) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectUtil.isNull(desc)) {
|
||||
return null;
|
||||
}
|
||||
final V target = ReflectUtil.newInstanceIfPossible(desc);
|
||||
return copy(source, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单对象基于对象创建拷贝
|
||||
*
|
||||
* @param source 数据来源实体
|
||||
* @param desc 转换后的对象
|
||||
* @return desc
|
||||
*/
|
||||
public static <T, V> V copy(T source, V desc) {
|
||||
if (ObjectUtil.isNull(source)) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectUtil.isNull(desc)) {
|
||||
return null;
|
||||
}
|
||||
BeanCopier beanCopier = BeanCopierCache.INSTANCE.get(source.getClass(), desc.getClass(), null);
|
||||
beanCopier.copy(source, desc, null);
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表对象基于class创建拷贝
|
||||
*
|
||||
* @param sourceList 数据来源实体列表
|
||||
* @param desc 描述对象 转换后的对象
|
||||
* @return desc
|
||||
*/
|
||||
public static <T, V> List<V> copyList(List<T> sourceList, Class<V> desc) {
|
||||
if (ObjectUtil.isNull(sourceList)) {
|
||||
return null;
|
||||
}
|
||||
if (CollUtil.isEmpty(sourceList)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return toList(sourceList, source -> {
|
||||
V target = ReflectUtil.newInstanceIfPossible(desc);
|
||||
copy(source, target);
|
||||
return target;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* bean拷贝到map
|
||||
*
|
||||
* @param bean 数据来源实体
|
||||
* @return map对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Map<String, Object> copyToMap(T bean) {
|
||||
if (ObjectUtil.isNull(bean)) {
|
||||
return null;
|
||||
}
|
||||
return BeanMap.create(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* map拷贝到bean
|
||||
*
|
||||
* @param map 数据来源
|
||||
* @param beanClass bean类
|
||||
* @return bean对象
|
||||
*/
|
||||
public static <T> T mapToBean(Map<String, Object> map, Class<T> beanClass) {
|
||||
if (MapUtil.isEmpty(map)) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectUtil.isNull(beanClass)) {
|
||||
return null;
|
||||
}
|
||||
T bean = ReflectUtil.newInstanceIfPossible(beanClass);
|
||||
return mapToBean(map, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* map拷贝到bean
|
||||
*
|
||||
* @param map 数据来源
|
||||
* @param bean bean对象
|
||||
* @return bean对象
|
||||
*/
|
||||
public static <T> T mapToBean(Map<String, Object> map, T bean) {
|
||||
if (MapUtil.isEmpty(map)) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectUtil.isNull(bean)) {
|
||||
return null;
|
||||
}
|
||||
BeanMap.create(bean).putAll(map);
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* map拷贝到map
|
||||
*
|
||||
* @param map 数据来源
|
||||
* @param clazz 返回的对象类型
|
||||
* @return map对象
|
||||
*/
|
||||
public static <T, V> Map<String, V> mapToMap(Map<String, T> map, Class<V> clazz) {
|
||||
if (MapUtil.isEmpty(map)) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectUtil.isNull(clazz)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, V> copyMap = new LinkedHashMap<>(map.size());
|
||||
map.forEach((k, v) -> copyMap.put(k, copy(v, clazz)));
|
||||
return copyMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* BeanCopier属性缓存<br>
|
||||
* 缓存用于防止多次反射造成的性能问题
|
||||
*
|
||||
* @author Looly
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public enum BeanCopierCache {
|
||||
/**
|
||||
* BeanCopier属性缓存单例
|
||||
*/
|
||||
INSTANCE;
|
||||
|
||||
private final SimpleCache<String, BeanCopier> cache = new SimpleCache<>();
|
||||
|
||||
/**
|
||||
* 获得类与转换器生成的key在{@link BeanCopier}的Map中对应的元素
|
||||
*
|
||||
* @param srcClass 源Bean的类
|
||||
* @param targetClass 目标Bean的类
|
||||
* @param converter 转换器
|
||||
* @return Map中对应的BeanCopier
|
||||
*/
|
||||
public BeanCopier get(Class<?> srcClass, Class<?> targetClass, Converter converter) {
|
||||
final String key = genKey(srcClass, targetClass, converter);
|
||||
return cache.get(key, () -> BeanCopier.create(srcClass, targetClass, converter != null));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得类与转换器生成的key
|
||||
*
|
||||
* @param srcClass 源Bean的类
|
||||
* @param targetClass 目标Bean的类
|
||||
* @param converter 转换器
|
||||
* @return 属性名和Map映射的key
|
||||
*/
|
||||
private String genKey(Class<?> srcClass, Class<?> targetClass, Converter converter) {
|
||||
final StringBuilder key = StrUtil.builder()
|
||||
.append(srcClass.getName()).append('#').append(targetClass.getName());
|
||||
if (null != converter) {
|
||||
key.append('#').append(converter.getClass().getName());
|
||||
}
|
||||
return key.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection转化为List集合,但是两者的泛型不同<br>
|
||||
* <B>{@code Collection<E> ------> List<T> } </B>
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param function collection中的泛型转化为list泛型的lambda表达式
|
||||
* @param <E> collection中的泛型
|
||||
* @param <T> List中的泛型
|
||||
* @return 转化后的list
|
||||
*/
|
||||
private static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
.map(function)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package com.qiaoba.common.web.utils;
|
||||
|
||||
import cn.hutool.http.ContentType;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.qiaoba.common.base.result.AjaxResult;
|
||||
|
||||
|
Reference in New Issue
Block a user