parent
42b5013cc1
commit
8be96df11e
@ -0,0 +1,229 @@ |
||||
package edu.ncst.award.common.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.enums.SqlMethod; |
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo; |
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; |
||||
import com.baomidou.mybatisplus.core.toolkit.*; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; |
||||
import edu.ncst.award.common.util.BeanCopyUtils; |
||||
import org.apache.ibatis.binding.MapperMethod; |
||||
import org.apache.ibatis.logging.Log; |
||||
import org.apache.ibatis.logging.LogFactory; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Objects; |
||||
|
||||
/** |
||||
* 自定义 Mapper 接口, 实现 自定义扩展 |
||||
* |
||||
* @param <M> mapper 泛型 |
||||
* @param <T> table 泛型 |
||||
* @param <V> vo 泛型 |
||||
* @author Lion Li |
||||
* @since 2021-05-13 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public interface BaseMapperPlus<M, T, V> extends BaseMapper<T> { |
||||
|
||||
Log log = LogFactory.getLog(BaseMapperPlus.class); |
||||
|
||||
int DEFAULT_BATCH_SIZE = 1000; |
||||
|
||||
default Class<V> currentVoClass() { |
||||
return (Class<V>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 2); |
||||
} |
||||
|
||||
default Class<T> currentModelClass() { |
||||
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 1); |
||||
} |
||||
|
||||
default Class<M> currentMapperClass() { |
||||
return (Class<M>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 0); |
||||
} |
||||
|
||||
default List<T> selectList() { |
||||
return this.selectList(new QueryWrapper<>()); |
||||
} |
||||
|
||||
/** |
||||
* 批量插入 |
||||
*/ |
||||
default boolean insertBatch(Collection<T> entityList) { |
||||
return insertBatch(entityList, DEFAULT_BATCH_SIZE); |
||||
} |
||||
|
||||
/** |
||||
* 批量更新 |
||||
*/ |
||||
default boolean updateBatchById(Collection<T> entityList) { |
||||
return updateBatchById(entityList, DEFAULT_BATCH_SIZE); |
||||
} |
||||
|
||||
/** |
||||
* 批量插入或更新 |
||||
*/ |
||||
default boolean insertOrUpdateBatch(Collection<T> entityList) { |
||||
return insertOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE); |
||||
} |
||||
|
||||
/** |
||||
* 批量插入(包含限制条数) |
||||
*/ |
||||
default boolean insertBatch(Collection<T> entityList, int batchSize) { |
||||
String sqlStatement = SqlHelper.getSqlStatement(this.currentMapperClass(), SqlMethod.INSERT_ONE); |
||||
return SqlHelper.executeBatch(this.currentModelClass(), log, entityList, batchSize, |
||||
(sqlSession, entity) -> sqlSession.insert(sqlStatement, entity)); |
||||
} |
||||
|
||||
/** |
||||
* 批量更新(包含限制条数) |
||||
*/ |
||||
default boolean updateBatchById(Collection<T> entityList, int batchSize) { |
||||
String sqlStatement = SqlHelper.getSqlStatement(this.currentMapperClass(), SqlMethod.UPDATE_BY_ID); |
||||
return SqlHelper.executeBatch(this.currentModelClass(), log, entityList, batchSize, |
||||
(sqlSession, entity) -> { |
||||
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>(); |
||||
param.put(Constants.ENTITY, entity); |
||||
sqlSession.update(sqlStatement, param); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 批量插入或更新(包含限制条数) |
||||
*/ |
||||
default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) { |
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.currentModelClass()); |
||||
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!"); |
||||
String keyProperty = tableInfo.getKeyProperty(); |
||||
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!"); |
||||
return SqlHelper.saveOrUpdateBatch(this.currentModelClass(), this.currentMapperClass(), log, entityList, batchSize, (sqlSession, entity) -> { |
||||
Object idVal = tableInfo.getPropertyValue(entity, keyProperty); |
||||
String sqlStatement = SqlHelper.getSqlStatement(this.currentMapperClass(), SqlMethod.SELECT_BY_ID); |
||||
return StringUtils.checkValNull(idVal) |
||||
|| CollectionUtils.isEmpty(sqlSession.selectList(sqlStatement, entity)); |
||||
}, (sqlSession, entity) -> { |
||||
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>(); |
||||
param.put(Constants.ENTITY, entity); |
||||
String sqlStatement = SqlHelper.getSqlStatement(this.currentMapperClass(), SqlMethod.UPDATE_BY_ID); |
||||
sqlSession.update(sqlStatement, param); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 插入或更新(包含限制条数) |
||||
*/ |
||||
default boolean insertOrUpdate(T entity) { |
||||
if (null != entity) { |
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.currentModelClass()); |
||||
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!"); |
||||
String keyProperty = tableInfo.getKeyProperty(); |
||||
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!"); |
||||
Object idVal = tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty()); |
||||
return StringUtils.checkValNull(idVal) || Objects.isNull(selectById((Serializable) idVal)) ? insert(entity) > 0 : updateById(entity) > 0; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
default V selectVoById(Serializable id) { |
||||
return selectVoById(id, this.currentVoClass()); |
||||
} |
||||
|
||||
/** |
||||
* 根据 ID 查询 |
||||
*/ |
||||
default <C> C selectVoById(Serializable id, Class<C> voClass) { |
||||
T obj = this.selectById(id); |
||||
if (ObjectUtil.isNull(obj)) { |
||||
return null; |
||||
} |
||||
return BeanCopyUtils.copy(obj, voClass); |
||||
} |
||||
|
||||
default List<V> selectVoById(Collection<? extends Serializable> idList) { |
||||
return selectVoBatchIds(idList, this.currentVoClass()); |
||||
} |
||||
|
||||
/** |
||||
* 查询(根据ID 批量查询) |
||||
*/ |
||||
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 BeanCopyUtils.copyList(list, voClass); |
||||
} |
||||
|
||||
default List<V> selectVoByMap(Map<String, Object> map) { |
||||
return selectVoByMap(map, this.currentVoClass()); |
||||
} |
||||
|
||||
/** |
||||
* 查询(根据 columnMap 条件) |
||||
*/ |
||||
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 BeanCopyUtils.copyList(list, voClass); |
||||
} |
||||
|
||||
default V selectVoOne(Wrapper<T> wrapper) { |
||||
return selectVoOne(wrapper, this.currentVoClass()); |
||||
} |
||||
|
||||
/** |
||||
* 根据 entity 条件,查询一条记录 |
||||
*/ |
||||
default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) { |
||||
T obj = this.selectOne(wrapper); |
||||
if (ObjectUtil.isNull(obj)) { |
||||
return null; |
||||
} |
||||
return BeanCopyUtils.copy(obj, voClass); |
||||
} |
||||
|
||||
default List<V> selectVoList(Wrapper<T> wrapper) { |
||||
return selectVoList(wrapper, this.currentVoClass()); |
||||
} |
||||
|
||||
/** |
||||
* 根据 entity 条件,查询全部记录 |
||||
*/ |
||||
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 BeanCopyUtils.copyList(list, voClass); |
||||
} |
||||
|
||||
default <P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper) { |
||||
return selectVoPage(page, wrapper, this.currentVoClass()); |
||||
} |
||||
|
||||
/** |
||||
* 分页查询VO |
||||
*/ |
||||
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(BeanCopyUtils.copyList(pageData.getRecords(), voClass)); |
||||
return (P) voPage; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,126 @@ |
||||
package edu.ncst.award.common.util; |
||||
|
||||
import cn.hutool.core.collection.CollUtil; |
||||
import cn.hutool.core.map.MapUtil; |
||||
import cn.hutool.core.util.ObjectUtil; |
||||
import cn.hutool.core.util.ReflectUtil; |
||||
import cn.hutool.extra.cglib.CglibUtil; |
||||
import lombok.AccessLevel; |
||||
import lombok.NoArgsConstructor; |
||||
import lombok.val; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* bean深拷贝工具(基于 cglib 性能优异) |
||||
* <p> |
||||
* 重点 cglib 不支持 拷贝到链式对象 |
||||
* 例如: 源对象 拷贝到 目标(链式对象) |
||||
* 请区分好`浅拷贝`和`深拷贝`再做使用 |
||||
* |
||||
* @author Lion Li |
||||
*/ |
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE) |
||||
public class BeanCopyUtils { |
||||
|
||||
/** |
||||
* 单对象基于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; |
||||
} |
||||
return CglibUtil.copy(source, desc); |
||||
} |
||||
|
||||
/** |
||||
* 单对象基于对象创建拷贝 |
||||
* |
||||
* @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; |
||||
} |
||||
CglibUtil.copy(source, desc); |
||||
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 CglibUtil.copyList(sourceList, () -> ReflectUtil.newInstanceIfPossible(desc)); |
||||
} |
||||
|
||||
/** |
||||
* bean拷贝到map |
||||
* |
||||
* @param bean 数据来源实体 |
||||
* @return map对象 |
||||
*/ |
||||
@SuppressWarnings({"unchecked"}) |
||||
public static <T> Map<String, Object> copyToMap(T bean) { |
||||
if (ObjectUtil.isNull(bean)) { |
||||
return null; |
||||
} |
||||
return CglibUtil.toMap(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; |
||||
} |
||||
return CglibUtil.toBean(map, beanClass); |
||||
} |
||||
|
||||
/** |
||||
* 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; |
||||
} |
||||
return CglibUtil.fillBean(map, bean); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue