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

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

转载自公众号:日拱一兵

,
    推荐阅读
  • 哪个颜色口罩防晒(这个颜色的口罩最防晒)

    专家使用专业光谱仪对白色、蓝色、黑色三种医用外科口罩进行了紫外线屏蔽能力检测,结果发现白色、蓝色、黑色口罩对紫外线的屏蔽能力,分别是73%、93%和99%。如果在风险程度较高的环境中,或是空间小,人员密集的情况下,可以选择医用外科口罩。

  • 车载冰箱千万不要家用吗(车载冰箱好用不)

    YOKOHAMA优科豪马根据选用优科豪马自主开发的“低油耗结构技术性”,进而完成低油耗性能。现阶段市场上大部分市场销售的车载冰箱为车家多用型,并出示了车截线和家用线应家用电压转换器。由于这类冰箱能够自动检索电瓶电压,当车辆蓄电瓶电量不足时,便会自动调节冰箱頻率或待机。

  • 最小的手机(世界最小手机什么样)

    2.比如以色列Modu公司便在最小的手机上大做文章,推出了重量仅在40克左右的全球最小手机,并吸引不少眼球的关注。4.实际上,Modu的这款全球最小手机并非第一次亮相,该机在过去两年的时间内经常会出现在一些展会上,并以轻巧到极致的特色而为人瞩目。

  • 入门学五行(轻松学五行)

    以《易经》来说,站在中国学术发展史的立场看,五行和《易经》根本没有关系。可是现在要了解《易经》的法则,在占卜方面,则有其密切的关系。近代以来,一般怀疑中国文化的学者,认为五行是汉朝、至少是秦汉以后人所假托,这是研究中国文化发展史的立场的一种看法。领导人对部下亦是如此。一个人的失败,往往失败在最信任、最亲近的人身上。东方木,植物易生发,早受阳光热能。

  • 千年武则天(好莱坞将拍科幻版武则天)

    9月23日,有媒体报道称,加拿大华裔作家赵希然的畅销小说《铁寡妇》将被好莱坞拍成电影,Picturestart媒体公司已经获得改编权,将讲述一个“科幻版武则天”的故事,官方还放出了机甲设计图。此消息一出,引发网友们的震惊和热议。18岁的主角则天为了暗杀导致姐妹死亡的男性王牌驾驶员,自愿成为这个可以被抛弃的“妾”驾驶员,以出乎意料的方式成功复仇。虽然则天被当局认定为是‘威胁’,但事实上她可能是世界唯一的救星。

  • 寂寞的孤独的网名男生(孤独的男生网名大全)

    15、世界太假而我又太傻16、你不懂海的哭泣17、孤獨比快樂更真實18、准备遗忘19、感情废物20、悲伤的季节21、往昔已逝22、格式化、哭泣23、仅剩的微笑24、菰萙难眠25、以孤独为友

  • 宝宝清蒸鳕鱼的做法(宝宝吃清蒸鳕鱼做法)

    尤其是对于宝宝来说,没有细小的鱼刺,更利于宝宝食用。清蒸鳕鱼的做法宝宝吃家有萌娃初长成,奈何淘气娃嘴刁得很!清蒸鳕鱼的做法宝宝吃主料:鳕鱼一块、鸡蛋两个辅料:生姜适量、盐适量、料酒少量、橄榄油适量、葱花少量做法:1、首先宝爸宝妈可以先把冰冻鳕鱼提前两个小时从冰箱拿出,然后清洗干净。

  • 7天失火40多次(女子回家吓坏了)

    7天失火40多次来源:杭州日报外出9天煤气忘记关9天!女子表示,出门那天早上炸了牙签肉,锅里有一锅油,当时自己右手端着盘子,左手关的燃气灶,拧反了开关,所以燃气灶一直是小火的状态,没有关闭。

  • 锦州市特色美食(美味辽宁等您来)

    锦州旅游景点众多,不少风景名胜人们耳熟能详,当然,特色美食也是必不可少的,今天小编就来分享辽宁锦州最有名的6大特色美食,你都吃过吗?而学生时代,任何一个人都抵挡不住美食的诱惑,尤其在锦州,还是烧烤!

  • 头雁怎么飞到国外过冬(加拿大黑雁冬天还飞往南方过冬吗)

    2020年7月,一群加拿大黑雁聚集在加拿大不列颠哥伦比亚省鹿湖公园的运动场上。如今,这种重达4公斤的鸟类遍布加拿大的每个省和美国大陆的每一个州,其数量还在继续增加。据加拿大野生动物管理局估计,这一数字一直增加到700万。如今,这一比例已超过60%。烦人的加拿大黑雁在大多数情况下,非迁徙的加拿大黑雁数量激增并未对当地野生动物和生态系统造成压力。2019年,其中一对加拿大黑雁将巢筑于国家地理学会的华盛顿特区总部。