基于Mybatis-Plus的数据权限框架
前言
近期开发使用的框架基本上都是springboot + Mybatis-plus 方便,快速。而且差不多都是单表查询,很少使用关联表。
经常会遇到需要做数据权限过滤的查询,每次都要写SQL,然后使用in的方式。非常麻烦。所以研究了一下Mybatis-plus的进阶使用。可以通过自定义SQL解析器,自定义SQL内容。
使用该方式 + 切面 的方式,实现自动添加数据权限的过滤方式。
注:我自己的工程的权限框架为shiro,可以通过修改,配置适配自己框架
设计
因为数据权限是与请求地址相关,所以将菜单与数据权限关联,角色不直接关联数据权限,角色通过菜单间接关联数据权限。如果一个用户有多个角色,并且这些角色都有分配同一个菜单的不同数据权限,则以最大权限为主。
这里就不做过多介绍。主要还是说明MP
的设计结构。
总体工程结构如下:其中DataScopeAspect
为自定义切面,将数据权限设置到参数的父类属性中。
正文
pom依赖
3.4以前的版本配置不一样,请自行查看。
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.16</version>
</dependency>
</dependencies>
1.数据权限基类
所有需要做数据权限过滤的接口入参,都需要继承该类,用于存储机构编号列表或者用户编号
package com.hongtool.mybatis.perms.domain;
import java.io.Serializable;
import java.util.List;
/**
* <p> 数据权限 传参 </p>
*
* @author hongtool
* @date 2022/11/1
*/
public class DataScopePerms implements Serializable {
private static final long serialVersionUID = 1L;
/** 创建者 */
private String userPerm;
/** 机构部门 */
private List<Long> deptPerms;
public DataScopePerms() {
}
// TODO 省略 GET 和 SET 方法
}
2.权限字段注解
注: 如果有更多的权限类型,则可以再自定义添加
1)机构部门权限
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p> 部门权限(只能有一个,如果有多个,只会获取第一个) </p>
*
* @author hongtool
* @date 2022/11/24
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface DeptPerm {
// 字段名,如果为空,则从MyBatis-plus的解析表字段获取
String value() default "";
}
2)用户权限
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p> 用户权限(只能有一个,同机构部门权限) </p>
*
* @author hongtool
* @date 2022/11/24
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface UserPerm {
String value() default "";
}
3.自定义SQL方法
如果有额外的自定义SQL,则可以添加。
package com.hongtool.mybatis.perms.enums;
/**
* <p> 自定义本项目支持的SQL方法 </p>
* 模拟MyBatis-plus的 {@link com.baomidou.mybatisplus.core.enums.SqlMethod}
* @author hongtool
* @date 2022/11/1
*/
public enum HongToolSqlMethod {
COUNT_PERMISSION("countPerms", "查询满足条件总记录数(带权限控制)", "<script>\nSELECT COUNT(%s) FROM %s %s %s\n</script>"),
LIST_PERMISSION("listPerms", "查询满足条件所有数据(带权限控制)", "<script>\nSELECT %s FROM %s %s %s\n</script>"),
PAGE_PERMISSION("pagePerms", "查询满足条件所有数据(并翻页)(带权限控制)", "<script>\nSELECT %s FROM %s %s %s\n</script>"),
;
private final String method;
private final String desc;
private final String sql;
HongToolSqlMethod(String method, String desc, String sql) {
this.method = method;
this.desc = desc;
this.sql = sql;
}
public String getMethod() {
return method;
}
public String getDesc() {
return desc;
}
public String getSql() {
return sql;
}
}
4.自定义注入器
package com.hongtool.mybatis.perms.injector;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.hongtool.mybatis.perms.injector.methods.SelectCountPermission;
import com.hongtool.mybatis.perms.injector.methods.SelectListPermission;
import com.hongtool.mybatis.perms.injector.methods.SelectPagePermission;
import java.util.List;
/**
* <p> mybatis 扩展,为了查询有权限的数据 </p>
*
* @author hongtool
* @date 2022/11/1
*/
public class HongToolInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
// 通过权限,查询数据
methodList.add(new SelectListPermission());
methodList.add(new SelectPagePermission());
methodList.add(new SelectCountPermission());
return methodList;
}
}
1)有权限的列表查询
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.hongtool.mybatis.perms.enums.HongToolSqlMethod;
import com.hongtool.mybatis.perms.util.WherePermSqlUtil;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class SelectListPermission extends AbstractMethod {
public SelectListPermission() {
super(HongToolSqlMethod.LIST_PERMISSION.getMethod());
}
public SelectListPermission(String methodName) {
super(methodName);
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
HongToolSqlMethod sqlMethod = HongToolSqlMethod.LIST_PERMISSION;
String sql = String.format(sqlMethod.getSql(), sqlSelectColumns(tableInfo, true),
tableInfo.getTableName(), WherePermSqlUtil.getWhereSql(tableInfo),
sqlComment());
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addSelectMappedStatementForTable(mapperClass, sqlMethod.getMethod(), sqlSource, tableInfo);
}
}
2)有权限的分页查询
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.hongtool.mybatis.perms.enums.HongToolSqlMethod;
import com.hongtool.mybatis.perms.util.WherePermSqlUtil;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class SelectPagePermission extends AbstractMethod {
public SelectPagePermission() {
super(HongToolSqlMethod.PAGE_PERMISSION.getMethod());
}
public SelectPagePermission(String methodName) {
super(methodName);
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
HongToolSqlMethod sqlMethod = HongToolSqlMethod.PAGE_PERMISSION;
String sql = String.format(sqlMethod.getSql(), sqlSelectColumns(tableInfo, true),
tableInfo.getTableName(), WherePermSqlUtil.getWhereSql(tableInfo),
sqlComment());
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addSelectMappedStatementForTable(mapperClass, sqlMethod.getMethod(), sqlSource, tableInfo);
}
}
3)有权限的数量统计
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.hongtool.mybatis.perms.enums.HongToolSqlMethod;
import com.hongtool.mybatis.perms.util.WherePermSqlUtil;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class SelectCountPermission extends AbstractMethod {
public SelectCountPermission() {
super(HongToolSqlMethod.COUNT_PERMISSION.getMethod());
}
public SelectCountPermission(String methodName) {
super(methodName);
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
HongToolSqlMethod sqlMethod = HongToolSqlMethod.COUNT_PERMISSION;
String sql = String.format(sqlMethod.getSql(), this.sqlCount(), tableInfo.getTableName(),
WherePermSqlUtil.getWhereSql(tableInfo), sqlComment());
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addSelectMappedStatementForOther(mapperClass, sqlMethod.getMethod(), sqlSource, Integer.class);
}
}
4)WherePermSqlUtil Sql组装工具(重点代码)
部分参考MP源码的写法,有待优化。
从TableInfo
中获取实体对象,然后通过反射获取字段的DeptPerm
和UserPerm
注解,确定数据权限过滤字段。如果没有,则不做过滤。
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import com.hongtool.mybatis.perms.annotation.DeptPerm;
import com.hongtool.mybatis.perms.annotation.UserPerm;
import java.lang.reflect.Field;
/**
* <p> 权限 whereSQL 工具类 </p>
*
* @author hongtool
* @date 2022/11/9
*/
public class WherePermSqlUtil {
public static String getWhereSql(TableInfo table) {
String sqlScript;
String userField = getUserPermField(table);
String deptField = getDeptPermField(table);
if (table.isWithLogicDelete()) {
sqlScript = table.getAllSqlWhere(true, true, "ew.entity.");
sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", "ew.entity"), true)+ "\n";
// 添加数据权限
sqlScript = sqlScript + getUserPermsSql(userField);
sqlScript = sqlScript + getDeptPermsSql(deptField);
sqlScript = sqlScript + "\n" + table.getLogicDeleteSql(true, true) + "\n";
String normalSqlScript = SqlScriptUtils.convertIf(String.format("AND ${%s}", "ew.sqlSegment"), String.format("%s != null and %s != '' and %s", "ew.sqlSegment", "ew.sqlSegment", "ew.nonEmptyOfNormal"), true);
normalSqlScript = normalSqlScript + "\n";
normalSqlScript = normalSqlScript + SqlScriptUtils.convertIf(String.format(" ${%s}", "ew.sqlSegment"), String.format("%s != null and %s != '' and %s", "ew.sqlSegment", "ew.sqlSegment", "ew.emptyOfNormal"), true);
sqlScript = sqlScript + normalSqlScript;
sqlScript = SqlScriptUtils.convertChoose(String.format("%s != null", "ew"), sqlScript, table.getLogicDeleteSql(false, true));
sqlScript = SqlScriptUtils.convertWhere(sqlScript);
return "\n" + sqlScript;
} else {
sqlScript = table.getAllSqlWhere(false, true, "ew.entity.");
sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", "ew.entity"), true) + "\n";
// 添加数据权限
sqlScript = sqlScript + getUserPermsSql(getUserPermField(table));
sqlScript = sqlScript + getDeptPermsSql(getDeptPermField(table));
sqlScript = sqlScript + "\n";
sqlScript = sqlScript + SqlScriptUtils.convertIf(String.format(SqlScriptUtils.convertIf(" AND ", String.format("%s and %s", "ew.nonEmptyOfEntity", "ew.nonEmptyOfNormal"), false) + "<if test="!(ew.nonEmptyOfEntity and ew.nonEmptyOfNormal) and data != null and (data.userPerm != null or data.userPerm != '' or data.deptPerms != null or data.deptPerms.size() > 0)"> AND </if> ${%s}", "ew.sqlSegment"), String.format("%s != null and %s != '' and %s", "ew.sqlSegment", "ew.sqlSegment", "ew.nonEmptyOfWhere"), true);
sqlScript = SqlScriptUtils.convertWhere(sqlScript) + "\n";
sqlScript = sqlScript + SqlScriptUtils.convertIf(String.format(" ${%s}", "ew.sqlSegment"), String.format("%s != null and %s != '' and %s", "ew.sqlSegment", "ew.sqlSegment", "ew.emptyOfWhere"), true);
sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", "ew"), true);
return "\n" + sqlScript;
}
}
private static String getUserPermsSql(String userField) {
if(userField != null) {
return "<if test="data != null">\n" +
" <if test="data.userPerm != null">\n" +
" <if test="ew == null">AND</if> " + userField + " = #{data.userPerm}\n" +
" </if>\n" +
"</if>\n";
}
return "";
}
private static String getDeptPermsSql(String deptField) {
if(deptField != null) {
return "<if test="data != null">\n" +
" <if test="data.deptPerms != null and data.deptPerms.size() > 0">\n" +
" <if test="ew == null">AND</if> " + deptField + " in \n" +
" <foreach item="id" collection="data.deptPerms" open="(" separator="," close=")">\n" +
" #{id}\n" +
" </foreach>\n" +
" </if>\n" +
"</if>\n";
}
return "";
}
private static String getUserPermField(TableInfo tableInfo) {
Field[] fields = tableInfo.getEntityType().getDeclaredFields();
for (Field field : fields) {
UserPerm userPerm = field.getAnnotation(UserPerm.class);
if(userPerm != null) {
String value = userPerm.value();
if(StringUtils.isNotEmpty(value)) {
return value;
} else {
return tableInfo.getFieldList().stream()
.filter(f -> f.getProperty().equals(field.getName()))
.findFirst()
.map(TableFieldInfo::getColumn).orElse(null);
}
}
}
return null;
}
private static String getDeptPermField(TableInfo tableInfo) {
Field[] fields = tableInfo.getEntityType().getDeclaredFields();
for (Field field : fields) {
DeptPerm deptPerm = field.getAnnotation(DeptPerm.class);
if(deptPerm != null) {
String value = deptPerm.value();
if(StringUtils.isNotEmpty(value)) {
return value;
} else {
return tableInfo.getFieldList().stream()
.filter(f -> f.getProperty().equals(field.getName()))
.findFirst()
.map(TableFieldInfo::getColumn)
// 如果在字段中找不到,判断是否为主键字段
.orElse(tableInfo.getKeyProperty().equals(field.getName()) ? tableInfo.getKeyColumn() : null);
}
}
}
return null;
}
}
5)添加自定义注入器到配置中
package com.hongtool.springframework.mybatis.config;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.hongtool.mybatis.perms.injector.HongToolInjector;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* <p> 配置分页插件 </p>
*
* @author hongtool
* @date 2022/9/16
*/
@EnableTransactionManagement
@Configuration
@MapperScan("com.hongtool.**.mapper")
public class MybatisPlusConfig {
/**
* 3.4.0 以后的配置方式
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 乐观锁
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 分页配置
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
/**
* 自定义sql注入器
* 或者application.properties配置:
* mybatis-plus.globalConfig.sqlInjector=com.hongtool.mybatis.perms.injector.HongToolInjector
*/
@Bean
public ISqlInjector iSqlInjector() {
return new HongToolInjector();
}
}
5.自定义BaseMapper
方法名需要与HongToolSqlMethod
的method参数的内容一致才能使用。不然会报错(找不到解析方法)。
package com.hongtool.mybatis.perms.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.hongtool.mybatis.perms.domain.DataScopePerms;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 功能描述: 自定义项目BaseMapper <br/>
*/
public interface HongToolBaseMapper<T> extends BaseMapper<T> {
/**
* 功能描述: 带权限的查询 <br/>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @return "java.util.List<T>"
*/
<D extends DataScopePerms> List<T> listPerms(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, @Param("data") D d);
/**
* 功能描述: 带权限的分页查询 <br/>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @return "java.util.List<T>"
*/
<D extends DataScopePerms> IPage<T> pagePerms(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper, @Param("data") D d);
/**
* 功能描述: 带权限的数量统计 <br/>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @return "java.util.List<T>"
*/
<D extends DataScopePerms> Long countPerms(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, @Param("data") D d);
}
6.自定义IService与ServiceImpl
这两个可有可无。基本上都是直接调用Mapper的。留着以防万一嘛。
package com.hongtool.mybatis.perms.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hongtool.mybatis.perms.domain.DataScopePerms;
import java.util.List;
/**
* <p> 洪图 Mybatis-plus service扩展 </p>
*
* @author hongtool
* @date 2022/11/8
*/
public interface IHongToolService<T> extends IService<T> {
/**
* 功能描述: 带权限的查询 <br/>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @param d 数据权限
* @return "java.util.List<T>"
*/
<D extends DataScopePerms> List<T> listPerms(Wrapper<T> queryWrapper, D d);
/**
* 功能描述: 带权限的分页查询 <br/>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @param d 数据权限
* @return "java.util.List<T>"
*/
<D extends DataScopePerms> IPage<T> pagePerms(IPage<T> page, Wrapper<T> queryWrapper, D d);
/**
* 功能描述: 带权限的数量统计 <br/>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @param d 数据权限
* @return long
*/
<D extends DataScopePerms> Long countPerms(Wrapper<T> queryWrapper, D d);
}
package com.hongtool.mybatis.perms.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hongtool.mybatis.perms.domain.DataScopePerms;
import com.hongtool.mybatis.perms.mapper.HongToolBaseMapper;
import com.hongtool.mybatis.perms.service.IHongToolService;
import java.util.List;
/**
* <p> 洪图 Mybatis-plus serviceImpl扩展 </p>
*
* @author hongtool
* @date 2022/11/8
*/
public class HongToolServiceImpl<M extends HongToolBaseMapper<T>, T> extends ServiceImpl<M, T> implements IHongToolService<T> {
@Override
public <D extends DataScopePerms> List<T> listPerms(Wrapper<T> wrapper, D d) {
return baseMapper.listPerms(wrapper, d);
}
@Override
public <D extends DataScopePerms> IPage<T> pagePerms(IPage<T> page, Wrapper<T> wrapper, D d) {
return baseMapper.pagePerms(page, wrapper, d);
}
@Override
public <D extends DataScopePerms> Long countPerms(Wrapper<T> wrapper, D d) {
return baseMapper.countPerms(wrapper, d);
}
}
7.切面处理(重点代码)
每个项目根据自己的实际情况,这里的写法都是不一样的。我这里是在登录的时候,将权限缓存到LoginUser中。并且使用了Shrio
权限框架。所以就直接切RequiresPermissions
注解,然后获取对应的权限类型,再对DataScopePerms
赋值。
package com.hongtool.web.aspectj;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.hongtool.common.domain.LoginUser;
import com.hongtool.domain.module.system.enums.DataScopeEnum;
import com.hongtool.mybatis.perms.domain.DataScopePerms;
import com.hongtool.shiro.util.ShiroUtils;
import lombok.RequiredArgsConstructor;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* <p> 数据权限切面 </p>
*
* @author hongtool
* @date 2022/11/1
*/
@Aspect
@Component
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class DataScopeAspect {
@Before(value = "@annotation(permissions)")
public void doBefore(JoinPoint point, RequiresPermissions permissions) throws Throwable {
if(ObjectUtil.isNull(point) || point.getArgs().length < 1) {
return;
}
String[] value = permissions.value();
Object params = point.getArgs()[0];
if(ArrayUtil.isNotEmpty(value) && params instanceof DataScopePerms) {
LoginUser loginUser = ShiroUtils.getLoginUser();
List<LoginUser.Perms> permsList = loginUser.getPermsList();
if(CollUtil.isNotEmpty(permsList)) {
// 存在多个权限标识时,只取第一个(TODO 后续再优化)
LoginUser.Perms perms = permsList.stream().filter(p -> p.getPerms().equals(value[0])).findFirst().orElse(null);
if (perms != null) {
DataScopePerms dataScopePerms = (DataScopePerms) params;
if (DataScopeEnum.S5.getCode().equals(perms.getDataScope())) {
dataScopePerms.setUserPerm(loginUser.getLoginName());
} else {
dataScopePerms.setDeptPerms(perms.getDeptIds());
}
}
}
}
}
}
使用
1.添加依赖
<dependency>
<groupId>com.hongtool</groupId>
<artifactId>hongtool-mybatis-perms</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2.入参继承DataScopePerms
import com.hongtool.mybatis.perms.domain.DataScopePerms;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p> 机构部门查询入参 </p>
*
* @author hongtool
* @date 2022/10/21
*/
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(value = "SysDeptQuery", description = "机构部门查询入参")
public class SysDeptQuery extends DataScopePerms {
@ApiModelProperty("机构部门名称,模糊匹配")
private String deptName;
@ApiModelProperty("状态(0-启用;1-禁用)")
private String status;
}
3.实体添加权限字段注解
package com.hongtool.domain.module.system.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.hongtool.mybatis.perms.annotation.DeptPerm;
import com.hongtool.mybatis.perms.annotation.UserPerm;
import lombok.Data;
import java.time.LocalDateTime;
/**
* <p> 机构部门表 </p>
*
* @author hongtool
* @date 2022/9/23
*/
@Data
@TableName("sys_dept")
public class SysDeptEntity {
@DeptPerm
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 父节点id */
@TableField("parent_id")
private Long parentId;
/** 祖级列表 前后都会加上"," 方便查找 */
@TableField("ancestors")
private String ancestors;
/** 机构部门名称 */
@TableField("dept_name")
private String deptName;
/** 机构部门类型(1-机构;2-部门) */
@TableField("dept_type")
private String deptType;
/** 显示顺序 */
@TableField("order_num")
private Integer orderNum;
/** 负责人 */
@TableField("leader")
private String leader;
/** 联系电话 */
@TableField("phone")
private String phone;
/** 邮箱 */
@TableField("email")
private String email;
/** 状态(0-启用;1-禁用) */
@TableField("status")
private String status;
/** 创建者 */
@UserPerm
@TableField("create_by")
private String createBy;
/** 更新者 */
@TableField("update_by")
private String updateBy;
/** 备注 */
@TableField("remark")
private String remark;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
/** 修改时间 */
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
4.Mapper与Service继承自定义的Mapper与Service
省略ISysDeptService与SysDeptMapper代码
/**
* <p> 机构部门 ServiceImpl </p>
*
* @author hongtool
* @date 2022/9/23
*/
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class SysDeptServiceImpl extends HongToolServiceImpl<SysDeptMapper, SysDeptEntity> implements ISysDeptService {
private final ISysUserService sysUserService;
@Override
public List<SysDeptList> queryList(SysDeptQuery query, LoginUser loginUser) {
// 权限查询(使用带权限的查询方法)
List<SysDeptEntity> entityList = listPerms(
Wrappers.<SysDeptEntity>lambdaQuery()
.like(StrUtil.isNotEmpty(query.getDeptName()), SysDeptEntity::getDeptName, query.getDeptName())
.eq(StrUtil.isNotEmpty(query.getStatus()), SysDeptEntity::getStatus, query.getStatus())
.orderByAsc(SysDeptEntity::getOrderNum),
query);
return SysDeptConverter.INSTANCE.toSysDeptList(entityList);
}
}
测试结果
机构部门:
==> Preparing: SELECT id,parent_id,ancestors,dept_name,dept_type,order_num,leader,phone,email,status,create_by,update_by,remark,create_time,update_time FROM sys_dept WHERE id in ( ? , ? , ? ) ORDER BY order_num ASC
==> Parameters: 7(Long), 8(Long), 13(Long)
创建用户:
==> Preparing: SELECT id,parent_id,ancestors,dept_name,dept_type,order_num,leader,phone,email,status,create_by,update_by,remark,create_time,update_time FROM sys_dept WHERE create_by = ? ORDER BY order_num ASC
==> Parameters: test2(String)
总结
数据权限还是非常复杂的内容,不同的设计有不同的实现方式。这里只是提供下其中的一种思路。欢迎各位大佬指正。
代码工程还不是很完善,就不开放了,如有需要的。视情况而定。