https://blog.csdn.net/tif_very/article/details/115034221
https://pythonjishu.com/mgghxgbqafqmtmt/
3、获得完整SQL、 存入数据库
问题在于存入数据库,Mybatis的插件先于spring容器的完全初始化,虽然加了@Component会被扫描加入容器管理,但是此时Mybatis的拦截器Dblnterceptor注入的对象EncryptManager是还未初始化到容器的。所以通过这种方式拿到的bean为空。
简单来说就是@Autowired 不管用,得用别的方法,这个方法就是创建SpringBeanUtils工具类getBean,文献3有代码。
package com.ty.crm.util;
import com.spire.pdf.packages.spreG;
import com.ty.crm.DO.Sys_Operation_LogDo;
import com.ty.crm.mapper.OperationLogMapper;
import com.ty.crm.shior.token.manager.TokenManager;
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.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
@Intercepts(
{
@Signature(type = Executor.class, method = “update”, args = {MappedStatement.class, Object.class}),
}
)
@Component
public class SqlInterceptor implements Interceptor {
Properties properties = null;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object target = invocation.getTarget(); //被代理对象
Method method = invocation.getMethod(); //代理方法
Object[] args = invocation.getArgs(); //方法参数
// do something ...方法拦截前执行代码块
this.addSqlLog(args);
Object result = invocation.proceed();
// do something ...方法拦截后执行代码块,不改变原有的sql执行过程
return result;
}
@Override
public Object plugin(Object target) {
// 只对要拦截制定类型的对象生成代理,这样能节省资源
if (target instanceof Executor) {
// 调用插件
return Plugin.wrap(target, this);
}
return target;
}
// 设置插件属性(直接通过Spring的方式获取属性,所以这个方法一般也用不到),项目启动的时候数据就会被加载
@Override
public void setProperties(Properties properties) {
// 赋值成员变量,在其他方法使用
this.properties = properties;
}
// 封装了一下sql语句,使得结果返回完整xml路径下的sql语句节点id + sql语句
public void addSqlLog(Object[] args) {
// 白名单:需要被记录日志的sql语句Mapper id
List<String> whiteList = Arrays.asList(
"com.ty.crm.mapper.OrderMapper.insertpurchase2List",
"com.ty.crm.mapper.OrderMapper.updatePurchaserequisition2Detail",
"com.ty.crm.mapper.OrderMapper.updatePurchaserequisition1Detail"
);
String sql = null;
MappedStatement mappedStatement = null;
try {
mappedStatement = (MappedStatement) args[0];
Object parameter = args[1];
// 白名单过滤
if (!whiteList.contains(mappedStatement.getId())) {
return;
}
BoundSql boundSql = mappedStatement.getBoundSql(parameter); // BoundSql就是封装myBatis最终产生的sql类
Configuration configuration = mappedStatement.getConfiguration(); // 获取节点的配置
sql = getSql(configuration, boundSql); // 获取到最终的sql语句
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("日志保存异常");
}
if (sql == null || "".equals(sql)) {
return;
}
//新增操作日志
Sys\_Operation\_LogDo sys_operation_logDo = new Sys\_Operation\_LogDo();
sys_operation_logDo.setAccount\_no(TokenManager.getAccountNo());
sys_operation_logDo.setLog\_usr\_id(TokenManager.getUserId().intValue());
sys_operation_logDo.setLog\_date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
sys_operation_logDo.setLog\_sql(sql);
// 保存
try {
OperationLogMapper operationLogMapper = SpringBeanUtils.getBean(OperationLogMapper.class);
operationLogMapper.insertOperationLog(sys_operation_logDo);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("日志保存异常");
}
}
// 获得sql,进行?的替换
public static String getSql(Configuration configuration, BoundSql boundSql) {
// 获取参数
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// sql语句中多个空格都用一个空格代替
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (parameterMappings != null && parameterMappings.size() != 0 && parameterObject != null) {
// 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
// 如果根据parameterObject.getClass()可以找到对应的类型,则替换
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(parameterObject)));
} else {
// MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
// 该分支是动态sql
Object obj = boundSql.getAdditionalParameter(propertyName);