MyBatis拦截器打印不带问号的完整sql语句方法

?


1

/* Preparing: SELECT * FROM tb_user WHERE id = ? AND user_name = ?  <br>   目标是打印:SELECT * FROM tb_user WHERE id = 1000059081 AND user_name = ‘积极‘<br>*/ 这部分代码只是拦截了查询和更新,如果想对其他语句进行拦截,在@Intercepts中添加对应方法即可

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

<br>package dao.Interceptor;

import org.apache.commons.collections.CollectionUtils;

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.session.ResultHandler;

import org.apache.ibatis.session.RowBounds;

import org.apache.ibatis.type.TypeHandlerRegistry;

import java.text.DateFormat;

import java.util.Date;

import java.util.List;

import java.util.Locale;

import java.util.Properties;

import java.util.regex.Matcher;

@Intercepts({

        @Signature(type = Executor.class, method = "update", args = {

                MappedStatement.class, Object.class }),

        @Signature(type = Executor.class, method = "query", args = {

                MappedStatement.class, Object.class, RowBounds.class,

                ResultHandler.class }) })

@SuppressWarnings({"unchecked", "rawtypes"})

public class MybatisInterceptor implements Interceptor {

    @Override

    public Object intercept(Invocation invocation) throws Throwable {

        try{

            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];  // 获取xml中的一个select/update/insert/delete节点,主要描述的是一条SQL语句

            Object parameter = null;

       // 获取参数,if语句成立,表示sql语句有参数,参数格式是map形式

            if (invocation.getArgs().length > 1) {

                parameter = invocation.getArgs()[1];

                System.out.println("parameter = " + parameter);

            }

            String sqlId = mappedStatement.getId(); // 获取到节点的id,即sql语句的id

            System.out.println("sqlId = " + sqlId);

            BoundSql boundSql = mappedStatement.getBoundSql(parameter);  // BoundSql就是封装myBatis最终产生的sql类

            Configuration configuration = mappedStatement.getConfiguration();  // 获取节点的配置

            String sql = getSql(configuration, boundSql, sqlId); // 获取到最终的sql语句

            System.out.println("sql = " + sql);

            //log.debug(sql);

        }catch(Exception e){

           // log.error(e.getMessage(), e);

        }

        return invocation.proceed();  // 执行完上面的任务后,不改变原有的sql执行过程

    }

  // 封装了一下sql语句,使得结果返回完整xml路径下的sql语句节点id + sql语句

    public static String getSql(Configuration configuration, BoundSql boundSql,String sqlId) {

        String sql = showSql(configuration, boundSql);

        StringBuilder str = new StringBuilder(100);

        str.append(sqlId);

        str.append(":");

        str.append(sql);

        return str.toString();

    }

  /*<br>    *如果参数是String,则添加单引号, 如果是日期,则转换为时间格式器并加单引号; 对参数是null和不是null的情况作了处理<br>  */

    private static String getParameterValue(Object obj) {

        String value = null;

        if (obj instanceof String) {

            value = "‘" + obj.toString() + "‘";

        } else if (obj instanceof Date) {

            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);

            value = "‘" + formatter.format(new Date()) + "‘";

        } else {

            if (obj != null) {

                value = obj.toString();

            } else {

                value = "";

            }

        }

        return value;

    }

  // 进行?的替换

    public static String showSql(Configuration configuration, BoundSql boundSql) {

        Object parameterObject = boundSql.getParameterObject();  // 获取参数

        List<ParameterMapping> parameterMappings = boundSql

                .getParameterMappings();

        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");  // sql语句中多个空格都用一个空格代替

        if (CollectionUtils.isNotEmpty(parameterMappings) && parameterObject != null) {

            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); // 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换<br>       // 如果根据parameterObject.getClass()可以找到对应的类型,则替换

            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {

                sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(parameterObject)));

            } else {

                MetaObject metaObject = configuration.newMetaObject(parameterObject);// MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作

                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)) {

                        Object obj = boundSql.getAdditionalParameter(propertyName);  // 该分支是动态sql

                        sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));

                    }else{sql=sql.replaceFirst("\\?","缺失");}//打印出缺失,提醒该参数缺失并防止错位

                }

            }

        }

        return sql;

    }

    @Override

    public Object plugin(Object target) {

        return Plugin.wrap(target, this);

    }

    @Override

    public void setProperties(Properties properties) {

      

    }

}

 Mybatis配置文件如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>  <!--该路径是拦截器文件的路径 dao.Interceptor是拦截器文件的包名称>    <plugins>        <plugin interceptor="dao.Interceptor.MybatisInterceptor">        </plugin>    </plugins>

<environments default="development">        <environment id="development">                <transactionManager type="JDBC">                    <property name="" value=""></property>                </transactionManager>                <dataSource type="UNPOOLED">                    <property name="driver" value="oracle.jdbc.driver.OracleDriver"></property>>                    <property name="url" value="jdbc:oracle:thin:@xx.xxx.xxx.xxx:端口:oratest"></property>                    <property name="username" value="用户名"></property>                    <property name="password" value="密码"></property>

</dataSource>        </environment>    </environments>    <mappers>  

      <mapper resource="mybatis/UserMapper.xml"/>
    </mappers></configuration>

原文地址:https://www.cnblogs.com/jpfss/p/9025660.html

时间: 2024-10-14 09:21:05

MyBatis拦截器打印不带问号的完整sql语句方法的相关文章

Mybatis拦截器介绍及分页插件

1.1    目录 1.1 目录 1.2 前言 1.3 Interceptor接口 1.4 注册拦截器 1.5 Mybatis可拦截的方法 1.6 利用拦截器进行分页 1.2     前言 拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法.Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑.打个比方,对于Executor

Mybatis拦截器介绍

拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法.Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑.打个比方,对于Executor,Mybatis中有几种实现:BatchExecutor.ReuseExecutor.SimpleExecutor和CachingExecutor.这个时候如果你觉得这几种实现对于Execu

Mybatis 拦截器(二)

Mybatis拦截器介绍 拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法.Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑.打个比方,对于Executor,Mybatis中有几种实现:BatchExecutor.ReuseExecutor.SimpleExecutor和CachingExecutor.这个时候如果你觉

mybatis拦截器使用

[toc] mybatis拦截器入门 mybatis 拦截器接口Interceptor Interceptor接口,我们通过这个接口可以自定义我们自己的拦截器,从而实现在拦截的时候写上我们自己的一些逻辑.该接口提供了三个方法, 接口介绍: intercept方法: intercept方法是在进行拦截的时候要执行的方法. plugin方法: 该方法是拦截器用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理. setProperties方法: mybatis配置文件中co

玩转SpringBoot之整合Mybatis拦截器对数据库水平分表

利用Mybatis拦截器对数据库水平分表 需求描述 当数据量比较多时,放在一个表中的时候会影响查询效率:或者数据的时效性只是当月有效的时候:这时我们就会涉及到数据库的分表操作了.当然,你也可以使用比较完善的第三方组件:sharding-jdbc来实现:但是你使用后会发现,貌似对oracle的兼容性不是很好.所以最后我还是决定使用Mybatis拦截器对数据库进行水平分表. 为什么要选用Mybatis拦截器 拦截器:我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可

mybatis拦截器

业务需求:由于公司业务需要在所有的sql的增删改查中必须包含officeId,业务以officeId做隔离.因此做了一个Mybatis的的过去器.通过拦截sql处理的过程来判断接口sql是否包含officeId,如果不包含则添加officeId.@NoNeedOffice的注解可以添加在Dao的接口类或方法上.用于标识不需要处理的接口. package com.example.springcloud.provider; import com.example.springcloud.provide

【Mybatis】1、Mybatis拦截器

MyBatis拦截器原理探究 http://www.cnblogs.com/fangjian0423/p/mybatis-interceptor.html MyBatis 拦截器 (实现分页功能) http://www.cnblogs.com/jethypc/p/5149183.html 由浅入深分析mybatis通过动态代理实现拦截器(插件)的原理 http://zhangbo-peipei-163-com.iteye.com/blog/2033832 使用方法 https://github.

Mybatis拦截器实现分页

本文介绍使用Mybatis拦截器,实现分页:并且在dao层,直接返回自定义的分页对象. 最终dao层结果: public interface ModelMapper { Page<Model> pageByConditions(RowBounds rowBounds, Model record); } 接下来一步一步来实现分页. 一.创建Page对象: public class Page<T> extends PageList<T> { private int page

Mybatis拦截器 mysql load data local 内存流处理

Mybatis 拦截器不做解释了,用过的基本都知道,这里用load data local主要是应对大批量数据的处理,提高性能,也支持事务回滚,且不影响其他的DML操作,当然这个操作不要涉及到当前所load的数据,其中在使用的时候一定要local , 这个命令使用是mysql规定的,否则不加则会认为是服务器本地的文件.这里主要是以流的方式来做处理,这样可以使用内存流,这样就可以避免在某些时候需要生成文件才能导入的多余操作,和IO性能消耗.也可以是应用本地的文件. 注:该做法只试用于存入数据的表,不