肥宅钓鱼网
当前位置: 首页 钓鱼百科

简述mybatis中如何实现模糊查询(如何使用Mybatis的拦截器实现数据加密与解密)

时间:2023-08-12 作者: 小编 阅读量: 1 栏目名: 钓鱼百科

既然是拦截器,可以拦截哪些内容呢?试想一下......当程序写到持久层时,Mybatis会执行指定SQL语句,并处理请求参数和返回值。

拦截器介绍

Mybatis Interceptor 在 Mybatis 中被当作 Plugin(插件),不知道为什么,但确实是在 org.apache.ibatis.plugin 包下面。

既然是拦截器,可以拦截哪些内容呢?试想一下...... 当程序写到持久层时,Mybatis 会 执行 指定 SQL 语句,并处理 请求参数返回值。没错,Mybatis 拦截器可以帮助我们处理上述内容,请看官网的 Plugins 的片段, 内容不多

// 执行Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)// 请求参数处理ParameterHandler (getParameterObject, setParameters)// 返回结果集处理ResultSetHandler (handleResultSets, handleOutputParameters)// SQL语句构建StatementHandler (prepare, parameterize, batch, update, query)

拦截器的使用

如果需要实现自定义的拦截器,只需要实现 org.apache.ibatis.plugin.Interceptor 接口,该接口有三个方法:

Object intercept(Invocation invocation) throws Throwable;Object plugin(Object target);void setProperties(Properties properties);

我们要实现数据加密,进入数据库的字段不能是真实的数据,但是返回来的数据要真实可用,所以我们需要针对 Parameter 和 ResultSet 两种类型处理,同时为了更灵活的使用,我们需要自定义注解

自定义注解

类注解,将注解放在实体类上

/** * 需要加解密的类注解 */@Documented@Inherited@Target({ ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)public @interface EncryptDecryptClass {}

字段注解,将注解放在实体字段上

/** * 加密字段注解 */@Documented@Inherited@Target({ ElementType.FIELD })@Retention(RetentionPolicy.RUNTIME)public @interface EncryptDecryptField {}

有了这两个注解,我们可以在我们可以标记我们要处理的实体和实体中的字段

自定义参数处理拦截器

参考官网,通过 @Intercepts 和 @Signature 的联合使用,指定 ParameterHandler.Class 类型,同时通过 @Component注解注入到容器中,即可在设置参数的时候进行拦截,通过自定义接口 IEncryptDecrypt, 根据 Field 的各种类型自定义加密解密算法

@Intercepts({ @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),})@ConditionalOnProperty(value = "domain.encrypt", havingValue = "true")@Component@Slf4jpublic class ParammeterInterceptor implements Interceptor { @Autowired private IEncryptDecrypt encryptDecrypt; @Override public Object intercept(Invocation invocation) throws Throwable { log.info("拦截器ParamInterceptor"); //拦截 ParameterHandler 的 setParameters 方法 动态设置参数 if (invocation.getTarget() instanceof ParameterHandler) { ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget(); PreparedStatement ps = (PreparedStatement) invocation.getArgs()[0]; // 反射获取 BoundSql 对象,此对象包含生成的sql和sql的参数map映射 /*Field boundSqlField = parameterHandler.getClass().getDeclaredField("boundSql"); boundSqlField.setAccessible(true); BoundSql boundSql = (BoundSql) boundSqlField.get(parameterHandler);*/ // 反射获取 参数对像 Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject"); parameterField.setAccessible(true); Object parameterObject = parameterField.get(parameterHandler); if (Objects.nonNull(parameterObject)){ Class<?> parameterObjectClass = parameterObject.getClass(); EncryptDecryptClass encryptDecryptClass = AnnotationUtils.findAnnotation(parameterObjectClass, EncryptDecryptClass.class); if (Objects.nonNull(encryptDecryptClass)){ Field[] declaredFields = parameterObjectClass.getDeclaredFields(); final Object encrypt = encryptDecrypt.encrypt(declaredFields, parameterObject); } } } return invocation.proceed(); } @Override public Object plugin(Object o) { return Plugin.wrap(o, this); } @Override public void setProperties(Properties properties) { }}

同样新建结果集拦截器

结果集拦截器

与参数拦截器基本一样, 只不过类型指定为 ResultSetHandler.class

@Intercepts({ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args={Statement.class})})@ConditionalOnProperty(value = "domain.decrypt", havingValue = "true")@Component@Slf4jpublic class ResultInterceptor implements Interceptor { @Autowired private IEncryptDecrypt encryptDecrypt; @Override public Object intercept(Invocation invocation) throws Throwable { Object result = invocation.proceed(); if (Objects.isNull(result)){ return null; } if (result instanceof ArrayList) { ArrayList resultList = (ArrayList) result; if (CollectionUtils.isNotEmpty(resultList) && needToDecrypt(resultList.get(0))){ for (int i = 0; i < resultList.size(); i) { encryptDecrypt.decrypt(resultList.get(i)); } } }else { if (needToDecrypt(result)){ encryptDecrypt.decrypt(result); } } return result; } public boolean needToDecrypt(Object object){ Class<?> objectClass = object.getClass(); EncryptDecryptClass encryptDecryptClass = AnnotationUtils.findAnnotation(objectClass, EncryptDecryptClass.class); if (Objects.nonNull(encryptDecryptClass)){ return true; } return false; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { }}

加密解密接口

IEncryptDecrypt 接口定义了 加密和解密两个方法:

public interface IEncryptDecrypt { /** * 加密方法 * @param declaredFields 反射bean成员变量 * @param parameterObject Mybatis入参 * @param <T> * @return */ public <T> T encrypt(Field[] declaredFields, T parameterObject) throws IllegalAccessException; /** * 解密方法 * @param result Mybatis 返回值,需要判断是否是ArrayList类型 * @param <T> * @return */ public <T> T decrypt(T result) throws IllegalAccessException;}

两个拦截器通过在 YAML 中配置属性,按条件注入,外加自定义加密解密算法,完成全局灵活的配置。

核心代码已上传至 Github Demo

问题彩蛋

也许应对当前的业务,看了该文章满足了当下需求,我们目前只看到了什么是 Mybatis 拦截器,怎样简单使用,拦截器的其他用法以及其他很多为什么都没有解决,关注公众号,回复“人迹罕至” 读完文章 「程序猿为什么要看源码」后 ,我不会满足眼前的这些基本应用,我会有诸多疑问,

  1. 我们日常写 CRUD 的业务,为什么 Executor 中只有 R(query) 和 U(update), 那么C(insert) 和 D(delete) 怎样处理的?
  2. 自定义拦截器是以什么方式被执行的,执行顺序是什么?
  3. 分页也是 Mybatis 拦截器的一种,带有分页的框架是怎样使用拦截器的呢?如 Mybatis Plus, PageHelper
  4. 虽然重写了 Inteceptor 接口的 public void setProperties(Properties properties) 方法,但是并没有写什么业务逻辑,这个方法能怎样使用?
  5. ......

后续文章也会通过读源码的方式逐步解析这些问题,当然你有相关问题也可以留言交流讨论

提高效率工具

依旧推荐在写文章时用到的高效工具,后续相关工具也会在文章中陆续更新,请持续关注

MyBatis Log Plugin

MyBatis Log Plugin 是 Intelligj IDEA 的一个插件,用来从 Mybatis 输出的 log 中提取出当前调用的 SQL 语句,并将参数封装在 SQL 语句中组成完整的 SQL,这样,当我们调试的时候更加清晰方便,可以轻松定位是否 SQL 又问题

转载自公众号:日拱一兵

,
    推荐阅读
  • 什么病不能喝牛奶 什么病不能喝牛奶吃鸡蛋

    结肠炎结肠炎的常见症状表现为腹痛和下泄,牛奶在消化道中不容易被分解,从而对肠道产生刺激作用,导致下泄和腹痛现象变得更加严重。腹部手术后经历过腹部手术的人群多会出现肠胀气,牛奶中含有较多的脂肪和酪蛋白,发酵后会产生气体,腹部手术后喝牛奶,会导致肠胀气加重,不利于肠蠕动功能的恢复。

  • 下雪会不会影响飞机起飞(下雪会影响飞机起飞吗)

    下雪会影响飞机起飞,至于影响程度要看雪的大小、厚度、结冰程度等具体情况飞机的飞行主要分为起飞爬升,航路巡航飞行和进近着陆三个阶段风雪天气的到来,对这三个阶段都会造成不同程度的影响,我来为大家讲解一下关于下雪会不会影响飞机起飞?跟着小编一起来看一看吧!飞机的飞行主要分为起飞爬升,航路巡航飞行和进近着陆三个阶段。雪天对于航路巡航阶段的飞行影响最小,但是积雪,结冰会严重危及飞机起降阶段的安全。

  • 淘宝代付退款退到哪里(如果朋友代付淘宝退款的流向)

    接下来我们就一起去研究一下吧!淘宝代付退款退到哪里淘宝朋友代付的退款退回路径有两种情况:单笔订单代付的退款:在该笔订单确认收货之前退款的话会退回代付人账户。订单“确认收货”之后退款的话,卖家同意退款申请的就会退回代付人账户。小二介入后转移卖家保证金退款的就会退回下单人的支付宝余额。

  • 补血补肾的食物有哪些(补血补肾认准的食物)

    首推山药,药食同源,日常可以适当多吃,不喜欢吃的人,可以做成蓝莓山药,也是不错的选择,山药可以健脾益胃补肾,固肾益精,聪耳明目,强筋骨,常吃可延年益寿,但便秘患者不建议多吃,可能会加重便秘。另外黑色食物、红色食物可补血补肾,如红枣、黑豆、黑芝麻、乌鸡、黑木耳、核桃、桑葚、黑米等。最后,可适当吃些动物内脏,猪肝等,鸭血、瘦肉、鱼、蛋、奶等均可补血补肾。当然要注意营养均衡,不可一味偏食某种食物。

  • 沙井最穷的地方是哪个(在沙井娄山关的日子)

    沙井最穷的地方是哪个我没做安利后只得又一次南下深圳。弟弟在沙井上南社区大和精密组件有限公司做品质工程师。和我同去面试的共有5人,但工厂只提供了一个仓管员的职位。当即就有一个求职者信心不足,自己放弃了竞争。老板是个军人,姓杨,四川人,据说和成都某重要部门那个姓杨的有密切关系。负责板材的是一个贵州崽,叫娄永强,他是娄经理的侄儿。娄永强平时言语不多,总是一副冷酷的表情。

  • 光与夜之恋第一幕攻略(光与夜之恋周年庆庆典装扮攻略)

    光与夜之恋周年庆庆典活动需要玩家搭配装扮来拿到奖励,下面小编带来光与夜之恋周年庆庆典装扮攻略,希望可以帮到大家。光与夜之恋周年庆庆典装扮攻略1、省流最优解︰第一天加速拉满。

  • 最好的波轮洗衣机是哪款(大牌波轮洗衣机推荐)

    海尔的波轮洗衣机可靠性不错,家用整机享受三年质保,公用为一年。5Whirlpool/惠而浦波轮洗衣机X系列惠而浦X系列外观非常精致,顶部的玻璃盖板方便使用的时候观察洗衣的情况,阻尼式的设计可以有效避免夹伤,支持6种洗涤模式,基本能够满足日常洗衣需求。以上几款波轮洗衣机的性价比可以说是非常高的,价格不贵,但是功能比较齐全,能够满足大部分人对波轮洗衣机的需求。

  • 工作能力提升方面有哪些 工作能力提升方面有哪些建议

    向书本学,增长知识和文化素养。身边的每一位同事都有你学习的一方面。主动参与单位和部门中的疑难险重工作任务,运用自己的知识和能力在其中献计献策,检验自己的学习成果,加强实践锻炼。

  • 鱼美人是什么花 鱼美人是什么花的名字

    鱼美人是虞美人,虞美人是一年生或二年生草本植物,原产欧洲,中国各地常见栽培,为观赏植物。虞美人的生长发育适温为5~25摄氏度,春夏温度高地区花期缩短,昼夜温差大。夜间低温有利于生长开花,在高海拔山区生长良好,花色更为艳丽。虞美人耐寒,怕暑热,喜阳光充足的环境,喜排水良好、肥沃的沙壤土,不耐移栽,忌连作与积水。

  • 女性的白带有点黑(下面太黑是因为)

    但进入青春期后,性激素水平分泌增高,雌激素会加速黑色素产生以及沉积,从而使得私处颜色加深。每天睡觉前用温水对局部清洗,不能滥用清洗液,能有效减少细菌滋生。优先选择宽松且透气性好的纯棉内裤,利于局部散热,防止细菌入侵。因为频繁性爱会使得阴道受到机械损伤,粘膜受损使得致病菌入侵,进而导致妇科疾病。还有性爱不注意卫生以及有多个性伴侣也会导致性病。