LastSqlInterceptor.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package com.welampiot.configuration;
  2. import org.apache.commons.collections4.CollectionUtils;
  3. import org.apache.ibatis.executor.statement.StatementHandler;
  4. import org.apache.ibatis.mapping.BoundSql;
  5. import org.apache.ibatis.mapping.MappedStatement;
  6. import org.apache.ibatis.mapping.ParameterMapping;
  7. import org.apache.ibatis.plugin.*;
  8. import org.apache.ibatis.reflection.MetaObject;
  9. import org.apache.ibatis.reflection.SystemMetaObject;
  10. import org.apache.ibatis.session.Configuration;
  11. import org.apache.ibatis.session.ResultHandler;
  12. import org.apache.ibatis.type.TypeHandlerRegistry;
  13. import org.springframework.stereotype.Component;
  14. import java.sql.Statement;
  15. import java.text.DateFormat;
  16. import java.util.Date;
  17. import java.util.List;
  18. import java.util.Locale;
  19. import java.util.Properties;
  20. import java.util.regex.Matcher;
  21. @Intercepts({
  22. @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
  23. @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
  24. @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
  25. })
  26. @Component
  27. public class LastSqlInterceptor implements Interceptor {
  28. public String sqlContent;
  29. //获取sql语句
  30. @Override
  31. public Object intercept(Invocation invocation) throws Throwable {
  32. // 耗时开始时间
  33. long startTime = System.currentTimeMillis();
  34. // 获取 StatementHandler ,默认是 RoutingStatementHandler
  35. StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
  36. // 获取 StatementHandler 包装类
  37. MetaObject metaObjectHandler = SystemMetaObject.forObject(statementHandler);
  38. // 获取查询接口映射的相关信息
  39. MappedStatement mappedStatement = (MappedStatement) metaObjectHandler.getValue("delegate.mappedStatement");
  40. // 获取请求时的参数
  41. Object parameterObject = statementHandler.getParameterHandler().getParameterObject();
  42. // 获取sql
  43. String sql = showSql(mappedStatement.getConfiguration(), mappedStatement.getBoundSql(parameterObject));
  44. // 获取执行sql方法
  45. String sqlId = mappedStatement.getId();
  46. // 执行sql
  47. Object result = invocation.proceed();
  48. // 计算总耗时
  49. long cost = System.currentTimeMillis() - startTime;
  50. System.out.println(" ======> SQL方法 : {} , 总耗时 : {}毫秒, SQL语句 : {} "+ sqlId+"----"+cost+"----"+sql);
  51. this.sqlContent = sql;
  52. return result;
  53. }
  54. /**
  55. * 拦截器对应的封装原始对象的方法,获取代理对象
  56. */
  57. @Override
  58. public Object plugin(Object target) {
  59. return (target instanceof StatementHandler) ? Plugin.wrap(target, this) : target;
  60. }
  61. /**
  62. * 设置注册拦截器时设定的属性,设置代理对象的参数
  63. */
  64. @Override
  65. public void setProperties(Properties properties) {
  66. }
  67. private static String showSql(Configuration configuration, BoundSql boundSql) {
  68. // 获取参数
  69. Object parameterObject = boundSql.getParameterObject();
  70. List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  71. // sql语句中多个空格都用一个空格代替
  72. String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
  73. if (CollectionUtils.isNotEmpty(parameterMappings) && parameterObject != null) {
  74. // 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换
  75. TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
  76. // 如果根据parameterObject.getClass()可以找到对应的类型,则替换
  77. if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
  78. sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(parameterObject)));
  79. } else {
  80. // MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作
  81. MetaObject metaObject = configuration.newMetaObject(parameterObject);
  82. for (ParameterMapping parameterMapping : parameterMappings) {
  83. String propertyName = parameterMapping.getProperty();
  84. if (metaObject.hasGetter(propertyName)) {
  85. Object obj = metaObject.getValue(propertyName);
  86. sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));
  87. } else if (boundSql.hasAdditionalParameter(propertyName)) {
  88. // 该分支是动态sql
  89. Object obj = boundSql.getAdditionalParameter(propertyName);
  90. sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));
  91. } else {
  92. // 打印出缺失,提醒该参数缺失并防止错位
  93. sql = sql.replaceFirst("\\?", "缺失");
  94. }
  95. }
  96. }
  97. }
  98. return sql;
  99. }
  100. private static String getParameterValue(Object obj) {
  101. String value;
  102. if (obj instanceof String) {
  103. value = "'" + obj.toString() + "'";
  104. }
  105. else if (obj instanceof Date) {
  106. DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
  107. value = "'" + formatter.format(new Date()) + "'";
  108. }
  109. else {
  110. if (obj != null) {
  111. value = obj.toString();
  112. } else {
  113. value = "";
  114. }
  115. }
  116. return value;
  117. }
  118. }