上代码:

  1. package tk.mybatis.plugin;
  2.  
  3. import org.apache.ibatis.executor.ErrorContext;
  4. import org.apache.ibatis.executor.parameter.ParameterHandler;
  5. import org.apache.ibatis.mapping.BoundSql;
  6. import org.apache.ibatis.mapping.MappedStatement;
  7. import org.apache.ibatis.mapping.ParameterMapping;
  8. import org.apache.ibatis.mapping.ParameterMode;
  9. import org.apache.ibatis.plugin.*;
  10. import org.apache.ibatis.reflection.MetaObject;
  11. import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
  12. import org.apache.ibatis.session.Configuration;
  13. import org.apache.ibatis.type.JdbcType;
  14. import org.apache.ibatis.type.TypeHandler;
  15. import org.apache.ibatis.type.TypeHandlerRegistry;
  16.  
  17. import java.lang.reflect.Field;
  18. import java.lang.reflect.Method;
  19. import java.math.BigDecimal;
  20. import java.math.BigInteger;
  21. import java.sql.PreparedStatement;
  22. import java.util.*;
  23.  
  24. /**
  25. * JdbcTypeInterceptor - 运行时自动添加 jdbcType 属性
  26. */
  27. @Intercepts({
  28. @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
  29. })
  30. public class JdbcTypeInterceptor implements Interceptor {
  31.  
  32. private static Set<String> methodSet = new HashSet<>();
  33. private static Map<Class<?>, JdbcType> typeMap = new HashMap<>();
  34. private static final Field mappedStatementField;
  35. private static final Field boundSqlField;
  36.  
  37. static {
  38. try {
  39. mappedStatementField = DefaultParameterHandler.class.getDeclaredField("mappedStatement");
  40. mappedStatementField.setAccessible(true);
  41.  
  42. } catch (NoSuchFieldException e) {
  43. throw new RuntimeException("获取 DefaultParameterHandler 字段 mappedStatement 时出错", e);
  44. }
  45. try {
  46. boundSqlField = DefaultParameterHandler.class.getDeclaredField("boundSql");
  47. boundSqlField.setAccessible(true);
  48. } catch (NoSuchFieldException e) {
  49. throw new RuntimeException("获取 DefaultParameterHandler 字段 boundSql 时出错", e);
  50. }
  51. //设置默认的方法,是用 Mapper 所有方法
  52. Method[] methods = tk.mybatis.mapper.common.Mapper.class.getMethods();
  53. for (Method method : methods) {
  54. methodSet.add(method.getName());
  55. }
  56. //设置默认的类型转换,参考 TypeHandlerRegistry
  57. register(Boolean.class, JdbcType.BOOLEAN);
  58. register(boolean.class, JdbcType.BOOLEAN);
  59.  
  60. register(Byte.class, JdbcType.TINYINT);
  61. register(byte.class, JdbcType.TINYINT);
  62.  
  63. register(Short.class, JdbcType.SMALLINT);
  64. register(short.class, JdbcType.SMALLINT);
  65.  
  66. register(Integer.class, JdbcType.INTEGER);
  67. register(int.class, JdbcType.INTEGER);
  68.  
  69. register(Long.class, JdbcType.BIGINT);
  70. register(long.class, JdbcType.BIGINT);
  71.  
  72. register(Float.class, JdbcType.FLOAT);
  73. register(float.class, JdbcType.FLOAT);
  74.  
  75. register(Double.class, JdbcType.DOUBLE);
  76. register(double.class, JdbcType.DOUBLE);
  77.  
  78. register(String.class, JdbcType.VARCHAR);
  79.  
  80. register(BigDecimal.class, JdbcType.DECIMAL);
  81. register(BigInteger.class, JdbcType.DECIMAL);
  82.  
  83. register(Byte[].class, JdbcType.BLOB);
  84. register(byte[].class, JdbcType.BLOB);
  85.  
  86. register(Date.class, JdbcType.DATE);
  87. register(java.sql.Date.class, JdbcType.DATE);
  88. register(java.sql.Time.class, JdbcType.TIME);
  89. register(java.sql.Timestamp.class, JdbcType.TIMESTAMP);
  90.  
  91. register(Character.class, JdbcType.CHAR);
  92. register(char.class, JdbcType.CHAR);
  93. }
  94.  
  95. @Override
  96. public Object intercept(Invocation invocation) throws Throwable {
  97. //这里不考虑有多个基于该方法插件时的情况
  98. Object handler = invocation.getTarget();
  99. MappedStatement mappedStatement = (MappedStatement) mappedStatementField.get(handler);
  100. //一旦配置了 methods,就只对配置的方法进行处理
  101. if (handler instanceof DefaultParameterHandler) {
  102. if (methodSet.size() > 0) {
  103. String msId = mappedStatement.getId();
  104. String methodName = msId.substring(msId.lastIndexOf(".") + 1);
  105. if (!methodSet.contains(methodName)) {
  106. return invocation.proceed();
  107. }
  108. }
  109. //获取基本变量信息
  110. BoundSql boundSql = (BoundSql) boundSqlField.get(handler);
  111. Object parameterObject = ((DefaultParameterHandler) handler).getParameterObject();
  112. Configuration configuration = mappedStatement.getConfiguration();
  113. TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
  114. PreparedStatement ps = (PreparedStatement) invocation.getArgs()[0];
  115. //原 DefaultParameterHandler 逻辑
  116. ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  117. List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  118. if (parameterMappings != null) {
  119. for (int i = 0; i < parameterMappings.size(); i++) {
  120. ParameterMapping parameterMapping = parameterMappings.get(i);
  121. if (parameterMapping.getMode() != ParameterMode.OUT) {
  122. Object value;
  123. String propertyName = parameterMapping.getProperty();
  124. if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
  125. value = boundSql.getAdditionalParameter(propertyName);
  126. } else if (parameterObject == null) {
  127. value = null;
  128. } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
  129. value = parameterObject;
  130. } else {
  131. MetaObject metaObject = configuration.newMetaObject(parameterObject);
  132. value = metaObject.getValue(propertyName);
  133. }
  134. TypeHandler typeHandler = parameterMapping.getTypeHandler();
  135. JdbcType jdbcType = parameterMapping.getJdbcType();
  136. if (value == null && jdbcType == null) {
  137. if (parameterMapping.getJavaType() != null && typeMap.containsKey(parameterMapping.getJavaType())) {
  138. jdbcType = typeMap.get(parameterMapping.getJavaType());
  139. } else {
  140. jdbcType = configuration.getJdbcTypeForNull();
  141. }
  142. }
  143. typeHandler.setParameter(ps, i + 1, value, jdbcType);
  144. }
  145. }
  146. }
  147. return null;
  148. }
  149. return invocation.proceed();
  150. }
  151.  
  152. @Override
  153. public Object plugin(Object target) {
  154. return Plugin.wrap(target, this);
  155. }
  156.  
  157. private boolean isNotEmpty(String str) {
  158. return str != null && str.length() > 0;
  159. }
  160.  
  161. @Override
  162. public void setProperties(Properties properties) {
  163. String methodStr = properties.getProperty("methods");
  164. if (isNotEmpty(methodStr)) {
  165. //处理所有方法
  166. if (methodStr.equalsIgnoreCase("ALL")) {
  167. methodSet.clear();
  168. } else {
  169. String[] methods = methodStr.split(",");
  170. for (String method : methods) {
  171. methodSet.add(method);
  172. }
  173. }
  174. }
  175. //手动配置
  176. String typeMapStr = properties.getProperty("typeMaps");
  177. if (isNotEmpty(typeMapStr)) {
  178. String[] typeMaps = typeMapStr.split(",");
  179. for (String typeMap : typeMaps) {
  180. String[] kvs = typeMap.split(":");
  181. if (kvs.length == 2) {
  182. register(kvs[0], kvs[1]);
  183. }
  184. }
  185. }
  186. }
  187.  
  188. public static void register(String type, String jdbcType) {
  189. try {
  190. typeMap.put(Class.forName(type), JdbcType.valueOf(jdbcType));
  191. } catch (ClassNotFoundException e) {
  192. throw new RuntimeException("配置 typeMaps 时出错!", e);
  193. }
  194. }
  195.  
  196. public static void register(Class<?> type, JdbcType jdbcType) {
  197. typeMap.put(type, jdbcType);
  198. }
  199. }

在springboot中使用:

  1. @Bean
  2. public Interceptor getInterceptor(){
  3. return new JdbcTypeInterceptor();
  4. }

它的好处,就是在运行mybatis动态sql的时候给属性添加jdbcType

mybatis jdbctype参考:https://www.cnblogs.com/pianai-shu/p/6349183.html

mybatis JdbcTypeInterceptor - 运行时自动添加 jdbcType 属性的更多相关文章

  1. (转载)让XCode运行时自动更新资源

    转自http://goldlion.blog.51cto.com/4127613/1351616 用过XCode的人都知道,XCode有一个臭名昭著的bug——除非你修改了源代码造成了重新编译,否则游 ...

  2. iOS开发——运行时OC篇&使用运行时获取系统的属性:使用自己的手势修改系统自带的手势

    使用运行时获取系统的属性:使用自己的手势修改系统自带的手势 有的时候我需要实现一个功能,但是没有想到很好的方法或者想到了方法只是那个方法实现起来太麻烦,一或者确实为了装逼,我们就会想到iOS开发中最牛 ...

  3. Visual studio 创建文件时自动添加备注

    Visual studio 创建文件时自动添加备注 描述 要求每回添加一个类,普通类或单元测试类文件头自动添加备注, 比如:Copyright, FileName, Author and so on. ...

  4. SpringBoot运行时动态添加数据源

    此方案适用于解决springboot项目运行时动态添加数据源,非静态切换多数据源!!! 一.多数据源应用场景: 1.配置文件配置多数据源,如默认数据源:master,数据源1:salve1...,运行 ...

  5. WordPress发布文章/页面时自动添加默认的自定义字段

    如果你每篇文章或页面都需要插入同一个自定义字段和值,可以考虑在WordPress发布文章/页面时,自动添加默认的自定义字段.将下面的代码添加到当前主题的 functions.php 即可: 1 2 3 ...

  6. swift3.0 运行时获取类的属性

    //定义Person类 class Person: NSObject { var name: String? //注意这里基本数据类型我定义的是必选属性 var age: Int = override ...

  7. Pycharm新建文件时自动添加基础信息

    位置:File->settings->Editor->File and Code Templates->Python Script 添加以下代码: #!/usr/bin/env ...

  8. vs install 安装时自动添加注册表

    思路:使用自定义 解决方案添加类库项目 添加安装程序类 随后右键查看代码 在构造函数添加事件 同时完成这个事件,在此事件中根据需要添加我们需要的内容,此处为添加注册表,并根据安装目录添加url pro ...

  9. 蚂蚁分类信息商家发布文章、商品外链及远程图片自动添加nofollow属性

    蚂蚁商户发布文章.商品是可以添加外链或者直接用外部图片,但是这对分类网站运营不利. 所以要对外链进行过滤,演示网站保洁,蚂蚁分类的源码. 下面就说下怎么处理自动给外链自动加上nofollow属性. 1 ...

随机推荐

  1. _编程语言_C++_宏定义#define 和 常量const 的区别

    C++中有两种定义常量的方式:#define预处理和const关键字 #define 预处理指令 #include <iostream> using namespace std; #def ...

  2. mysql 中 datetime和 timestamp的区别

    DATETIME日期和时间的组合.支持的范围是'1000-01-01 00:00:00'到'9999-12-31 23:59:59'.MySQL以'YYYY-MM-DD HH:MM:SS'格式显示DA ...

  3. Codeforces821A Okabe and Future Gadget Laboratory 2017-06-28 14:55 80人阅读 评论(0) 收藏

    A. Okabe and Future Gadget Laboratory time limit per test 2 seconds memory limit per test 256 megaby ...

  4. 类变量的初始化时机(摘录自java突破程序员基本功德16课)

    先看书本的一个例子,代码如下: public class Price { final static Price INSTANCE=new Price(2.8); static double initP ...

  5. kafka eagel的使用

    sql语句eq: select * from "ke_test_topic" where "partition" in (0,1,2) limit 100 官网 ...

  6. vdscode连接git服务器(以码云为例)

    准备工作:先下载并安装git客户端 1.在码云或者github上新建项目,获得新建项目的地址,得到一个类似:https://gitee.com/zhangshitongsky/vueTest.git ...

  7. HTML超级链接详细讲解

    超级链接是网站中使用比较频繁的HTML元素,因为网站的各种页面都是由超级链接串接而成,超级链接完成了页面之间的跳转.超级链接是浏览者和服务器的交互的主要手段,在后面的技术中会逐步深化学习. —  注意 ...

  8. DDD Code First 迁移数据实现EF CORE的软删除,值对象迁移配置

    感谢Jeffcky大佬的博客: EntityFramework Core 2.0全局过滤 (HasQueryFilter) https://www.cnblogs.com/CreateMyself/p ...

  9. [ZJOI2010]基站选址(线段树优化dp)

    坑待填. \(Code\ Below:\) #include <bits/stdc++.h> #define lson (rt<<1) #define rson (rt< ...

  10. Django(ORM查询2)

    day70 ORM训练专题 :http://www.cnblogs.com/liwenzhou/articles/8337352.html 内容回顾     1. ORM         1. ORM ...