怎么用Springboot+mybatis-plus+注解实现数据权限隔离

怎么用Springboot+mybatis-plus+注解实现数据权限隔离

今天小编给大家分享一下怎么用Springboot+mybatis-plus+注解实现数据权限隔离的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

1.创建注解

当此注解打在类上,不需要传参,该类下所有查询接口开启数据隔离;打在方法上默认开启数据隔离,传参为false则该方法关闭验证

怎么用Springboot+mybatis-plus+注解实现数据权限隔离

/***数据权限验证注解*@authorxiaohua*@date2021/6/23*/@Documented@Target({METHOD,ANNOTATION_TYPE,TYPE})@Retention(RUNTIME)public@interfaceDataPermission{/***是否要进行数据权限隔离*/booleanisPermi()defaulttrue;}

2. 具体实现

@Component@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class,Integer.class})})publicclassDataPermissionInterceptorimplementsInterceptor{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(DataPermissionInterceptor.class);@AutowiredprivateTokenServicetokenService;//扫描的包路径(根据自己的项目路径来),这里是取的配置里的包路径@Value("${permission.package-path}")privateStringpackagePath;privatefinalstaticStringDEPT_ID="dept_id";privatefinalstaticStringUSER_ID="create_user";privatestaticList<String>classNames;@OverridepublicObjectintercept(Invocationinvocation)throwsThrowable{try{LoginInfouser=tokenService.getLoginInfo();if(user==null){returninvocation.proceed();}List<Long>deptIds=(List<Long>)Convert.toList(user.getDataScope());if(deptIds==null){deptIds=newArrayList<>();}//反射扫包会比较慢,这里做了个懒加载if(classNames==null){synchronized(LazyInit.class){if(classNames==null){//扫描指定包路径下所有包含指定注解的类Set<Class<?>>classSet=ClassUtil.scanPackageByAnnotation(packagePath,DataPermission.class);if(classSet==null&&classSet.size()==0){classNames=newArrayList<>();}else{//取得类全名classNames=classSet.stream().map(Class::getName).collect(Collectors.toList());}}}}//拿到mybatis的一些对象StatementHandlerstatementHandler=PluginUtils.realTarget(invocation.getTarget());MetaObjectmetaObject=SystemMetaObject.forObject(statementHandler);MappedStatementmappedStatement=(MappedStatement)metaObject.getValue("delegate.mappedStatement");//mappedStatement.getId()为执行的mapper方法的全路径名,newId为执行的mapper方法的类全名StringnewId=mappedStatement.getId().substring(0,mappedStatement.getId().lastIndexOf("."));//如果不是指定的方法,直接结束拦截if(!classNames.contains(newId)){returninvocation.proceed();}StringnewName=mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".")+1,mappedStatement.getId().length());//是否开启数据权限booleanisPermi=true;Class<?>clazz=Class.forName(newId);//遍历方法for(Methodmethod:clazz.getDeclaredMethods()){//方法是否含有DataPermission注解,如果含有注解则将数据结果过滤if(method.isAnnotationPresent(DataPermission.class)&&newName.equals(method.getName())){DataPermissiondataPermission=method.getAnnotation(DataPermission.class);if(dataPermission!=null){//不验证if(!dataPermission.isPermi()){isPermi=false;}else{//开启验证isPermi=true;}}}}if(isPermi){//获取到原始sql语句Stringsql=statementHandler.getBoundSql().getSql();//解析并返回新的SQL语句,只处理查询sqlif(mappedStatement.getSqlCommandType().toString().equals("SELECT")){//StringnewSql=getNewSql(sql,deptIds,user.getUserId());sql=getSql(sql,deptIds,user.getUserId());}//修改sqlmetaObject.setValue("delegate.boundSql.sql",sql);}returninvocation.proceed();}catch(Exceptione){logger.error("数据权限隔离异常:",e);returninvocation.proceed();}}/***解析SQL语句,并返回新的SQL语句*注意,该方法使用了JSqlParser来操作SQL,该依赖包Mybatis-plus已经集成了。如果要单独使用,请先自行导入依赖**@paramsql原SQL*@return新SQL*/privateStringgetSql(Stringsql,List<Long>deptIds,LonguserId){try{Stringcondition="";StringpermissionSql="(";if(deptIds.size()>0){for(LongdeptId:deptIds){if("(".equals(permissionSql)){permissionSql=permissionSql+deptId;}else{permissionSql=permissionSql+","+deptId;}}permissionSql=permissionSql+")";//修改原语句condition=DEPT_ID+"in"+permissionSql;}else{condition=USER_ID+"="+userId;}if(StringUtils.isBlank(condition)){returnsql;}Selectselect=(Select)CCJSqlParserUtil.parse(sql);PlainSelectplainSelect=(PlainSelect)select.getSelectBody();//取得原SQL的where条件finalExpressionexpression=plainSelect.getWhere();//增加新的where条件finalExpressionenvCondition=CCJSqlParserUtil.parseCondExpression(condition);if(expression==null){plainSelect.setWhere(envCondition);}else{AndExpressionandExpression=newAndExpression(expression,envCondition);plainSelect.setWhere(andExpression);}returnplainSelect.toString();}catch(JSQLParserExceptione){logger.error("解析原SQL并构建新SQL错误:"+e);returnsql;}}

以上就是“怎么用Springboot+mybatis-plus+注解实现数据权限隔离”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注恰卡编程网行业资讯频道。

发布于 2022-04-03 22:33:49
收藏
分享
海报
0 条评论
39
上一篇:springboot项目事务标签验证问题怎么解决 下一篇:idea怎么使用外置tomcat配置springboot
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码