自定义注解与拦截器实现不规范sql拦截(拦截器实现篇)

最近考虑myBatis中sql语句使用规范的问题,如果漏下条件或者写一些不规范语句会对程序性能造成很大影响。最好的方法就是利用代码进行限制,通过拦截器进行sql格式的判断在自测环节就能找到问题。写了个简单情景下的demo,并通过idea插件来将myBatis的mapper方法都打上拦截器判断的注解,多少自动化一点。

需求简介

使用myBatis拦截器对Mapper的sql进行判断,对增加了自定义注解修饰的方法进行where条件的判断,存在where子句再执行,否则抛出异常。

具体实现

自定义注解

// 标志注解,用来表示mapper方法需要经过where条件存在与否的判断
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface WhereConditionCheck {
}

限定method修饰,同时指定runtime,以在运行过程中判断是否被该注解修饰。

拦截器实现类

WhereConditionInterceptor拦截器判断类

@Intercepts({// 拦截query方法@Signature(type = Executor.class, method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class,method = "update",args = {MappedStatement.class, Object.class})
})
@Component
@Slf4j
// 利用myBatis拦截器去获取对应的语句,where条件放行,无where阻止
public class WhereConditionInterceptor implements Interceptor {

首先利用@Intercepters注解,定义拦截器拦截的方法。这些方法来自Mybatis执行时调用的Executor接口的实现类,并通过args参数的设置来唯一指定同名的重载方法。

    @Overridepublic Object intercept(Invocation invocation) throws Throwable {// 获取sql信息MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];Object parameter = invocation.getArgs()[1]; // 参数BoundSql sql = mappedStatement.getBoundSql(parameter);// 获取原始调用方法的注解信息String id = mappedStatement.getId();String className = id.substring(0, id.lastIndexOf("."));String methodName = id.substring(id.lastIndexOf(".") + 1);Method[] methods = Class.forName(className).getMethods();// 不考虑方法重载for(Method method:methods){if(method.getName().equals(methodName) && method.isAnnotationPresent(WhereConditionCheck.class)){// 执行拦截boolean checkResult = checkIfWhereExist(sql);if(!checkResult){// 根据sql类型判断抛出异常的语句SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();if(sqlCommandType.equals(SqlCommandType.SELECT)) {log.error("query error, sql='" + sql.getSql() + "''");throw new RuntimeException("Query methods must contain where condition. method:" + id);} else if(sqlCommandType.equals(SqlCommandType.DELETE)) {log.error("delete error, sql='" + sql.getSql()  + "''");throw new RuntimeException("Delete methods must contain where condition. method:" + id);}}}}return invocation.proceed();}

重写intercept方法,利用invocation来获取之前定义的拦截方法的具体参数对象,利用第一个参数MappedStatement对象来获取具体的sql信息。需要注意的是,为了获取原Mapper接口中定义方法的注解信息,我们需要利用getId获取完整的接口名和类名,并利用反射获取对应的方法对象,以判断对应方法是否存在@WhereConditionCheck注解。

    private boolean checkIfWhereExist(BoundSql sql){String sqlStr = sql.getSql();sqlStr = sqlStr.toUpperCase();return sqlStr.contains("WHERE");}

具体的判断就直接将字符串转成大写后进行匹配即可。

简单使用

Mapper接口

@Mapper
public interface UserMapper {@Select("select * from user where code = #{code}")@WhereConditionCheckpublic User findUserByCode(String code);@Select("select * from user")// 全量查询,需要拦截@WhereConditionCheckpublic List<User> findUserListWhole();

简单设置两个方法,where子句和全量查询。

controller

@Controller
@RequestMapping("/user")
public class WhereConditionCheckController {@AutowiredUserMapper userMapper;@ResponseBody@RequestMapping("/queryWhole")// 全量查询public String getWholeUser(){try {List<User> userList = userMapper.findUserListWhole();return JSONObject.toJSONString(userList);}catch(Exception ex){// 获取异常栈最底层以显示自定义信息Throwable cause = ex;Throwable result = null;while(cause != null){result = cause;cause = cause.getCause();}return result.getMessage();}}@ResponseBody@RequestMapping("/queryByCode")// where查询public String getUser(String code){try{User user = userMapper.findUserByCode(code);return JSONObject.toJSONString(user);}catch(Exception ex){/// 获取异常栈最底层以显示自定义信息Throwable cause = ex;Throwable result = null;while(cause != null){result = cause;cause = cause.getCause();}return result.getMessage();}}
}

对两个方法进行使用访问。需要注意的是,为了返回拦截器中抛出方法设定的message,需要捕获到异常栈中底层的exception进行输出。

效果展示

postman进行调用:
在这里插入图片描述
全量查询被拒绝。
在这里插入图片描述
这边有做一个脱敏处理,不用管。可以看出能正常查询出来。

总结

简单展示了使用Mybatis拦截器进行where子句判断的方式,用完整的类名和方法名去定位自定义注解,比较麻烦的其实是如何显示最原始的异常信息。开头说的使用插件自动添加自定义注解的实现,放在自定义注解与拦截器实现不规范sql拦截(自定义注解填充插件篇)中来讲。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/245003.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leaflet学习笔记-带过滤的图例(九)

前言 图例不只能够帮助我们在查看地图的时候更加方便容易地分辨不同颜色代表的要素&#xff0c;本文要介绍的图例组件还可以按需求过滤掉不用显示的要素&#xff0c;使地图的更能清晰的显示我们需要显示的内容 技术核心 说到过滤要素&#xff0c;第一时间想到的就是滑块组件…

内网穿透、远程桌面、VPN的理解

最近在研究内网穿透的相关技术&#xff0c;然后回想起一些相关的技术&#xff0c;比如说要远程桌面公司的电脑&#xff0c;VPN连入内网等。然后想着在此处记录一下&#xff0c;各个的区别&#xff0c;这个纯粹是从技术层面的理解&#xff0c;此处不详细解释怎么去实现或者用什么…

【C++】stack、queue的使用及模拟实现

目录 一、stack1.1 stack的使用1.2 stack的模拟实现 二、queue2.1 queue的使用2.2 queue的模拟实现 一、stack 1.1 stack的使用 stack是一种容器适配器&#xff0c;它的特点是后进先出&#xff0c;只能在容器的一端进行插入和删除操作。 stack的使用很简单&#xff0c;主要有…

在IDEA中创建SpringBoot项目

概述 SpringBoot是由Pivotal团队提供的全新的框架&#xff0c;其设计的目的是用来简化Spring应用的初始搭建以及开发过程。 传统方式构建Spring应用程序 导入依赖繁琐 依赖冲突 项目配置繁琐 SpringBoot特性 1、起步依赖 本质上就行一个Maven坐标&#xff0c;整合了完成一…

Java 集合List相关面试题

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于java面试题系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基…

dataGrip连接数据库mysql和intersystems的iris

文章目录 前言创建新项目选择对应的数据库产品类型新建数据库资源连接sql命令窗体手动配置本地驱动 前言 intersystems公司的产品iris是cache的升级版本&#xff0c;目前绝大多数数据库工具都没法连接这个数据库 datagrip下载地址 https://download-cdn.jetbrains.com.cn/da…

eBay在人工智能道路上的成败得失:衡量标准是关键

我是2006年加入eBay的。2009年&#xff0c;这家公司的运营状况非常糟糕&#xff0c;其股价创历史新低&#xff08;远低于近24美元的历史高位&#xff09;&#xff0c;还出现削减各项成本、负增长、市场占有率降低、技术团队缺乏创新能力等情况。 简而言之&#xff0c;eBay公司…

CentOS7自动备份数据库到git

虽然数据库没什么数据&#xff0c;但是有就是珍贵的啦&#xff0c;为了服务器什么的无了&#xff0c;所以还是要自动备份一下比较好。 Open备忘第一页 步骤 在Gitee&#xff08;github&#xff09;上创建一个私有仓库Gitee&#xff08;github&#xff09;配置好服务器的ssh在服…

Oracle BIEE 示例(一)数据透视表2

1 背景 版本:BIEE 12C 视图:数据透视表 实现内容(顺序与具体内容不一致): 2 空列显示(方法一) 2.1 问题 列为空时,标题栏不显示信息。 2.2 期望 即使数据为空,也要显示列名。 2.3 官方资料 2.3.1 操作步骤 2.3.1.1 要在分析级别关闭空值隐藏,请执行以下操作…

MySQL与PostgreSQL对比

对比 许可证 License MySQL 社区版采用 GPL 许可证。Postgres 发布在 PostgreSQL 许可下&#xff0c;是一种类似于 BSD 或 MIT 的自由开源许可。 即便 MySQL 采用了 GPL&#xff0c;仍有人担心 MySQL 归 Oracle 所有&#xff0c;这也是为什么 MariaDB 从 MySQL 分叉出来。 …

mac安装部署gitbook教程

mac安装部署gitbook教程 前言一、安装准备二、GitBook安装三、项目初始化 前言 一些自己实际操作的记录。 一、安装准备 Node.js gitbook基于Node.js&#xff0c;所以需要提前安装。 下载地址&#xff1a;https://nodejs.org/en/&#xff0c;可以下载比较新的版本。(但我的建议…

[已解决]504 Gateway Time-out 网关超时

文章目录 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时思路解决 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时 思路 网上的常规思路是修改nginx配置文件,增加请求执行时间,试过没有用 keepalive_timeout 600; fastcgi_con…

vue3-深入组件-组件注册和props更多细节

组件注册 定义好的组件需要注册才能被使用。 注册方式有两种 全局注册 局部注册 全局注册 .component() 方法&#xff0c;让组件在当前 Vue 应用中全局可用。 在 main.ts 中 import ./assets/main.cssimport { createApp } from vue import { createPinia } from pinia i…

基于springboot+vue的网上租赁系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

碳排放预测 | Matlab实现LSTM多输入单输出未来碳排放预测,预测新数据

碳排放预测 | Matlab实现LSTM多输入单输出未来碳排放预测&#xff0c;预测新数据 目录 碳排放预测 | Matlab实现LSTM多输入单输出未来碳排放预测&#xff0c;预测新数据预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab实现LSTM长短期记忆神经网络多输入单输出未来…

架构师之路(十六)计算机网络(传输层)

前置知识&#xff08;了解&#xff09;&#xff1a;计算机基础。 作为架构师&#xff0c;我们所设计的系统很少为单机系统&#xff0c;因此有必要了解计算机和计算机之间是怎么联系的。局域网的集群和混合云的网络有啥区别。系统交互的时候网络会存在什么瓶颈。 既然网络层已经…

C# Bitmap类学习1

Bitmap对象封装了GDI中的一个位图&#xff0c;此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using …

mybatis----小细节

1、起别名 在MyBatis中&#xff0c;<typeAliases>元素用于定义类型别名&#xff0c;它可以将Java类名映射为一个更简短的别名&#xff0c;这样在映射文件中可以直接使用别名而不需要完整的类名。 下面是一个示例&#xff1a; 在mybatis核心配置文件中配置typeAliases标…

第21课 在Android Native开发中架起java与c++互通的桥梁

在开始本节课&#xff0c;我尝试把项目拷贝到另一台电脑上以便继续工作&#xff0c;但出现了大量的“could not be resolved”问题&#xff0c;尝试包含新的include路径也无法解决该问题&#xff0c;最后删除了项目的Native Support&#xff0c;然后重新添加Native Support才解…

百科同名就不能重建一个百科吗,代创建百科公司是如何做到的

发现自己的名字在百度上已经有百科词条并不出奇&#xff0c;因为同名同姓的人非常多&#xff0c;但是是不是百科已经有同名词条了就不能重建一个百科&#xff0c;很多朋友在自己做百度百科不通过时往往会发出这样的疑问。 实际上百度百科同名也是可以再重新创建的&#xff0c;…