创建注解类
package com.dnk.business.link.annotation;
import com.dnk.business.link.web.system.enums.DataPermissionTypeEnum;
import java.lang.annotation.*;
/**
* 数据权限注解
* 用于MyBatis Mapper方法上,配合DataPermissionInterceptor实现数据权限过滤
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataPermission {
/**
* 数据权限类型
*/
DataPermissionTypeEnum type();
/**
* SQL中的表别名,默认为空
*/
String alias() default "";
/**
* 不过滤的字段。例如某个字段为某个值表示全部可见的时候需要配置unfilteredField和unfilteredValue
*/
String unfilteredField() default "";
/**
* 不过滤的值
*/
String unfilteredValue() default "";
}
实现DataPermissionHandler
package com.dnk.config.mp;
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import com.dnk.business.link.annotation.DataPermission;
import com.dnk.business.link.util.TokenUserInfo;
import com.dnk.business.link.web.system.entity.SysUser;
import com.dnk.business.link.web.system.enums.DataPermissionTypeEnum;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import java.lang.reflect.Method;
/**
* 数据权限处理器
*/
@Slf4j
@Component
public class MyDataPermissionHandler implements DataPermissionHandler {
@Autowired
private HttpServletRequest request;
@Override
public Expression getSqlSegment(Expression where, String mappedStatementId) {
try {
// 获取Mapper方法上的注解
String className = mappedStatementId.substring(0, mappedStatementId.lastIndexOf("."));
String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);
Class<?> mapperClass = Class.forName(className);
Method[] methods = mapperClass.getMethods();
DataPermission dataPermission = null;
// 简单匹配方法名,暂不考虑重载情况(MyBatis Mapper通常不建议重载)
for (Method method : methods) {
if (method.getName().equals(methodName) && method.isAnnotationPresent(DataPermission.class)) {
dataPermission = method.getAnnotation(DataPermission.class);
break;
}
}
if (dataPermission == null) {
return where;
}
// 获取当前用户
// 注意:这里可能在非Web环境下调用,需要判空
if (RequestContextHolder.getRequestAttributes() == null) {
return where;
}
SysUser user = TokenUserInfo.getTokenUserInfo(request);
if (user == null) {
// 未登录,不返回数据
return CCJSqlParserUtil.parseCondExpression("1=0");
}
// 管理员查看所有数据
if ("1".equals(user.getUserType())) {
return where;
}
// 构造权限SQL
DataPermissionTypeEnum type = dataPermission.type();
String alias = dataPermission.alias();
String tableName = StringUtils.isNotBlank(alias) ? alias : type.getTableName();
// 处理别名
String dataIdColumn = tableName + ".id";
// 处理不过滤的条件(如果有)
String unfilteredSql = null;
if (StringUtils.isNotBlank(dataPermission.unfilteredField())) {
unfilteredSql = tableName + ". " +dataPermission.unfilteredField() + " = '" + dataPermission.unfilteredValue() + "'";
}
// 构造权限SQL
String sql = String.format(
"(exists (select 1 from sys_data_permission p join sys_dept_user_rel u on p.dept_id = u.dept_id where p.data_id = %s and p.data_type = '%s' and u.user_id = %s) %s)",
dataIdColumn, type.getCode(), user.getId(), StringUtils.isNotBlank(unfilteredSql) ? "or " + unfilteredSql : ""
);
Expression appendExpression = CCJSqlParserUtil.parseCondExpression(sql);
// 拼接 AND 条件
AndExpression andExpression = new AndExpression(where, appendExpression);
log.debug("附加数据权限SQL: {}", andExpression.toString());
return andExpression;
} catch (Exception e) {
log.error("数据权限处理异常", e);
// 异常时为了安全起见,可以不返回数据或者忽略
return null;
}
}
}
数据类型枚举
package com.dnk.business.link.web.system.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 数据权限类型枚举
*/
@Getter
@AllArgsConstructor
public enum DataPermissionTypeEnum {
/**
* AI提示词信息
*/
PROMPT("prompt", "ai_prompt", "AI提示词信息"),
;
/**
* 类型编码(前端传递)
*/
private final String code;
/**
* 数据库表名
*/
private final String tableName;
/**
* 描述
*/
private final String description;
/**
* 根据编码获取表名
*
* @param code 类型编码
* @return 表名
*/
public static String getTableNameByCode(String code) {
for (DataPermissionTypeEnum value : values()) {
if (value.getCode().equals(code)) {
return value.getTableName();
}
}
return null;
}
/**
* 校验编码是否存在
*
* @param code 类型编码
* @return 是否存在
*/
public static boolean isValidCode(String code) {
for (DataPermissionTypeEnum value : values()) {
if (value.getCode().equals(code)) {
return true;
}
}
return false;
}
}
上述仅为示例,具体以实际业务进行改造。
用法:在Mapper方法中添加注解
@DataPermission(type = DataPermissionTypeEnum.PROMPT, alias = "ap", unfilteredField = "sys_dept_id", unfilteredValue = "0")
List<AiPrompt> queryByAiModelSetting(QueryAiPromptQo queryAiPromptQo);