怎么用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+注解实现数据权限隔离”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注恰卡编程网行业资讯频道。
推荐阅读
-
iphone(14 plus 双卡双待设置 苹果手机14双卡是什么概念)
苹果手机14双卡是什么概念?苹果手机14双卡的概念是双卡双待,普通持一台手机就能用两张手机卡两个号码的使用。我国所售卖的苹果手机1...
-
mybatis如何编写一个自定义插件(mybatis plus优点)
mybatisplus优点?Mybatis-Plus是一个Mybatis的增强工具,只是在Mybatis的基础上做了增强却不做改...
-
oppor11s手机隐藏应用功能在哪里(oppo r 11s plus 拔号键盘隐藏功能)
oppor11splus拔号键盘隐藏功能?再打开oppo手机光盘驱动的拨号盘界面:1、输入“*#*#4636#*#*”,查...
-
iphone(6 plus 怎样调出铃声 苹果专注模式没声音)
苹果专注模式没声音?苹果手机专注心模式没声音的原因和解决方法:踏实专注模式是一种实际尽肯定会减少干扰到来帮您踏实专注于任务的功能。...
-
vue动态添加删除输入框(springboot vue怎么让数据库显示出来)
springbootvue怎么让数据库显示出来?一般情况下是前端调阅后端接口,来获取到数据库的数据,后端哪里会把数据库的数据整理...
-
springboot实现基于aop的切面日志
本文实例为大家分享了springboot实现基于aop的切面日志的具体代码,供大家参考,具体内容如下通过aop的切面方式实现日志...
-
SpringBoot定时任务功能怎么实现
-
SpringBoot中的@Import注解怎么使用
-
SpringBoot整合Lombok及常见问题怎么解决
SpringBoot整合Lombok及常见问题怎么解决这篇文章主要...
-
MyBatis和jeesite多表查询的方法
MyBatis和jeesite多表查询的方法这篇文章主要介绍了My...