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);
|
}
|
|
}
|