1. why

为什么要拦截传递给 mapper 文件的参数对象呢?因为要对指定属性设置默认值。如何拦截传递给 mapper 文件的参数对象可以参考《使用(org.apache.ibatis.plugin.Interceptor)拦截器实现全局参数注入》这里我们只贴出处理拦截对象的核心方法。

2. code

既然是核心方法,无关的@Override方法不再贴出, 参数对象是Map类型的不是重点,这里主要看一下封装对象借助反射机制通过 getter 和 setter 方法获取和设置指定属性值的操作。

public class SchemaInterceptor implements Interceptor {/*** mapper.xml 使用SCHEMA时的参数名称*/private static final String SCHEMA = "schemaName";/*** 设置默认的schema*/private String schema = "public";/*** 拦截到的动态SQL*/private Set<Integer> sourceStorage = new HashSet<>();@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object[] args = invocation.getArgs();MappedStatement mappedStatement = (MappedStatement) args[0];SqlSource sqlSource = mappedStatement.getSqlSource();// 只拦截动态SQLif (sqlSource instanceof DynamicSqlSource) {// 获取到sqlNode对象Field field = DynamicSqlSource.class.getDeclaredField("rootSqlNode");field.setAccessible(true);SqlNode sqlNode = (SqlNode) field.get(sqlSource);Object argParameter = args[1];// 获取传递给 mapper 的参数对象if (!sourceStorage.contains(sqlSource.hashCode()) && argParameter != null) {if (argParameter instanceof HashMap) {// 处理 map 类型的参数Map<String, Object> argMap = (Map<String, Object>) argParameter;// 判断是否传递 schemaName或schema 如果已经传递则使用用户传递的值 否则使用默认值String schemaNameStr = "schemaName", schemaStr = "schema";if (StringUtils.isEmpty(MapUtils.getString(argMap, schemaNameStr)) && StringUtils.isEmpty(MapUtils.getString(argMap, schemaStr))) {SqlNode proxyNode = proxyNode(sqlNode);field.set(sqlSource, proxyNode);}} else {// 处理封装成请求对象类型的参数Class<?> clz = argParameter.getClass();// 获取实体类的所有属性Field[] fields = clz.getDeclaredFields();for (Field f : fields) {String fieldName = f.getName();Class<?> fieldType = f.getType();// 处理 schemaName 属性if (SCHEMA.equals(fieldName)) {// 获取 schemaName 属性的 getter 方法String methodName = getMethodName(fieldName);String getName = "get" + methodName;Method getFieldValue = clz.getMethod(getName);String val = (String) getFieldValue.invoke(argParameter);// schemaName 属性值为空则使用默认值if (StringUtils.isBlank(val)) {String setName = "set" + methodName;Method setFieldValue = clz.getMethod(setName, fieldType);setFieldValue.invoke(argParameter, schema);}}}}sourceStorage.add(sqlSource.hashCode());}}return invocation.proceed();}/*** 通过动态代理对象 添加schema参数** @param sqlNode SQL节点* @return SqlNode*/private SqlNode proxyNode(SqlNode sqlNode) {return (SqlNode) Proxy.newProxyInstance(sqlNode.getClass().getClassLoader(),new Class[]{SqlNode.class}, new SqlNodeInvocationHandler(sqlNode));}private class SqlNodeInvocationHandler implements InvocationHandler {private SqlNode target;SqlNodeInvocationHandler(SqlNode target) {super();this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {DynamicContext context = (DynamicContext) args[0];setSchema(schema);context.getBindings().put(SCHEMA, schema);return method.invoke(target, args);}}/*** 给schema 添加.** @param schema schemaName*/private void setSchema(String schema) {String pointStr = ".";if (StringUtils.isNotBlank(schema)) {if (!schema.endsWith(pointStr)) {schema += pointStr;}}this.schema = schema;}/*** 将首字母变成大写** @param fieldName 字段名称* @return 首字母大写的字段名称*/private static String getMethodName(String fieldName) {byte[] items = fieldName.getBytes();items[0] = (byte) ((char) items[0] - 'a' + 'A');return new String(items);}

方法解析

拦截到的参数对象是 Object 类型,可以通过方法名获取其 getter 和 setter 方法,使用获取到的方法执行即可获取或设置指定的属性值:

        Object argParameter = args[1];// 处理封装成请求对象类型的参数Class<?> clz = argParameter.getClass();// 获取实体类的所有属性Field[] fields = clz.getDeclaredFields();for (Field f : fields) {// 属性的名称String fieldName = f.getName();// 属性的类型Class<?> fieldType = f.getType();// 处理 schemaName 属性if (SCHEMA.equals(fieldName)) {// 获取 schemaName 属性的 getter 方法String methodName = getMethodName(fieldName);// 方法名String getName = "get" + methodName;// 获取到的 getter 方法Method getFieldValue = clz.getMethod("get" + methodName);// 执行 getter 方法String val = (String) getFieldValue.invoke(argParameter);// schemaName 属性值为空则使用默认值if (StringUtils.isBlank(val)) {// 方法名String setName = "set" + methodName;// 获取 setter 方法 需要传递当前属性的类型Method setFieldValue = clz.getMethod(setName, fieldType);// 执行 setter 方法setFieldValue.invoke(argParameter, schema);}}}

将首字母大写:

    /*** 将首字母变成大写** @param fieldName 字段名称【字段的第一位必须是小写的字母】* @return 首字母大写的字段名称*/private static String getMethodName(String fieldName) {byte[] items = fieldName.getBytes();items[0] = (byte) ((char) items[0] - 'a' + 'A');return new String(items);}

【Java代码】反射机制处理传递给mapper文件的非Map类型参数对象(指定属性为空则设置默认值)相关推荐

  1. 搞懂Java的反射机制

    搞懂Java的反射机制 1.什么是反射? java的反射机制是指可以在运行状态下获取类和对象的所有属性和方法. 2.反射的作用? 1.在运行时获取一个类/对象的成员变量和方法 2.在运行时创建一个类的 ...

  2. Java的反射机制,内含超简单实例代码(搞懂反射,这一篇就够了)

    一 首先来说说反射机制的概念: 程序在运行时, 对于类来说,可以知道该类的任意属性和方法: 对于对象来说,可以调用该对象的任意方法和属性: 就以上这种动态获取信息的机制就称为Java的反射机制 彻底了 ...

  3. android中通过java的反射机制获取U盘名称

    在android项目中实现Windos一样的U盘效果,需监听两个U盘的插入和拔出状态,并屏蔽本地存储,使用U盘来下载和上传文件: 在编辑代码中碰到一个问题:无法获取插入U盘的名称,于是通过java的反 ...

  4. Java的反射机制 工厂模式综合讲解【转载自51CTO】

    2019独角兽企业重金招聘Python工程师标准>>> Java的反射机制 工厂模式综合讲解 1.什么叫反射 Java.lang.reflect包下 正常情况下我们可以通过类实例化一 ...

  5. java xml 反射_Java 读取XML文件以及Java 的反射机制实现

    Java 读取XML文件以及Java 的反射机制实现 代码部分 import java.io.File; import javax.xml.parsers.DocumentBuilder; impor ...

  6. Java编程:Java的反射机制中的 getComponentType() 方法

    转载自  Java编程:Java的反射机制中的 getComponentType() 方法 Java 中所有的类都继承自 Object,数组本身也是一个 Class,如果我们能够得到数据的 Class ...

  7. java原理—反射机制

    http://www.cnblogs.com/forlina/archive/2011/06/21/2085849.html 一.什么是反射: 反射的概念是由Smith在1982年首次提出的,主要是指 ...

  8. 学习:java原理—反射机制

    一.什么是反射: 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提 出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序 ...

  9. Java基础-反射机制

    目录 1.反射机制概述 2.获取class的三种方式 2.1.Class.forName()方式 2.2.obj.getClass()方式 2.3..class方式 3.通过反射实例化对象 4.通过读 ...

最新文章

  1. 导入Excel和CSV文件
  2. python代码删掉了几行怎么撤回_78行Python代码实现现微信撤回消息功能
  3. XSLT2.0---多文件输出
  4. SQL Server 创建表
  5. [转载] Flask+Celery+Redis简单操作
  6. java 基本理论知识点
  7. 一个迷茫的 大学生自学Linux的开始
  8. java游戏精灵薇薇安_薇薇安和骑士召唤师使用技巧
  9. c语言流程图文本,c语言流程图
  10. SQL——连接字符串常用函数
  11. 未能连接到驱动人生服务器,更新显卡驱动提示“无法连接到Nvidia”,驱动人生来解决。...
  12. 打造全功能的NERO
  13. 在IntelliJ IDEA下编辑jspx文件(转)
  14. Centos 7.6 挂载硬盘
  15. 《伟大是熬出来的》冯仑与年轻人闲话人生之一
  16. 【个人亲历】上海市人才引进落户最详细的流程记录说明
  17. 实验三+070+胡阳洋
  18. Js模拟重力场【Js动效】
  19. 二进制,八进制,十进制,十六进制转换算法
  20. 爱奇艺知识播放体验优化的探索和实践

热门文章

  1. python3 内置函数详解
  2. BI Content、Metadata Repository
  3. java成果_JAVA WEB期末项目第二阶段成果
  4. 树莓派命令连接wifi_树莓派连接无线网wifi配置方法
  5. python高阶函数心得体会_Python高阶函数使用总结
  6. android服务器概念,Android_tv_metro
  7. 四川大学计算机网络_四川大学20考研情况
  8. java webpack_webpack将对象暴露为全局
  9. 英语在线听力翻译器_仁爱版初一英语免费听力训练电子教程
  10. 十七、爬虫实战,多线程抓取大搜网新车的数据