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

简述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 又问题

转载自公众号:日拱一兵

,
    推荐阅读
  • 禾字组词和造句(禾字组词并造句)

    田里的禾苗长得很旺盛。绿色的禾苗好可爱。

  • 比亚迪宋发动机怎么样 比亚迪宋发动机耐用吗

    所以经过慎重考虑,从价格出发,着眼空房间和实用配置,最终选定了宋老爷车,于是在7月中旬果断入手。转眼间,宋经典陪伴已经三个月了,有车的美好时光。有了宋经典,更快更容易到达目的地。宋经典的动力表现确实出乎意料,给车带来一些好感。驾驶时可以感受到宋经典的底盘扎实稳定,即使高速行驶,车身也很稳定。对于长途来说,宋经典有着不错的安慰。所以发现宋经的质量也是不错的。

  • 烟酒为何是男性不育症的帮凶(烟酒对男性功能的影响)

    法国一位医生经过调查后认为,引起阳萎的动脉供血不全,主要是因为抽烟和饮食不当引起的。他认为这些病人戒烟有助于恢复正常的性功能。孕妇吸烟或被动吸烟者,低体重儿发生率高,吸烟孕妇低体重儿出生率是非吸烟孕妇的2倍。英国研究人员最近指出,酗酒可损害生殖内分泌功能,加快睾酮代谢,造成雌激素相对增多,由于有活性的雄激素减少睾丸萎缩,可出现阳萎。

  • 冷却塔噪声治理措施(如何治理设备噪声)

    随着冷却塔的应用越来越广泛,冷却塔噪声成为了现阶段城市环境污染中较为突出的问题,急需治理。冷却塔噪声源分析冷却塔噪声的产生与其结构形式相关,最常见的冷却塔有通风冷却塔和机械通风冷却塔。冷却塔噪声治理措施风口消声器在排风口安装消声装置。冷却塔噪声治理相对容易,但要注意隔音治理同时避免影响散热性能的发挥,虽然消声装置和消声百叶可以大幅降噪,但要合理设计,及设计时要综合考虑散热性能和动力性能。

  • 华为怎么查手机型号(华为手机型号怎么看)

    接下来我们就一起去了解一下吧!华为怎么查手机型号HUAWEIP50Pro为例:打开华为手机的设置系统,并在里面往下翻动。在最底端找到关于手机的相关设置后,点击进入到相关页面。进入后,就会看到本手机的型号、版本号以及其他的信息了。

  • 猫屎咖啡有几个口味(来认真地科普一下)

    猫屎咖啡产量非常少,亦因此特别昂贵,在售卖地更是少之又少。麝猫与果子狸同属灵猫科动物,因此也遭到大面积扑杀。最终,真正的麝猫咖啡,还是产量非常有限的。这种想法不能说绝对错误,因为基本原理都是利用动物肠道发酵咖啡豆,称为“体内发酵法”。结论综上所述,猫屎咖啡的确带有独特的风味,且“物以稀为贵”,但充其量只能算作一种“猎奇品种”。

  • word文档中输入字体与其它不一样 word文档中输入字体与其它不一样

    这是Word的一个bug所致。仿宋分为仿宋体和仿宋_GB2312,前者是低版本,后者是07以上才有的高版本。

  • 艋舺怎么念(艋舺怎么读)

    下面内容希望能帮助到你,我们来一起看看吧!艋舺怎么念艋舺的拼音是měngxiá。艋舺是个汉语词语,原指小船,后引申为小船聚集的地方。艋舺,又称“文甲”、“蟒甲”、“蚊甲”、“莽葛”,是台湾少数民族平埔族凯达格兰语“Moungar/Mankah”的译音。

  • 十二生肖对应的文玩(什么生肖对应什么文玩)

    属羊就佩戴海南黄花梨是最合适的了,因为海黄那丰富多变的纹理,能恰好的体现出羊的一种多变的性格,而且海黄能使属羊的人运势上涨,一路顺顺利利。属猪的就佩戴小叶紫檀,因为小叶紫檀就是给人一种沉稳大气的感觉,猪虽然是憨厚的,可是属猪的品质可是很高的,佩戴小叶紫檀可以让自己的运势一涨再涨。

  • 在腌制肉类的时候加柠檬(在腌制肉类的时候)

    两个选项分别是A、让肉更嫩;B、去除酸味。两个选项分别是A、有风险,最好不要;B、当然行,趁新鲜。还可以加入少量白砂糖,缓冲咸味,使肉具有特殊的鲜美味,对腌肉的质量起到良好的效果。这个问题的答案和分析,希望对您有帮助。答对即可获得一份180g饲料,小鸡又有免费的饲料吃了,每天还能够增长知识,同时还做了慈善,赶紧来玩吧。