【Java代码】反射机制处理传递给mapper文件的非Map类型参数对象(指定属性为空则设置默认值)
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类型参数对象(指定属性为空则设置默认值)相关推荐
- 搞懂Java的反射机制
搞懂Java的反射机制 1.什么是反射? java的反射机制是指可以在运行状态下获取类和对象的所有属性和方法. 2.反射的作用? 1.在运行时获取一个类/对象的成员变量和方法 2.在运行时创建一个类的 ...
- Java的反射机制,内含超简单实例代码(搞懂反射,这一篇就够了)
一 首先来说说反射机制的概念: 程序在运行时, 对于类来说,可以知道该类的任意属性和方法: 对于对象来说,可以调用该对象的任意方法和属性: 就以上这种动态获取信息的机制就称为Java的反射机制 彻底了 ...
- android中通过java的反射机制获取U盘名称
在android项目中实现Windos一样的U盘效果,需监听两个U盘的插入和拔出状态,并屏蔽本地存储,使用U盘来下载和上传文件: 在编辑代码中碰到一个问题:无法获取插入U盘的名称,于是通过java的反 ...
- Java的反射机制 工厂模式综合讲解【转载自51CTO】
2019独角兽企业重金招聘Python工程师标准>>> Java的反射机制 工厂模式综合讲解 1.什么叫反射 Java.lang.reflect包下 正常情况下我们可以通过类实例化一 ...
- java xml 反射_Java 读取XML文件以及Java 的反射机制实现
Java 读取XML文件以及Java 的反射机制实现 代码部分 import java.io.File; import javax.xml.parsers.DocumentBuilder; impor ...
- Java编程:Java的反射机制中的 getComponentType() 方法
转载自 Java编程:Java的反射机制中的 getComponentType() 方法 Java 中所有的类都继承自 Object,数组本身也是一个 Class,如果我们能够得到数据的 Class ...
- java原理—反射机制
http://www.cnblogs.com/forlina/archive/2011/06/21/2085849.html 一.什么是反射: 反射的概念是由Smith在1982年首次提出的,主要是指 ...
- 学习:java原理—反射机制
一.什么是反射: 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提 出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序 ...
- Java基础-反射机制
目录 1.反射机制概述 2.获取class的三种方式 2.1.Class.forName()方式 2.2.obj.getClass()方式 2.3..class方式 3.通过反射实例化对象 4.通过读 ...
最新文章
- 导入Excel和CSV文件
- python代码删掉了几行怎么撤回_78行Python代码实现现微信撤回消息功能
- XSLT2.0---多文件输出
- SQL Server 创建表
- [转载] Flask+Celery+Redis简单操作
- java 基本理论知识点
- 一个迷茫的 大学生自学Linux的开始
- java游戏精灵薇薇安_薇薇安和骑士召唤师使用技巧
- c语言流程图文本,c语言流程图
- SQL——连接字符串常用函数
- 未能连接到驱动人生服务器,更新显卡驱动提示“无法连接到Nvidia”,驱动人生来解决。...
- 打造全功能的NERO
- 在IntelliJ IDEA下编辑jspx文件(转)
- Centos 7.6 挂载硬盘
- 《伟大是熬出来的》冯仑与年轻人闲话人生之一
- 【个人亲历】上海市人才引进落户最详细的流程记录说明
- 实验三+070+胡阳洋
- Js模拟重力场【Js动效】
- 二进制,八进制,十进制,十六进制转换算法
- 爱奇艺知识播放体验优化的探索和实践
热门文章
- python3 内置函数详解
- BI Content、Metadata Repository
- java成果_JAVA WEB期末项目第二阶段成果
- 树莓派命令连接wifi_树莓派连接无线网wifi配置方法
- python高阶函数心得体会_Python高阶函数使用总结
- android服务器概念,Android_tv_metro
- 四川大学计算机网络_四川大学20考研情况
- java webpack_webpack将对象暴露为全局
- 英语在线听力翻译器_仁爱版初一英语免费听力训练电子教程
- 十七、爬虫实战,多线程抓取大搜网新车的数据