mybatis拦截器 打印完整sql日志,并存入数据库_mybatis的sql日志拦截器打印日志

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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值