| package com.xzx.gc.interceptor;  | 
|   | 
| import cn.hutool.core.collection.CollUtil;  | 
| import cn.hutool.core.convert.Convert;  | 
| import com.xzx.gc.common.dto.log.SqlDto;  | 
| import com.xzx.gc.common.utils.SpringUtil;  | 
| import lombok.extern.slf4j.Slf4j;  | 
| import org.apache.commons.lang3.StringUtils;  | 
| import org.apache.ibatis.cache.CacheKey;  | 
| import org.apache.ibatis.executor.Executor;  | 
| import org.apache.ibatis.mapping.BoundSql;  | 
| import org.apache.ibatis.mapping.MappedStatement;  | 
| import org.apache.ibatis.mapping.ParameterMapping;  | 
| import org.apache.ibatis.mapping.SqlCommandType;  | 
| import org.apache.ibatis.plugin.*;  | 
| import org.apache.ibatis.reflection.MetaObject;  | 
| import org.apache.ibatis.session.Configuration;  | 
| import org.apache.ibatis.session.ResultHandler;  | 
| import org.apache.ibatis.session.RowBounds;  | 
| import org.apache.ibatis.type.TypeHandlerRegistry;  | 
| import org.springframework.beans.factory.annotation.Autowired;  | 
| import org.springframework.stereotype.Component;  | 
|   | 
| import javax.servlet.http.HttpServletRequest;  | 
| import java.text.SimpleDateFormat;  | 
| import java.util.Date;  | 
| import java.util.List;  | 
| import java.util.Properties;  | 
|   | 
| /**ALL < index < range ~ index_merge < ref < eq_ref < const < system  | 
|  * 1.可以用来分析SQL执行效率  | 
|  * 2.可以用来获取实际执行的SQL  | 
|  *  * @author zhanjixun  | 
|  * @time 2018年6月28日 19:20:23  | 
|  */  | 
| @Slf4j  | 
| @Intercepts({  | 
|         @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),  | 
|         @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),  | 
|         @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}  | 
| )  | 
| @Component  | 
| public class SqlInterceptor implements Interceptor {  | 
|   | 
|     public static  final String SQL_PARAM="sqlParam";  | 
|   | 
|     @Autowired  | 
|     private SpringUtil springUtil;  | 
|       | 
|     private int MIN_SIZE = 0;  | 
|   | 
|     @Override  | 
|     public Object intercept(Invocation invocation) throws Throwable {  | 
|         HttpServletRequest request = springUtil.getCurrentRequest();  | 
|         List<SqlDto> sqlList=null;  | 
|         if(request!=null) {  | 
|             sqlList = (List<SqlDto>) request.getAttribute(SQL_PARAM);  | 
|         }  | 
|   | 
|         Object[] args = invocation.getArgs();  | 
|         MappedStatement mappedStatement = (MappedStatement) args[0];  | 
|         BoundSql boundSql=null;  | 
|         if (args.length > 5) {  | 
|             boundSql = (BoundSql) args[5];  | 
|         }  | 
|         if(boundSql==null){  | 
|             Object parameter= args[1];  | 
|             boundSql = mappedStatement.getBoundSql(parameter);  | 
|         }  | 
|         String sqlId = mappedStatement.getId();  | 
|         Configuration configuration = mappedStatement.getConfiguration();  | 
|   | 
|         long startTime = System.currentTimeMillis();  | 
|         Object result = null;  | 
|         try {  | 
|             result = invocation.proceed();  | 
|         } finally {  | 
|             try {  | 
|                 if(request!=null) {  | 
|                     SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();  | 
|                     int effectNum = 0;  | 
|   | 
|                     if (sqlCommandType == SqlCommandType.UPDATE || sqlCommandType == SqlCommandType.INSERT || sqlCommandType == SqlCommandType.DELETE) {  | 
|                         effectNum = Convert.toInt(result, 0);  | 
|                     }else if(sqlId.endsWith("_COUNT")){  | 
|                         List<?> objects = Convert.toList(result);  | 
|                         if(CollUtil.isNotEmpty(objects)){  | 
|                             effectNum=Convert.toInt(objects.get(0),0);  | 
|                         }  | 
|                     }else if(sqlCommandType==SqlCommandType.SELECT){  | 
|                         List<?> objects = Convert.toList(result);  | 
|                         if(CollUtil.isNotEmpty(objects)){  | 
|                             effectNum=objects.size();  | 
|                         }  | 
|                     }  | 
|                     long sqlCostTime = System.currentTimeMillis() - startTime;  | 
|                     String sql = getSql(configuration, boundSql);  | 
|                     SqlDto sqlDto = new SqlDto();  | 
|                     sqlDto.setSql(sql);  | 
|                     sqlDto.setSqlId(sqlId);  | 
|                     sqlDto.setCostTime(sqlCostTime + "");  | 
|                     sqlDto.setEffectNum(effectNum + "");  | 
|                     sqlDto.setSqlType(sqlCommandType.name());  | 
|                     if (CollUtil.isNotEmpty(sqlList)) {  | 
|                         sqlList.add(sqlDto);  | 
|                     } else {  | 
|                         sqlList = CollUtil.newArrayList(sqlDto);  | 
|                     }  | 
|                     request.setAttribute(SQL_PARAM, sqlList);  | 
|                 }  | 
|             } catch (Exception ignored) {  | 
| //                ignored.printStackTrace();  | 
|             }  | 
|         }  | 
|         return result;  | 
|     }  | 
|   | 
|     @Override  | 
|     public Object plugin(Object target) {  | 
|         return Plugin.wrap(target, this);  | 
|     }  | 
|   | 
|     @Override  | 
|     public void setProperties(Properties properties) {  | 
|         if (properties == null) {  | 
|             return;  | 
|         }  | 
|         if (properties.containsKey("minLogSize")) {  | 
|             MIN_SIZE = Integer.valueOf(properties.getProperty("minLogSize"));  | 
|         }  | 
|     }  | 
|   | 
|     private String getSql(Configuration configuration, BoundSql boundSql) {  | 
|         // 输入sql字符串空判断  | 
|         if(boundSql==null){  | 
|             return "";  | 
|         }  | 
|         String sql = boundSql.getSql();  | 
|         if (StringUtils.isBlank(sql)) {  | 
|             return "";  | 
|         }  | 
|   | 
|         //美化sql  | 
|         sql = beautifySql(sql);  | 
|   | 
|         //填充占位符, 目前基本不用mybatis存储过程调用,故此处不做考虑  | 
|         Object parameterObject = boundSql.getParameterObject();  | 
|         List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();  | 
|         if (!parameterMappings.isEmpty() && parameterObject != null) {  | 
|             TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();  | 
|             if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {  | 
|                 sql = this.replacePlaceholder(sql, parameterObject);  | 
|             } else {  | 
|                 MetaObject metaObject = configuration.newMetaObject(parameterObject);  | 
|                 for (ParameterMapping parameterMapping : parameterMappings) {  | 
|                     String propertyName = parameterMapping.getProperty();  | 
|                     if (metaObject.hasGetter(propertyName)) {  | 
|                         Object obj = metaObject.getValue(propertyName);  | 
|                         sql = replacePlaceholder(sql, obj);  | 
|                     } else if (boundSql.hasAdditionalParameter(propertyName)) {  | 
|                         Object obj = boundSql.getAdditionalParameter(propertyName);  | 
|                         sql = replacePlaceholder(sql, obj);  | 
|                     }  | 
|                 }  | 
|             }  | 
|         }  | 
|         return sql;  | 
|     }  | 
|   | 
|     private String beautifySql(String sql) {  | 
|         return sql.replaceAll("[\\s\n ]+", " ");  | 
|     }  | 
|   | 
|     private String replacePlaceholder(String sql, Object parameterObject) {  | 
|         String result;  | 
|         if(parameterObject!=null) {  | 
|             if (parameterObject instanceof String) {  | 
|                 result = "'" + parameterObject.toString() + "'";  | 
|             } else if (parameterObject instanceof Date) {  | 
|                 result = "'" + getDate2String((Date) parameterObject) + "'";  | 
|             } else {  | 
|                 result = parameterObject.toString();  | 
|             }  | 
|             return sql.replaceFirst("\\?", result);  | 
|         }else {  | 
|             return sql;  | 
|         }  | 
|     }  | 
|   | 
|     private String getDate2String(Date parameterObject) {  | 
|         return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(parameterObject);  | 
|     }  | 
|   | 
| }  |