parent
3681150010
commit
3dff529920
@ -3,9 +3,10 @@ package org.dromara.common.mybatis.annotation;
|
|||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据权限
|
* 数据权限注解,用于标记数据权限的占位符关键字和替换值
|
||||||
*
|
* <p>
|
||||||
* 一个注解只能对应一个模板
|
* 一个注解只能对应一个模板
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
* @version 3.5.0
|
* @version 3.5.0
|
||||||
@ -16,12 +17,16 @@ import java.lang.annotation.*;
|
|||||||
public @interface DataColumn {
|
public @interface DataColumn {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 占位符关键字
|
* 数据权限模板的占位符关键字,默认为 "deptName"
|
||||||
|
*
|
||||||
|
* @return 占位符关键字数组
|
||||||
*/
|
*/
|
||||||
String[] key() default "deptName";
|
String[] key() default "deptName";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 占位符替换值
|
* 数据权限模板的占位符替换值,默认为 "dept_id"
|
||||||
|
*
|
||||||
|
* @return 占位符替换值数组
|
||||||
*/
|
*/
|
||||||
String[] value() default "dept_id";
|
String[] value() default "dept_id";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ package org.dromara.common.mybatis.annotation;
|
|||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据权限组
|
* 数据权限组注解,用于标记数据权限配置数组
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
* @version 3.5.0
|
* @version 3.5.0
|
||||||
@ -13,6 +13,11 @@ import java.lang.annotation.*;
|
|||||||
@Documented
|
@Documented
|
||||||
public @interface DataPermission {
|
public @interface DataPermission {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据权限配置数组,用于指定数据权限的占位符关键字和替换值
|
||||||
|
*
|
||||||
|
* @return 数据权限配置数组
|
||||||
|
*/
|
||||||
DataColumn[] value();
|
DataColumn[] value();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class BaseEntity implements Serializable {
|
public class BaseEntity implements Serializable {
|
||||||
|
|
||||||
|
@ -34,20 +34,38 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
|
|
||||||
Log log = LogFactory.getLog(BaseMapperPlus.class);
|
Log log = LogFactory.getLog(BaseMapperPlus.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前实例对象关联的泛型类型 V 的 Class 对象
|
||||||
|
*
|
||||||
|
* @return 返回当前实例对象关联的泛型类型 V 的 Class 对象
|
||||||
|
*/
|
||||||
default Class<V> currentVoClass() {
|
default Class<V> currentVoClass() {
|
||||||
return (Class<V>) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[1];
|
return (Class<V>) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前实例对象关联的泛型类型 T 的 Class 对象
|
||||||
|
*
|
||||||
|
* @return 返回当前实例对象关联的泛型类型 T 的 Class 对象
|
||||||
|
*/
|
||||||
default Class<T> currentModelClass() {
|
default Class<T> currentModelClass() {
|
||||||
return (Class<T>) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[0];
|
return (Class<T>) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用默认的查询条件查询并返回结果列表
|
||||||
|
*
|
||||||
|
* @return 返回查询结果的列表
|
||||||
|
*/
|
||||||
default List<T> selectList() {
|
default List<T> selectList() {
|
||||||
return this.selectList(new QueryWrapper<>());
|
return this.selectList(new QueryWrapper<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量插入
|
* 批量插入实体对象集合
|
||||||
|
*
|
||||||
|
* @param entityList 实体对象集合
|
||||||
|
* @return 插入操作是否成功的布尔值
|
||||||
*/
|
*/
|
||||||
default boolean insertBatch(Collection<T> entityList) {
|
default boolean insertBatch(Collection<T> entityList) {
|
||||||
Db.saveBatch(entityList);
|
Db.saveBatch(entityList);
|
||||||
@ -56,7 +74,10 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量更新
|
* 批量根据ID更新实体对象集合
|
||||||
|
*
|
||||||
|
* @param entityList 实体对象集合
|
||||||
|
* @return 更新操作是否成功的布尔值
|
||||||
*/
|
*/
|
||||||
default boolean updateBatchById(Collection<T> entityList) {
|
default boolean updateBatchById(Collection<T> entityList) {
|
||||||
Db.updateBatchById(entityList);
|
Db.updateBatchById(entityList);
|
||||||
@ -65,7 +86,10 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量插入或更新
|
* 批量插入或更新实体对象集合
|
||||||
|
*
|
||||||
|
* @param entityList 实体对象集合
|
||||||
|
* @return 插入或更新操作是否成功的布尔值
|
||||||
*/
|
*/
|
||||||
default boolean insertOrUpdateBatch(Collection<T> entityList) {
|
default boolean insertOrUpdateBatch(Collection<T> entityList) {
|
||||||
Db.saveOrUpdateBatch(entityList);
|
Db.saveOrUpdateBatch(entityList);
|
||||||
@ -74,7 +98,11 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量插入(包含限制条数)
|
* 批量插入实体对象集合并指定批处理大小
|
||||||
|
*
|
||||||
|
* @param entityList 实体对象集合
|
||||||
|
* @param batchSize 批处理大小
|
||||||
|
* @return 插入操作是否成功的布尔值
|
||||||
*/
|
*/
|
||||||
default boolean insertBatch(Collection<T> entityList, int batchSize) {
|
default boolean insertBatch(Collection<T> entityList, int batchSize) {
|
||||||
Db.saveBatch(entityList, batchSize);
|
Db.saveBatch(entityList, batchSize);
|
||||||
@ -83,7 +111,11 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量更新(包含限制条数)
|
* 批量根据ID更新实体对象集合并指定批处理大小
|
||||||
|
*
|
||||||
|
* @param entityList 实体对象集合
|
||||||
|
* @param batchSize 批处理大小
|
||||||
|
* @return 更新操作是否成功的布尔值
|
||||||
*/
|
*/
|
||||||
default boolean updateBatchById(Collection<T> entityList, int batchSize) {
|
default boolean updateBatchById(Collection<T> entityList, int batchSize) {
|
||||||
Db.updateBatchById(entityList, batchSize);
|
Db.updateBatchById(entityList, batchSize);
|
||||||
@ -92,7 +124,11 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量插入或更新(包含限制条数)
|
* 批量插入或更新实体对象集合并指定批处理大小
|
||||||
|
*
|
||||||
|
* @param entityList 实体对象集合
|
||||||
|
* @param batchSize 批处理大小
|
||||||
|
* @return 插入或更新操作是否成功的布尔值
|
||||||
*/
|
*/
|
||||||
default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
|
default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
|
||||||
Db.saveOrUpdateBatch(entityList, batchSize);
|
Db.saveOrUpdateBatch(entityList, batchSize);
|
||||||
@ -100,12 +136,23 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询单个VO对象
|
||||||
|
*
|
||||||
|
* @param id 主键ID
|
||||||
|
* @return 查询到的单个VO对象
|
||||||
|
*/
|
||||||
default V selectVoById(Serializable id) {
|
default V selectVoById(Serializable id) {
|
||||||
return selectVoById(id, this.currentVoClass());
|
return selectVoById(id, this.currentVoClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 ID 查询
|
* 根据ID查询单个VO对象并将其转换为指定的VO类
|
||||||
|
*
|
||||||
|
* @param id 主键ID
|
||||||
|
* @param voClass 要转换的VO类的Class对象
|
||||||
|
* @param <C> VO类的类型
|
||||||
|
* @return 查询到的单个VO对象,经过转换为指定的VO类后返回
|
||||||
*/
|
*/
|
||||||
default <C> C selectVoById(Serializable id, Class<C> voClass) {
|
default <C> C selectVoById(Serializable id, Class<C> voClass) {
|
||||||
T obj = this.selectById(id);
|
T obj = this.selectById(id);
|
||||||
@ -115,12 +162,23 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
return MapstructUtils.convert(obj, voClass);
|
return MapstructUtils.convert(obj, voClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID集合批量查询VO对象列表
|
||||||
|
*
|
||||||
|
* @param idList 主键ID集合
|
||||||
|
* @return 查询到的VO对象列表
|
||||||
|
*/
|
||||||
default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) {
|
default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) {
|
||||||
return selectVoBatchIds(idList, this.currentVoClass());
|
return selectVoBatchIds(idList, this.currentVoClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询(根据ID 批量查询)
|
* 根据ID集合批量查询实体对象列表,并将其转换为指定的VO对象列表
|
||||||
|
*
|
||||||
|
* @param idList 主键ID集合
|
||||||
|
* @param voClass 要转换的VO类的Class对象
|
||||||
|
* @param <C> VO类的类型
|
||||||
|
* @return 查询到的VO对象列表,经过转换为指定的VO类后返回
|
||||||
*/
|
*/
|
||||||
default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
|
default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
|
||||||
List<T> list = this.selectBatchIds(idList);
|
List<T> list = this.selectBatchIds(idList);
|
||||||
@ -130,12 +188,23 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
return MapstructUtils.convert(list, voClass);
|
return MapstructUtils.convert(list, voClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据查询条件Map查询VO对象列表
|
||||||
|
*
|
||||||
|
* @param map 查询条件Map
|
||||||
|
* @return 查询到的VO对象列表
|
||||||
|
*/
|
||||||
default List<V> selectVoByMap(Map<String, Object> map) {
|
default List<V> selectVoByMap(Map<String, Object> map) {
|
||||||
return selectVoByMap(map, this.currentVoClass());
|
return selectVoByMap(map, this.currentVoClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询(根据 columnMap 条件)
|
* 根据查询条件Map查询实体对象列表,并将其转换为指定的VO对象列表
|
||||||
|
*
|
||||||
|
* @param map 查询条件Map
|
||||||
|
* @param voClass 要转换的VO类的Class对象
|
||||||
|
* @param <C> VO类的类型
|
||||||
|
* @return 查询到的VO对象列表,经过转换为指定的VO类后返回
|
||||||
*/
|
*/
|
||||||
default <C> List<C> selectVoByMap(Map<String, Object> map, Class<C> voClass) {
|
default <C> List<C> selectVoByMap(Map<String, Object> map, Class<C> voClass) {
|
||||||
List<T> list = this.selectByMap(map);
|
List<T> list = this.selectByMap(map);
|
||||||
@ -145,23 +214,47 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
return MapstructUtils.convert(list, voClass);
|
return MapstructUtils.convert(list, voClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查询单个VO对象
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @return 查询到的单个VO对象
|
||||||
|
*/
|
||||||
default V selectVoOne(Wrapper<T> wrapper) {
|
default V selectVoOne(Wrapper<T> wrapper) {
|
||||||
return selectVoOne(wrapper, this.currentVoClass());
|
return selectVoOne(wrapper, this.currentVoClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查询单个VO对象,并根据需要决定是否抛出异常
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @param throwEx 是否抛出异常的标志
|
||||||
|
* @return 查询到的单个VO对象
|
||||||
|
*/
|
||||||
default V selectVoOne(Wrapper<T> wrapper, boolean throwEx) {
|
default V selectVoOne(Wrapper<T> wrapper, boolean throwEx) {
|
||||||
return selectVoOne(wrapper, this.currentVoClass(), throwEx);
|
return selectVoOne(wrapper, this.currentVoClass(), throwEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 entity 条件,查询一条记录
|
* 根据条件查询单个VO对象,并指定返回的VO对象的类型
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @param voClass 返回的VO对象的Class对象
|
||||||
|
* @param <C> 返回的VO对象的类型
|
||||||
|
* @return 查询到的单个VO对象,经过类型转换为指定的VO类后返回
|
||||||
*/
|
*/
|
||||||
default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) {
|
default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) {
|
||||||
return selectVoOne(wrapper, voClass, true);
|
return selectVoOne(wrapper, voClass, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 entity 条件,查询一条记录
|
* 根据条件查询单个实体对象,并将其转换为指定的VO对象
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @param voClass 要转换的VO类的Class对象
|
||||||
|
* @param throwEx 是否抛出异常的标志
|
||||||
|
* @param <C> VO类的类型
|
||||||
|
* @return 查询到的单个VO对象,经过转换为指定的VO类后返回
|
||||||
*/
|
*/
|
||||||
default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass, boolean throwEx) {
|
default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass, boolean throwEx) {
|
||||||
T obj = this.selectOne(wrapper, throwEx);
|
T obj = this.selectOne(wrapper, throwEx);
|
||||||
@ -171,16 +264,32 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
return MapstructUtils.convert(obj, voClass);
|
return MapstructUtils.convert(obj, voClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有VO对象列表
|
||||||
|
*
|
||||||
|
* @return 查询到的VO对象列表
|
||||||
|
*/
|
||||||
default List<V> selectVoList() {
|
default List<V> selectVoList() {
|
||||||
return selectVoList(new QueryWrapper<>(), this.currentVoClass());
|
return selectVoList(new QueryWrapper<>(), this.currentVoClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查询VO对象列表
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @return 查询到的VO对象列表
|
||||||
|
*/
|
||||||
default List<V> selectVoList(Wrapper<T> wrapper) {
|
default List<V> selectVoList(Wrapper<T> wrapper) {
|
||||||
return selectVoList(wrapper, this.currentVoClass());
|
return selectVoList(wrapper, this.currentVoClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 entity 条件,查询全部记录
|
* 根据条件查询实体对象列表,并将其转换为指定的VO对象列表
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @param voClass 要转换的VO类的Class对象
|
||||||
|
* @param <C> VO类的类型
|
||||||
|
* @return 查询到的VO对象列表,经过转换为指定的VO类后返回
|
||||||
*/
|
*/
|
||||||
default <C> List<C> selectVoList(Wrapper<T> wrapper, Class<C> voClass) {
|
default <C> List<C> selectVoList(Wrapper<T> wrapper, Class<C> voClass) {
|
||||||
List<T> list = this.selectList(wrapper);
|
List<T> list = this.selectList(wrapper);
|
||||||
@ -190,15 +299,31 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
return MapstructUtils.convert(list, voClass);
|
return MapstructUtils.convert(list, voClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件分页查询VO对象列表
|
||||||
|
*
|
||||||
|
* @param page 分页信息
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @return 查询到的VO对象分页列表
|
||||||
|
*/
|
||||||
default <P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper) {
|
default <P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper) {
|
||||||
return selectVoPage(page, wrapper, this.currentVoClass());
|
return selectVoPage(page, wrapper, this.currentVoClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询VO
|
* 根据条件分页查询实体对象列表,并将其转换为指定的VO对象分页列表
|
||||||
|
*
|
||||||
|
* @param page 分页信息
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @param voClass 要转换的VO类的Class对象
|
||||||
|
* @param <C> VO类的类型
|
||||||
|
* @param <P> VO对象分页列表的类型
|
||||||
|
* @return 查询到的VO对象分页列表,经过转换为指定的VO类后返回
|
||||||
*/
|
*/
|
||||||
default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) {
|
default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) {
|
||||||
|
// 根据条件分页查询实体对象列表
|
||||||
List<T> list = this.selectList(page, wrapper);
|
List<T> list = this.selectList(page, wrapper);
|
||||||
|
// 创建一个新的VO对象分页列表,并设置分页信息
|
||||||
IPage<C> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
IPage<C> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
||||||
if (CollUtil.isEmpty(list)) {
|
if (CollUtil.isEmpty(list)) {
|
||||||
return (P) voPage;
|
return (P) voPage;
|
||||||
@ -207,6 +332,14 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
return (P) voPage;
|
return (P) voPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查询符合条件的对象,并将其转换为指定类型的对象列表
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @param mapper 转换函数,用于将查询到的对象转换为指定类型的对象
|
||||||
|
* @param <C> 要转换的对象的类型
|
||||||
|
* @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回
|
||||||
|
*/
|
||||||
default <C> List<C> selectObjs(Wrapper<T> wrapper, Function<? super Object, C> mapper) {
|
default <C> List<C> selectObjs(Wrapper<T> wrapper, Function<? super Object, C> mapper) {
|
||||||
return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
|
return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,10 @@ import cn.hutool.core.collection.CollUtil;
|
|||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.Data;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.core.utils.sql.SqlUtil;
|
import org.dromara.common.core.utils.sql.SqlUtil;
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -19,7 +19,6 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class PageQuery implements Serializable {
|
public class PageQuery implements Serializable {
|
||||||
|
|
||||||
@ -56,6 +55,9 @@ public class PageQuery implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
|
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建分页对象
|
||||||
|
*/
|
||||||
public <T> Page<T> build() {
|
public <T> Page<T> build() {
|
||||||
Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
|
Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
|
||||||
Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
|
Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
|
||||||
|
@ -14,7 +14,6 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class TableDataInfo<T> implements Serializable {
|
public class TableDataInfo<T> implements Serializable {
|
||||||
@ -53,6 +52,9 @@ public class TableDataInfo<T> implements Serializable {
|
|||||||
this.total = total;
|
this.total = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据分页对象构建表格分页数据对象
|
||||||
|
*/
|
||||||
public static <T> TableDataInfo<T> build(IPage<T> page) {
|
public static <T> TableDataInfo<T> build(IPage<T> page) {
|
||||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||||
rspData.setCode(HttpStatus.HTTP_OK);
|
rspData.setCode(HttpStatus.HTTP_OK);
|
||||||
@ -62,6 +64,9 @@ public class TableDataInfo<T> implements Serializable {
|
|||||||
return rspData;
|
return rspData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据数据列表构建表格分页数据对象
|
||||||
|
*/
|
||||||
public static <T> TableDataInfo<T> build(List<T> list) {
|
public static <T> TableDataInfo<T> build(List<T> list) {
|
||||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||||
rspData.setCode(HttpStatus.HTTP_OK);
|
rspData.setCode(HttpStatus.HTTP_OK);
|
||||||
@ -71,6 +76,9 @@ public class TableDataInfo<T> implements Serializable {
|
|||||||
return rspData;
|
return rspData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建表格分页数据对象
|
||||||
|
*/
|
||||||
public static <T> TableDataInfo<T> build() {
|
public static <T> TableDataInfo<T> build() {
|
||||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||||
rspData.setCode(HttpStatus.HTTP_OK);
|
rspData.setCode(HttpStatus.HTTP_OK);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package org.dromara.common.mybatis.enums;
|
package org.dromara.common.mybatis.enums;
|
||||||
|
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据库类型
|
* 数据库类型
|
||||||
@ -33,8 +33,17 @@ public enum DataBaseType {
|
|||||||
*/
|
*/
|
||||||
SQL_SERVER("Microsoft SQL Server");
|
SQL_SERVER("Microsoft SQL Server");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据库类型
|
||||||
|
*/
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据数据库产品名称查找对应的数据库类型
|
||||||
|
*
|
||||||
|
* @param databaseProductName 数据库产品名称
|
||||||
|
* @return 对应的数据库类型枚举值,如果未找到则返回 null
|
||||||
|
*/
|
||||||
public static DataBaseType find(String databaseProductName) {
|
public static DataBaseType find(String databaseProductName) {
|
||||||
if (StringUtils.isBlank(databaseProductName)) {
|
if (StringUtils.isBlank(databaseProductName)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
package org.dromara.common.mybatis.enums;
|
package org.dromara.common.mybatis.enums;
|
||||||
|
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.dromara.common.core.domain.model.LoginUser;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据权限类型
|
* 数据权限类型枚举
|
||||||
* <p>
|
* <p>
|
||||||
* 语法支持 spel 模板表达式
|
* 支持使用 SpEL 模板表达式定义 SQL 查询条件
|
||||||
* <p>
|
* 内置数据:
|
||||||
* 内置数据 user 当前用户 内容参考 LoginUser
|
* - {@code user}: 当前登录用户信息,参考 {@link LoginUser}
|
||||||
* 如需扩展数据 可使用 {@link DataPermissionHelper} 操作
|
* 内置服务:
|
||||||
* 内置服务 sdss 系统数据权限服务 内容参考 SysDataScopeService
|
* - {@code sdss}: 系统数据权限服务,参考 {@link ISysDataScopeService}
|
||||||
* 如需扩展更多自定义服务 可以参考 sdss 自行编写
|
* 如需扩展数据,可以通过 {@link DataPermissionHelper} 进行操作
|
||||||
|
* 如需扩展服务,可以通过 {@link ISysDataScopeService} 自行编写
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
* @version 3.5.0
|
* @version 3.5.0
|
||||||
@ -29,36 +32,50 @@ public enum DataScopeType {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定数据权限
|
* 自定数据权限
|
||||||
|
* 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} )`
|
||||||
|
* 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
|
||||||
*/
|
*/
|
||||||
CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "),
|
CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门数据权限
|
* 部门数据权限
|
||||||
|
* 使用 SpEL 表达式:`#{#deptName} = #{#user.deptId}`
|
||||||
|
* 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
|
||||||
*/
|
*/
|
||||||
DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
|
DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门及以下数据权限
|
* 部门及以下数据权限
|
||||||
|
* 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )}`
|
||||||
|
* 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
|
||||||
*/
|
*/
|
||||||
DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "),
|
DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 仅本人数据权限
|
* 仅本人数据权限
|
||||||
|
* 使用 SpEL 表达式:`#{#userName} = #{#user.userId}`
|
||||||
|
* 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
|
||||||
*/
|
*/
|
||||||
SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
|
SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
|
||||||
|
|
||||||
private final String code;
|
private final String code;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语法 采用 spel 模板表达式
|
* SpEL 模板表达式,用于构建 SQL 查询条件
|
||||||
*/
|
*/
|
||||||
private final String sqlTemplate;
|
private final String sqlTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 不满足 sqlTemplate 则填充
|
* 如果不满足 {@code sqlTemplate} 的条件,则使用此默认 SQL 表达式
|
||||||
*/
|
*/
|
||||||
private final String elseSql;
|
private final String elseSql;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据枚举代码查找对应的枚举值
|
||||||
|
*
|
||||||
|
* @param code 枚举代码
|
||||||
|
* @return 对应的枚举值,如果未找到则返回 null
|
||||||
|
*/
|
||||||
public static DataScopeType findCode(String code) {
|
public static DataScopeType findCode(String code) {
|
||||||
if (StringUtils.isBlank(code)) {
|
if (StringUtils.isBlank(code)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -3,12 +3,12 @@ package org.dromara.common.mybatis.handler;
|
|||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.http.HttpStatus;
|
import cn.hutool.http.HttpStatus;
|
||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.ibatis.reflection.MetaObject;
|
||||||
import org.dromara.common.core.domain.model.LoginUser;
|
import org.dromara.common.core.domain.model.LoginUser;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.ibatis.reflection.MetaObject;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ -21,21 +21,28 @@ import java.util.Date;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入填充方法,用于在插入数据时自动填充实体对象中的创建时间、更新时间、创建人、更新人等信息
|
||||||
|
*
|
||||||
|
* @param metaObject 元对象,用于获取原始对象并进行填充
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void insertFill(MetaObject metaObject) {
|
public void insertFill(MetaObject metaObject) {
|
||||||
try {
|
try {
|
||||||
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
|
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
|
||||||
|
// 获取当前时间作为创建时间和更新时间,如果创建时间不为空,则使用创建时间,否则使用当前时间
|
||||||
Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime())
|
Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime())
|
||||||
? baseEntity.getCreateTime() : new Date();
|
? baseEntity.getCreateTime() : new Date();
|
||||||
baseEntity.setCreateTime(current);
|
baseEntity.setCreateTime(current);
|
||||||
baseEntity.setUpdateTime(current);
|
baseEntity.setUpdateTime(current);
|
||||||
|
|
||||||
|
// 如果创建人为空,则填充当前登录用户的信息
|
||||||
if (ObjectUtil.isNull(baseEntity.getCreateBy())) {
|
if (ObjectUtil.isNull(baseEntity.getCreateBy())) {
|
||||||
LoginUser loginUser = getLoginUser();
|
LoginUser loginUser = getLoginUser();
|
||||||
if (ObjectUtil.isNotNull(loginUser)) {
|
if (ObjectUtil.isNotNull(loginUser)) {
|
||||||
Long userId = loginUser.getUserId();
|
Long userId = loginUser.getUserId();
|
||||||
// 当前已登录 且 创建人为空 则填充
|
// 填充创建人、更新人和创建部门信息
|
||||||
baseEntity.setCreateBy(userId);
|
baseEntity.setCreateBy(userId);
|
||||||
// 当前已登录 且 更新人为空 则填充
|
|
||||||
baseEntity.setUpdateBy(userId);
|
baseEntity.setUpdateBy(userId);
|
||||||
baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept())
|
baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept())
|
||||||
? baseEntity.getCreateDept() : loginUser.getDeptId());
|
? baseEntity.getCreateDept() : loginUser.getDeptId());
|
||||||
@ -47,19 +54,24 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新填充方法,用于在更新数据时自动填充实体对象中的更新时间和更新人信息
|
||||||
|
*
|
||||||
|
* @param metaObject 元对象,用于获取原始对象并进行填充
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void updateFill(MetaObject metaObject) {
|
public void updateFill(MetaObject metaObject) {
|
||||||
try {
|
try {
|
||||||
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
|
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
|
||||||
|
// 获取当前时间作为更新时间,无论原始对象中的更新时间是否为空都填充
|
||||||
Date current = new Date();
|
Date current = new Date();
|
||||||
// 更新时间填充(不管为不为空)
|
|
||||||
baseEntity.setUpdateTime(current);
|
baseEntity.setUpdateTime(current);
|
||||||
// 当前已登录 更新人填充(不管为不为空)
|
|
||||||
|
// 获取当前登录用户的ID,并填充更新人信息
|
||||||
Long userId = LoginHelper.getUserId();
|
Long userId = LoginHelper.getUserId();
|
||||||
if (ObjectUtil.isNotNull(userId)) {
|
if (ObjectUtil.isNotNull(userId)) {
|
||||||
baseEntity.setUpdateBy(userId);
|
baseEntity.setUpdateBy(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
|
throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
|
||||||
@ -67,7 +79,9 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取登录用户名
|
* 获取当前登录用户信息
|
||||||
|
*
|
||||||
|
* @return 当前登录用户的信息,如果用户未登录则返回 null
|
||||||
*/
|
*/
|
||||||
private LoginUser getLoginUser() {
|
private LoginUser getLoginUser() {
|
||||||
LoginUser loginUser;
|
LoginUser loginUser;
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
package org.dromara.common.mybatis.handler;
|
package org.dromara.common.mybatis.handler;
|
||||||
|
|
||||||
import org.dromara.common.core.domain.R;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.mybatis.spring.MyBatisSystemException;
|
import org.mybatis.spring.MyBatisSystemException;
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mybatis异常处理器
|
* Mybatis异常处理器
|
||||||
*
|
*
|
||||||
|
@ -68,13 +68,27 @@ public class PlusDataPermissionHandler {
|
|||||||
*/
|
*/
|
||||||
private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
|
private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法,扫描指定包下的 Mapper 类并初始化缓存
|
||||||
|
*
|
||||||
|
* @param mapperPackage Mapper 类所在的包路径
|
||||||
|
*/
|
||||||
public PlusDataPermissionHandler(String mapperPackage) {
|
public PlusDataPermissionHandler(String mapperPackage) {
|
||||||
scanMapperClasses(mapperPackage);
|
scanMapperClasses(mapperPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数据过滤条件的 SQL 片段
|
||||||
|
*
|
||||||
|
* @param where 原始的查询条件表达式
|
||||||
|
* @param mappedStatementId Mapper 方法的 ID
|
||||||
|
* @param isSelect 是否为查询语句
|
||||||
|
* @return 数据过滤条件的 SQL 片段
|
||||||
|
*/
|
||||||
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
|
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
|
||||||
|
// 获取数据权限配置
|
||||||
DataPermission dataPermission = getDataPermission(mappedStatementId);
|
DataPermission dataPermission = getDataPermission(mappedStatementId);
|
||||||
|
// 获取当前登录用户信息
|
||||||
LoginUser currentUser = DataPermissionHelper.getVariable("user");
|
LoginUser currentUser = DataPermissionHelper.getVariable("user");
|
||||||
if (ObjectUtil.isNull(currentUser)) {
|
if (ObjectUtil.isNull(currentUser)) {
|
||||||
currentUser = LoginHelper.getLoginUser();
|
currentUser = LoginHelper.getLoginUser();
|
||||||
@ -84,6 +98,7 @@ public class PlusDataPermissionHandler {
|
|||||||
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
||||||
return where;
|
return where;
|
||||||
}
|
}
|
||||||
|
// 构造数据过滤条件的 SQL 片段
|
||||||
String dataFilterSql = buildDataFilter(dataPermission.value(), isSelect);
|
String dataFilterSql = buildDataFilter(dataPermission.value(), isSelect);
|
||||||
if (StringUtils.isBlank(dataFilterSql)) {
|
if (StringUtils.isBlank(dataFilterSql)) {
|
||||||
return where;
|
return where;
|
||||||
@ -103,7 +118,12 @@ public class PlusDataPermissionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造数据过滤sql
|
* 构建数据过滤条件的 SQL 语句
|
||||||
|
*
|
||||||
|
* @param dataColumns 数据权限注解中的列信息
|
||||||
|
* @param isSelect 标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式
|
||||||
|
* @return 构建的数据过滤条件的 SQL 语句
|
||||||
|
* @throws ServiceException 如果角色的数据范围异常或者 key 与 value 的长度不匹配,则抛出 ServiceException 异常
|
||||||
*/
|
*/
|
||||||
private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) {
|
private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) {
|
||||||
// 更新或删除需满足所有条件
|
// 更新或删除需满足所有条件
|
||||||
@ -159,20 +179,29 @@ public class PlusDataPermissionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过 mapperPackage 设置的扫描包 扫描缓存有注解的方法与类
|
* 扫描指定包下的 Mapper 类,并查找其中带有特定注解的方法或类
|
||||||
|
*
|
||||||
|
* @param mapperPackage Mapper 类所在的包路径
|
||||||
*/
|
*/
|
||||||
private void scanMapperClasses(String mapperPackage) {
|
private void scanMapperClasses(String mapperPackage) {
|
||||||
|
// 创建资源解析器和元数据读取工厂
|
||||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||||
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
|
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
|
||||||
|
// 将 Mapper 包路径按分隔符拆分为数组
|
||||||
String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
|
String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
|
||||||
String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
|
String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
|
||||||
try {
|
try {
|
||||||
for (String packagePattern : packagePatternArray) {
|
for (String packagePattern : packagePatternArray) {
|
||||||
|
// 将包路径转换为资源路径
|
||||||
String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
|
String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
|
||||||
|
// 获取指定路径下的所有 .class 文件资源
|
||||||
Resource[] resources = resolver.getResources(classpath + path + "/*.class");
|
Resource[] resources = resolver.getResources(classpath + path + "/*.class");
|
||||||
for (Resource resource : resources) {
|
for (Resource resource : resources) {
|
||||||
|
// 获取资源的类元数据
|
||||||
ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
|
ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
|
||||||
|
// 获取资源对应的类对象
|
||||||
Class<?> clazz = Resources.classForName(classMetadata.getClassName());
|
Class<?> clazz = Resources.classForName(classMetadata.getClassName());
|
||||||
|
// 查找类中的特定注解
|
||||||
findAnnotation(clazz);
|
findAnnotation(clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,9 +210,13 @@ public class PlusDataPermissionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在指定的类中查找特定的注解 DataPermission,并将带有这个注解的方法或类存储到 dataPermissionCacheMap 中
|
||||||
|
*
|
||||||
|
* @param clazz 要查找的类
|
||||||
|
*/
|
||||||
private void findAnnotation(Class<?> clazz) {
|
private void findAnnotation(Class<?> clazz) {
|
||||||
DataPermission dataPermission;
|
DataPermission dataPermission;
|
||||||
// 获取方法注解
|
|
||||||
for (Method method : clazz.getMethods()) {
|
for (Method method : clazz.getMethods()) {
|
||||||
if (method.isDefault() || method.isVarArgs()) {
|
if (method.isDefault() || method.isVarArgs()) {
|
||||||
continue;
|
continue;
|
||||||
@ -194,17 +227,24 @@ public class PlusDataPermissionHandler {
|
|||||||
dataPermissionCacheMap.put(mappedStatementId, dataPermission);
|
dataPermissionCacheMap.put(mappedStatementId, dataPermission);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 获取类注解
|
|
||||||
if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
|
if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
|
||||||
dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
|
dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
|
||||||
dataPermissionCacheMap.put(clazz.getName(), dataPermission);
|
dataPermissionCacheMap.put(clazz.getName(), dataPermission);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据映射语句 ID 或类名获取对应的 DataPermission 注解对象
|
||||||
|
*
|
||||||
|
* @param mapperId 映射语句 ID
|
||||||
|
* @return DataPermission 注解对象,如果不存在则返回 null
|
||||||
|
*/
|
||||||
public DataPermission getDataPermission(String mapperId) {
|
public DataPermission getDataPermission(String mapperId) {
|
||||||
|
// 检查缓存中是否包含映射语句 ID 对应的 DataPermission 注解对象
|
||||||
if (dataPermissionCacheMap.containsKey(mapperId)) {
|
if (dataPermissionCacheMap.containsKey(mapperId)) {
|
||||||
return dataPermissionCacheMap.get(mapperId);
|
return dataPermissionCacheMap.get(mapperId);
|
||||||
}
|
}
|
||||||
|
// 如果缓存中不包含映射语句 ID 对应的 DataPermission 注解对象,则尝试使用类名作为键查找
|
||||||
String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
|
String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
|
||||||
if (dataPermissionCacheMap.containsKey(clazzName)) {
|
if (dataPermissionCacheMap.containsKey(clazzName)) {
|
||||||
return dataPermissionCacheMap.get(clazzName);
|
return dataPermissionCacheMap.get(clazzName);
|
||||||
@ -213,7 +253,10 @@ public class PlusDataPermissionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否无效
|
* 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象
|
||||||
|
*
|
||||||
|
* @param mapperId 映射语句 ID
|
||||||
|
* @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true
|
||||||
*/
|
*/
|
||||||
public boolean invalid(String mapperId) {
|
public boolean invalid(String mapperId) {
|
||||||
return getDataPermission(mapperId) == null;
|
return getDataPermission(mapperId) == null;
|
||||||
|
@ -2,11 +2,11 @@ package org.dromara.common.mybatis.helper;
|
|||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.utils.SpringUtils;
|
import org.dromara.common.core.utils.SpringUtils;
|
||||||
import org.dromara.common.mybatis.enums.DataBaseType;
|
import org.dromara.common.mybatis.enums.DataBaseType;
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@ -14,7 +14,6 @@ import java.sql.DatabaseMetaData;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据库助手
|
* 数据库助手
|
||||||
|
@ -24,17 +24,35 @@ public class DataPermissionHelper {
|
|||||||
|
|
||||||
private static final String DATA_PERMISSION_KEY = "data:permission";
|
private static final String DATA_PERMISSION_KEY = "data:permission";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从上下文中获取指定键的变量值,并将其转换为指定的类型
|
||||||
|
*
|
||||||
|
* @param key 变量的键
|
||||||
|
* @param <T> 变量值的类型
|
||||||
|
* @return 指定键的变量值,如果不存在则返回 null
|
||||||
|
*/
|
||||||
public static <T> T getVariable(String key) {
|
public static <T> T getVariable(String key) {
|
||||||
Map<String, Object> context = getContext();
|
Map<String, Object> context = getContext();
|
||||||
return (T) context.get(key);
|
return (T) context.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向上下文中设置指定键的变量值
|
||||||
|
*
|
||||||
|
* @param key 要设置的变量的键
|
||||||
|
* @param value 要设置的变量值
|
||||||
|
*/
|
||||||
public static void setVariable(String key, Object value) {
|
public static void setVariable(String key, Object value) {
|
||||||
Map<String, Object> context = getContext();
|
Map<String, Object> context = getContext();
|
||||||
context.put(key, value);
|
context.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数据权限上下文
|
||||||
|
*
|
||||||
|
* @return 存储在SaStorage中的Map对象,用于存储数据权限相关的上下文信息
|
||||||
|
* @throws NullPointerException 如果数据权限上下文类型异常,则抛出NullPointerException
|
||||||
|
*/
|
||||||
public static Map<String, Object> getContext() {
|
public static Map<String, Object> getContext() {
|
||||||
SaStorage saStorage = SaHolder.getStorage();
|
SaStorage saStorage = SaHolder.getStorage();
|
||||||
Object attribute = saStorage.get(DATA_PERMISSION_KEY);
|
Object attribute = saStorage.get(DATA_PERMISSION_KEY);
|
||||||
@ -64,6 +82,7 @@ public class DataPermissionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 在忽略数据权限中执行
|
* 在忽略数据权限中执行
|
||||||
|
* <p>禁止在忽略数据权限中执行忽略数据权限</p>
|
||||||
*
|
*
|
||||||
* @param handle 处理执行方法
|
* @param handle 处理执行方法
|
||||||
*/
|
*/
|
||||||
@ -78,6 +97,7 @@ public class DataPermissionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 在忽略数据权限中执行
|
* 在忽略数据权限中执行
|
||||||
|
* <p>禁止在忽略数据权限中执行忽略数据权限</p>
|
||||||
*
|
*
|
||||||
* @param handle 处理执行方法
|
* @param handle 处理执行方法
|
||||||
*/
|
*/
|
||||||
|
@ -37,17 +37,33 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
|
|
||||||
private final PlusDataPermissionHandler dataPermissionHandler;
|
private final PlusDataPermissionHandler dataPermissionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数,初始化 PlusDataPermissionHandler 实例
|
||||||
|
*
|
||||||
|
* @param mapperPackage 扫描的映射器包
|
||||||
|
*/
|
||||||
public PlusDataPermissionInterceptor(String mapperPackage) {
|
public PlusDataPermissionInterceptor(String mapperPackage) {
|
||||||
this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage);
|
this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在执行查询之前,检查并处理数据权限相关逻辑
|
||||||
|
*
|
||||||
|
* @param executor MyBatis 执行器对象
|
||||||
|
* @param ms 映射语句对象
|
||||||
|
* @param parameter 方法参数
|
||||||
|
* @param rowBounds 分页对象
|
||||||
|
* @param resultHandler 结果处理器
|
||||||
|
* @param boundSql 绑定的 SQL 对象
|
||||||
|
* @throws SQLException 如果发生 SQL 异常
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
|
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
|
||||||
// 检查忽略注解
|
// 检查是否需要忽略数据权限处理
|
||||||
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
|
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 检查是否无效 无数据权限注解
|
// 检查是否缺少有效的数据权限注解
|
||||||
if (dataPermissionHandler.invalid(ms.getId())) {
|
if (dataPermissionHandler.invalid(ms.getId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -56,16 +72,26 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));
|
mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在准备 SQL 语句之前,检查并处理更新和删除操作的数据权限相关逻辑
|
||||||
|
*
|
||||||
|
* @param sh MyBatis StatementHandler 对象
|
||||||
|
* @param connection 数据库连接对象
|
||||||
|
* @param transactionTimeout 事务超时时间
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
||||||
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
||||||
MappedStatement ms = mpSh.mappedStatement();
|
MappedStatement ms = mpSh.mappedStatement();
|
||||||
|
// 获取 SQL 命令类型(增、删、改、查)
|
||||||
SqlCommandType sct = ms.getSqlCommandType();
|
SqlCommandType sct = ms.getSqlCommandType();
|
||||||
|
|
||||||
|
// 只处理更新和删除操作的 SQL 语句
|
||||||
if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
|
if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
|
||||||
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
|
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 检查是否无效 无数据权限注解
|
// 检查是否缺少有效的数据权限注解
|
||||||
if (dataPermissionHandler.invalid(ms.getId())) {
|
if (dataPermissionHandler.invalid(ms.getId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -74,6 +100,14 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 SELECT 查询语句中的 WHERE 条件
|
||||||
|
*
|
||||||
|
* @param select SELECT 查询对象
|
||||||
|
* @param index 查询语句的索引
|
||||||
|
* @param sql 查询语句
|
||||||
|
* @param obj WHERE 条件参数
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void processSelect(Select select, int index, String sql, Object obj) {
|
protected void processSelect(Select select, int index, String sql, Object obj) {
|
||||||
if (select instanceof PlainSelect) {
|
if (select instanceof PlainSelect) {
|
||||||
@ -84,6 +118,14 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 UPDATE 语句中的 WHERE 条件
|
||||||
|
*
|
||||||
|
* @param update UPDATE 查询对象
|
||||||
|
* @param index 查询语句的索引
|
||||||
|
* @param sql 查询语句
|
||||||
|
* @param obj WHERE 条件参数
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void processUpdate(Update update, int index, String sql, Object obj) {
|
protected void processUpdate(Update update, int index, String sql, Object obj) {
|
||||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false);
|
Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false);
|
||||||
@ -92,6 +134,14 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 DELETE 语句中的 WHERE 条件
|
||||||
|
*
|
||||||
|
* @param delete DELETE 查询对象
|
||||||
|
* @param index 查询语句的索引
|
||||||
|
* @param sql 查询语句
|
||||||
|
* @param obj WHERE 条件参数
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void processDelete(Delete delete, int index, String sql, Object obj) {
|
protected void processDelete(Delete delete, int index, String sql, Object obj) {
|
||||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false);
|
Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false);
|
||||||
@ -101,10 +151,10 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置 where 条件
|
* 设置 SELECT 语句的 WHERE 条件
|
||||||
*
|
*
|
||||||
* @param plainSelect 查询对象
|
* @param plainSelect SELECT 查询对象
|
||||||
* @param mappedStatementId 执行方法id
|
* @param mappedStatementId 映射语句的 ID
|
||||||
*/
|
*/
|
||||||
protected void setWhere(PlainSelect plainSelect, String mappedStatementId) {
|
protected void setWhere(PlainSelect plainSelect, String mappedStatementId) {
|
||||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true);
|
Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true);
|
||||||
@ -113,6 +163,14 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建表达式,用于处理表的数据权限
|
||||||
|
*
|
||||||
|
* @param table 表对象
|
||||||
|
* @param where WHERE 条件表达式
|
||||||
|
* @param whereSegment WHERE 条件片段
|
||||||
|
* @return 构建的表达式
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Expression buildTableExpression(Table table, Expression where, String whereSegment) {
|
public Expression buildTableExpression(Table table, Expression where, String whereSegment) {
|
||||||
// 只有新版数据权限处理器才会执行到这里
|
// 只有新版数据权限处理器才会执行到这里
|
||||||
|
@ -3,14 +3,14 @@ package org.dromara.system.service.impl;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import org.dromara.system.domain.SysDept;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
|
||||||
import org.dromara.common.core.utils.StreamUtils;
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
|
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||||
|
import org.dromara.system.domain.SysDept;
|
||||||
import org.dromara.system.domain.SysRoleDept;
|
import org.dromara.system.domain.SysRoleDept;
|
||||||
import org.dromara.system.mapper.SysDeptMapper;
|
import org.dromara.system.mapper.SysDeptMapper;
|
||||||
import org.dromara.system.mapper.SysRoleDeptMapper;
|
import org.dromara.system.mapper.SysRoleDeptMapper;
|
||||||
import org.dromara.system.service.ISysDataScopeService;
|
import org.dromara.system.service.ISysDataScopeService;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -30,6 +30,12 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
|
|||||||
private final SysRoleDeptMapper roleDeptMapper;
|
private final SysRoleDeptMapper roleDeptMapper;
|
||||||
private final SysDeptMapper deptMapper;
|
private final SysDeptMapper deptMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取角色自定义权限
|
||||||
|
*
|
||||||
|
* @param roleId 角色Id
|
||||||
|
* @return 部门Id组
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getRoleCustom(Long roleId) {
|
public String getRoleCustom(Long roleId) {
|
||||||
List<SysRoleDept> list = roleDeptMapper.selectList(
|
List<SysRoleDept> list = roleDeptMapper.selectList(
|
||||||
@ -42,6 +48,12 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取部门及以下权限
|
||||||
|
*
|
||||||
|
* @param deptId 部门Id
|
||||||
|
* @return 部门Id组
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getDeptAndChild(Long deptId) {
|
public String getDeptAndChild(Long deptId) {
|
||||||
List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
|
List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user