怎么用Springboot+mybatis-plus+注解实现数据权限隔离
怎么用Springboot+mybatis-plus+注解实现数据权限隔离
今天小编给大家分享一下怎么用Springboot+mybatis-plus+注解实现数据权限隔离的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
1.创建注解
当此注解打在类上,不需要传参,该类下所有查询接口开启数据隔离;打在方法上默认开启数据隔离,传参为false则该方法关闭验证
/***数据权限验证注解*@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+注解实现数据权限隔离”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注恰卡编程网行业资讯频道。
推荐阅读
-
springboot实现基于aop的切面日志
本文实例为大家分享了springboot实现基于aop的切面日志的具体代码,供大家参考,具体内容如下通过aop的切面方式实现日志...
-
SpringBoot定时任务功能怎么实现
-
SpringBoot中的@Import注解怎么使用
-
SpringBoot整合Lombok及常见问题怎么解决
-
MyBatis和jeesite多表查询的方法
MyBatis和jeesite多表查询的方法这篇文章主要介绍了My...
-
Mybatis怎么实现ResultMap结果集
-
springboot图片验证码功能模块怎么实现
-
Springboot+SpringSecurity怎么实现图片验证码登录
-
SpringBoot注解的知识点有哪些
SpringBoot注解的知识点有哪些这篇“SpringBoot注...
-
SpringBoot2.x中management.security.enabled=false无效怎么解决