mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-10 07:05:02 +08:00
refactor(data/mp): 将 MP 的 CrudRepository 迁移至 ServiceImpl 类中,减少两层继承,解决层级过多出现 Sonar 警告的问题
This commit is contained in:
@@ -17,33 +17,258 @@
|
|||||||
package top.continew.starter.data.service.impl;
|
package top.continew.starter.data.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.ClassUtil;
|
import cn.hutool.core.util.ClassUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.enums.SqlMethod;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.MapperProxyMetadata;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.*;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
|
||||||
|
import com.baomidou.mybatisplus.extension.repository.AbstractRepository;
|
||||||
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
|
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
|
||||||
|
import com.baomidou.mybatisplus.extension.repository.IRepository;
|
||||||
|
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
|
||||||
|
import org.apache.ibatis.binding.MapperMethod;
|
||||||
|
import org.apache.ibatis.logging.Log;
|
||||||
|
import org.apache.ibatis.logging.LogFactory;
|
||||||
|
import org.apache.ibatis.session.SqlSession;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import top.continew.starter.core.util.ReflectUtils;
|
import top.continew.starter.core.util.ReflectUtils;
|
||||||
import top.continew.starter.data.service.IService;
|
import top.continew.starter.data.service.IService;
|
||||||
import top.continew.starter.core.util.validation.CheckUtils;
|
import top.continew.starter.core.util.validation.CheckUtils;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用业务实现类
|
* 通用业务实现类
|
||||||
*
|
*
|
||||||
|
* <p>将 MP 的 {@link CrudRepository} 迁移至本类中,减少两层继承,解决层级过多出现 Sonar 警告的问题</p>
|
||||||
|
*
|
||||||
|
* @see CrudRepository
|
||||||
* @param <M> Mapper 接口
|
* @param <M> Mapper 接口
|
||||||
* @param <T> 实体类型
|
* @param <T> 实体类型
|
||||||
|
* @author hubin (<a href="https://gitee.com/baomidou/mybatis-plus">MyBatis Plus</a>)
|
||||||
* @author Charles7c
|
* @author Charles7c
|
||||||
* @since 1.5.0
|
* @since 1.5.0
|
||||||
*/
|
*/
|
||||||
public class ServiceImpl<M extends BaseMapper<T>, T> extends CrudRepository<M, T> implements IService<T> {
|
public abstract class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected M baseMapper;
|
||||||
|
private Class<T> entityClass;
|
||||||
|
private Class<M> mapperClass;
|
||||||
private List<Field> entityFields;
|
private List<Field> entityFields;
|
||||||
|
private volatile SqlSessionFactory sqlSessionFactory;
|
||||||
|
private final Log innerLog = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TableId 注解存在更新记录,否插入一条记录
|
||||||
|
*
|
||||||
|
* @param entity 实体对象
|
||||||
|
* @return boolean
|
||||||
|
* @see AbstractRepository#saveOrUpdate(Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean saveOrUpdate(T entity) {
|
||||||
|
return getBaseMapper().insertOrUpdate(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 Wrapper,查询一条记录
|
||||||
|
*
|
||||||
|
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||||
|
* @param throwEx 有多个 result 是否抛出异常
|
||||||
|
* @return 单条数据
|
||||||
|
* @see AbstractRepository#getOne(Wrapper, boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
|
||||||
|
return getBaseMapper().selectOne(queryWrapper, throwEx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 Wrapper,查询一条记录
|
||||||
|
*
|
||||||
|
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||||
|
* @param throwEx 有多个 result 是否抛出异常
|
||||||
|
* @return {@link Optional} 返回一个Optional对象
|
||||||
|
* @see AbstractRepository#getOneOpt(Wrapper, boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Optional<T> getOneOpt(Wrapper<T> queryWrapper, boolean throwEx) {
|
||||||
|
return Optional.ofNullable(getBaseMapper().selectOne(queryWrapper, throwEx));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 Wrapper,查询一条记录
|
||||||
|
*
|
||||||
|
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||||
|
* @return 单条数据
|
||||||
|
* @see AbstractRepository#getMap(Wrapper)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
|
||||||
|
return SqlHelper.getObject(innerLog, getBaseMapper().selectMaps(queryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 Wrapper,查询一条记录
|
||||||
|
*
|
||||||
|
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||||
|
* @param mapper 转换函数
|
||||||
|
* @return 单条数据
|
||||||
|
* @see AbstractRepository#getObj(Wrapper, Function)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
|
||||||
|
return SqlHelper.getObject(innerLog, listObjs(queryWrapper, mapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行批量操作
|
||||||
|
*
|
||||||
|
* @param list 数据集合
|
||||||
|
* @param batchSize 批量大小
|
||||||
|
* @param consumer 执行方法
|
||||||
|
* @param <E> 泛型
|
||||||
|
* @return 操作结果
|
||||||
|
* @see AbstractRepository#executeBatch(Collection, int, BiConsumer)
|
||||||
|
*/
|
||||||
|
protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
|
||||||
|
return SqlHelper.executeBatch(getSqlSessionFactory(), this.innerLog, list, batchSize, consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行批量操作(默认批次提交数量{@link IRepository#DEFAULT_BATCH_SIZE})
|
||||||
|
*
|
||||||
|
* @param list 数据集合
|
||||||
|
* @param consumer 执行方法
|
||||||
|
* @param <E> 泛型
|
||||||
|
* @return 操作结果
|
||||||
|
* @see AbstractRepository#executeBatch(Collection, BiConsumer)
|
||||||
|
*/
|
||||||
|
protected <E> boolean executeBatch(Collection<E> list, BiConsumer<SqlSession, E> consumer) {
|
||||||
|
return executeBatch(list, DEFAULT_BATCH_SIZE, consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 ID 删除
|
||||||
|
*
|
||||||
|
* @param id 主键(类型必须与实体类型字段保持一致)
|
||||||
|
* @param useFill 是否启用填充(为true的情况,会将入参转换实体进行delete删除)
|
||||||
|
* @return 删除结果
|
||||||
|
* @see AbstractRepository#removeById(Serializable, boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean removeById(Serializable id, boolean useFill) {
|
||||||
|
return SqlHelper.retBool(getBaseMapper().deleteById(id, useFill));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量插入
|
||||||
|
*
|
||||||
|
* @param entityList 数据集合
|
||||||
|
* @param batchSize 批量大小
|
||||||
|
* @return boolean
|
||||||
|
* @see CrudRepository#saveBatch(Collection, int)
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public boolean saveBatch(Collection<T> entityList, int batchSize) {
|
||||||
|
String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
|
||||||
|
return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量插入
|
||||||
|
*
|
||||||
|
* @param entityList 数据集合
|
||||||
|
* @param batchSize 批量大小
|
||||||
|
* @return boolean
|
||||||
|
* @see CrudRepository#saveOrUpdateBatch(Collection, int)
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
|
||||||
|
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.getEntityClass());
|
||||||
|
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(getSqlSessionFactory(), this
|
||||||
|
.getMapperClass(), this.innerLog, entityList, batchSize, (sqlSession, entity) -> {
|
||||||
|
Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
|
||||||
|
return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession
|
||||||
|
.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
|
||||||
|
}, (sqlSession, entity) -> {
|
||||||
|
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
|
||||||
|
param.put(Constants.ENTITY, entity);
|
||||||
|
sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新
|
||||||
|
*
|
||||||
|
* @param entityList 数据集合
|
||||||
|
* @param batchSize 批量大小
|
||||||
|
* @return boolean
|
||||||
|
* @see CrudRepository#updateBatchById(Collection, int)
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
|
||||||
|
String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
|
||||||
|
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
|
||||||
|
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
|
||||||
|
param.put(Constants.ENTITY, entity);
|
||||||
|
sqlSession.update(sqlStatement, param);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T getById(Serializable id) {
|
public T getById(Serializable id) {
|
||||||
return this.getById(id, true);
|
return this.getById(id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public M getBaseMapper() {
|
||||||
|
Assert.notNull(this.baseMapper, "baseMapper can not be null");
|
||||||
|
return this.baseMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getEntityClass() {
|
||||||
|
if (this.entityClass == null) {
|
||||||
|
this.entityClass = (Class<T>)GenericTypeUtils.resolveTypeArguments(this
|
||||||
|
.getMapperClass(), BaseMapper.class)[0];
|
||||||
|
}
|
||||||
|
return this.entityClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前 Mapper 类型
|
||||||
|
*
|
||||||
|
* @return 当前 Mapper 类型
|
||||||
|
* @see CrudRepository#getMapperClass()
|
||||||
|
*/
|
||||||
|
public Class<M> getMapperClass() {
|
||||||
|
if (this.mapperClass == null) {
|
||||||
|
MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this.getBaseMapper());
|
||||||
|
this.mapperClass = (Class<M>)mapperProxyMetadata.getMapperInterface();
|
||||||
|
}
|
||||||
|
return this.mapperClass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前实体类型字段
|
* 获取当前实体类型字段
|
||||||
*
|
*
|
||||||
@@ -56,6 +281,31 @@ public class ServiceImpl<M extends BaseMapper<T>, T> extends CrudRepository<M, T
|
|||||||
return this.entityFields;
|
return this.entityFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 SqlSessionFactory
|
||||||
|
*
|
||||||
|
* @return SqlSessionFactory
|
||||||
|
* @see AbstractRepository#getSqlSessionFactory()
|
||||||
|
*/
|
||||||
|
protected SqlSessionFactory getSqlSessionFactory() {
|
||||||
|
if (this.sqlSessionFactory == null) {
|
||||||
|
MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this.getBaseMapper());
|
||||||
|
this.sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mapperProxyMetadata.getSqlSession());
|
||||||
|
}
|
||||||
|
return this.sqlSessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取mapperStatementId
|
||||||
|
*
|
||||||
|
* @param sqlMethod 方法名
|
||||||
|
* @return 命名id
|
||||||
|
* @see CrudRepository#getSqlStatement(SqlMethod)
|
||||||
|
*/
|
||||||
|
protected String getSqlStatement(SqlMethod sqlMethod) {
|
||||||
|
return SqlHelper.getSqlStatement(this.getMapperClass(), sqlMethod);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 ID 查询
|
* 根据 ID 查询
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user