第一次写数据权限,在网上找了很多材料,不知道具体功能能不能实现,姑且试试
背景
- 主要显示表,园区表,大棚表,用户表,权限表。
- 权限分为5种:1、所有权限;2、自定义权限(暂无用处,先设计上);3、园区及以下权限;4、大棚权限;5、个人。(注:2、5没用上,姑且就这样吧)
设计
1.设计注解(还算一个小白,对注解不是很熟悉)
//注解的作用目标
@Target(ElementType.METHOD)
//注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
//用来做标识(个人认为意义不大)
@Documented
public @interface WechatDataScope {
/**
* 园区表的别名
* @return
*/
public String parkAlias() default "";
/**
* 大棚表名
* @return
*/
public String greenhouseAlias() default "";
}
2.创建切面(第一次写切面)
/**
* 数据切面
*
* @author zhangxq
* @version 0.1
* @Time 3/25
*/
@Aspect
// 基础注解之一:为spring容器注册Bean
@Component
public class WechatDataScopeAspect {
// 1. 定义静态属性(权限)
// 权限1:全部
private static final String WECHAT_DATA_SCOPE_ALL = "1";
// 权限1:自定义
private static final String WECHAT_DATA_SCOPE_CUSTOM = "2";
// 权限1:园区
private static final String WECHAT_DATA_SCOPE_PARK = "3";
// 权限1:大棚
private static final String WECHAT_DATA_SCOPE_GREENHOUSE = "4";
// 权限1:本人
private static final String WECHAT_DATA_SCOPE_SELF = "5";
// 2. 定义数据权限过滤的关键字
private static final String WECHAT_DATA_SCOPE = "wechatDataScope";
// 3. 编辑织入点,空方法体
@Pointcut("@annotation(com.joolun.common.annotation.WechatDataScope)")
public void wechatDataScopePointCut(){
}
// 4. 增强类型,此处需要用到前置通知,去判断权限
@Before("wechatDataScopePointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable{
handleDataScope(joinPoint);
}
public void handleDataScope(final JoinPoint joinPoint){
// 获取注解,先去定义获取注解的方法,见方法getAnnotation
WechatDataScope wechatDataScope = getAnnotation(joinPoint);
if (wechatDataScope == null){
return;
}
//获取用户权限(我是因为登录没有用Secriuty框架,查询的时候前台传的权限的信息)
WechatLoginInfo wechatLoginInfo = (WechatLoginInfo)joinPoint.getArgs()[0];
// 判断如果用户存在
if (wechatLoginInfo != null){
dataScopeFilter(joinPoint,wechatLoginInfo,wechatDataScope.parkAlias(),wechatDataScope.greenhouseAlias());
}
}
/**
* 数据过滤
* @param joinPoint
* @param user
* @param parkAlias
* @param greenhouseAlias
*/
public static void dataScopeFilter(JoinPoint joinPoint, WechatLoginInfo user, String parkAlias, String greenhouseAlias)
{
StringBuilder sqlString = new StringBuilder();
String dataScope = user.getDataScope();
// 因为我获取园区和大棚两个是分开查的,懒得再写一个了,在这加个判断算了(如果有更好的方法可以告诉我)
if (joinPoint.getSignature().getName().equals("getPark")) {
if (WECHAT_DATA_SCOPE_ALL.equals(dataScope)) {
sqlString = new StringBuilder();
// 自定义
} else if (WECHAT_DATA_SCOPE_CUSTOM.equals(dataScope)) {
//拼接sql
sqlString.append(StringUtils.format("where {}.id in (select dept_id from sys_role_dept where role_id = {})"
, greenhouseAlias, user.getRoleId()));
// 权限3.园区及以下
} else if (WECHAT_DATA_SCOPE_PARK.equals(dataScope)) {
sqlString.append(StringUtils.format("Left Join sys_user su on (su.ssYqDp = {}.id) WHERE su.user_name = {}"
,parkAlias,user.getUserName()));
// 权限4.大棚
} else if (WECHAT_DATA_SCOPE_GREENHOUSE.equals(dataScope)) {
sqlString.append(StringUtils.format("Left Join sys_user su on (su.ssYqDp = {}.id) WHERE su.user_name = {}"
,greenhouseAlias,user.getUserName()));
// 权限5.本人
} else if (WECHAT_DATA_SCOPE_SELF.equals(dataScope)) {
sqlString.append(StringUtils.format("WHERE {}.createUser = {} or {}.createUser = {}"
,parkAlias,user.getUserName(),greenhouseAlias,user.getUserName()));
}
// 大棚
}else if(joinPoint.getSignature().getName().equals("getGreenhouse")){
// 如果是自定义
if (WECHAT_DATA_SCOPE_CUSTOM.equals(dataScope)){
sqlString.append(StringUtils.format("AND {}.id in (select dept_id from sys_role_dept where role_id = {})",
greenhouseAlias,user.getRoleId()));
}else if (WECHAT_DATA_SCOPE_GREENHOUSE.equals(dataScope)){
sqlString.append(StringUtils.format("AND {}.id = (select ssYqDp from sys_user where user_name = {})",
greenhouseAlias,user.getUserName()));
}else if (WECHAT_DATA_SCOPE_SELF.equals(dataScope)){
sqlString.append(StringUtils.format("AND {}.createUser = {}",
greenhouseAlias,user.getUserName()));
}else{
sqlString = new StringBuilder();
}
}
//判断是不是空,将数据权限的sql放到实体类里
if (StringUtils.isNotBlank(sqlString.toString())){
Object params = joinPoint.getArgs()[0];
// 用来判断能否携带参数
if (StringUtils.isNotNull(params) && params instanceof BaseEntity){
BaseEntity baseEntity = (BaseEntity) params;
baseEntity.getParams().put(WECHAT_DATA_SCOPE,sqlString);
}
}
}
/**
* 是否存在注解,有就获取注解
* @param joinPoint
* @return
*/
public WechatDataScope getAnnotation(JoinPoint joinPoint){
// 获取被增强的相关信息
Signature signature = joinPoint.getSignature();
// 因为作用在方法上,所以强转为被增强的方法的相关信息(个人这样理解)
MethodSignature methodSignature = (MethodSignature) signature;
// 获取方法
Method method = methodSignature.getMethod();
// 如果存在该方法
if (method != null){
// 返回方法上的注解
return method.getAnnotation(WechatDataScope.class);
}
return null;
}
}
3.掌握的技术
- AOP:面向切面编程(一直在背,接触不多)
- 创建接口注解
- 定义织入点(空方法体)
- 增强类型(注解具体要干什么在这里写)类型分为前置,后置,环绕,报错后置,引介增强
4.个人提醒(大佬就不要看了)
- 对于数据权限而言,注解接口里属性只用表的别名,当你用注解的时候,一定要注意,你定义表的别名和你xml里边sql表的别名一定要一致。
- 因为我没有用Secriuty框架,所以我自己前台获取的个人相关信息,用Secriuty的可以用
LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());