范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Mybatis拦截器实现带参数SQL语句打印

  前言
  在我们工作实际项目中,常常遇到使用Mybatis作为ORM框架,在使用的过程中,一般都会开启日志的打印功能,这样在控制台就会输出执行的SQL,定位SQL问题也是比较方便的。 但是,我们就会发现,这样打印出来的SQL是预编译语句和参数是分开的。
  此时如果需要去数据库执行上条SQL的时候,我们需要手动的把参数拼接到SQL语句中; 参数少此操作还可以,参数一旦比较多,此操作相当的麻烦繁琐。 下面我们就使用Mybatis拦截器的方式来实现打印完整SQL的功能。  具体实现实现拦截器逻辑import lombok.extern.slf4j.Slf4j; 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.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.util.CollectionUtils;  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;  /**  * @author 公众号: SimpleMemory  * @version 1.0.0  * @ClassName FullSQLInterceptor.java  * @Description TODO  * @createTime 2022年10月14日 18:39:00  */ @Slf4j @Intercepts(value = {         @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, CacheKey.class, BoundSql.class}),         @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) public class MybatisSQLInterceptor implements Interceptor {      @Override     public Object intercept(Invocation invocation) throws Throwable {         try {             // 获取xml中的一个select/update/insert/delete节点,主要描述的是一条SQL语句             MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];             Object parameter = null;             // 获取参数,if语句成立,表示sql语句有参数,参数格式是map形式             if (invocation.getArgs().length > 1) {                 parameter = invocation.getArgs()[1];                 log.error("sql-param:{}", parameter);             }            /* if (SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {             }*/             // 获取到节点的id,即sql语句的id             String sqlId = mappedStatement.getId();             // BoundSql就是封装myBatis最终产生的sql类             BoundSql boundSql = mappedStatement.getBoundSql(parameter);             // 获取节点的配置             Configuration configuration = mappedStatement.getConfiguration();             // 获取到最终的sql语句             String sql = getSql(configuration, boundSql, sqlId);             log.error("sql->{}", sql);         } catch (Exception e) {         }         // 执行完上面的任务后,不改变原有的sql执行过程         return invocation.proceed();     }      /**      * 封装了一下sql语句,使得结果返回完整xml路径下的sql语句节点id + sql语句      *      * @param configuration configuration      * @param boundSql      boundSql      * @param sqlId         sqlId      * @return java.lang.String      */     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();     }      /**      * 如果参数是String,则添加单引号, 如果是日期,则转换为时间格式器并加单引号;      * 对参数是null和不是null的情况作了处理      *      * @param obj obj      * @return java.lang.String      */     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;     }      /**      * 进行?的替换      *      * @param configuration      * @param boundSql      * @return      */     public static String showSql(Configuration configuration, BoundSql boundSql) {         Object parameterObject = boundSql.getParameterObject();  // 获取参数         List parameterMappings = boundSql                 .getParameterMappings();         String sql = boundSql.getSql().replaceAll("[s]+", " ");  // sql语句中多个空格都用一个空格代替         if (!CollectionUtils.isEmpty(parameterMappings) && parameterObject != null) {             TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); // 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换
  // 如果根据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的配置文件中配置拦截器
          
  在application.yml中配置Mybatis的全局的配置文件mybatis-config.xml
  实现效果
  启动项目,查看控制台打印SQL语句情况。
  2022-10-15 09:51:50.780 ERROR 30292 --- [io-8089-exec-24] c.r.web.config.MybatisSQLInterceptor     : sql->com.ruoyi.system.mapper.SysDeptMapper.selectDeptList:select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time from sys_dept d where d.del_flag = "0" AND dept_name like concat("%", "开发", "%") AND status = "0" order by d.parent_id, d.order_num
  公众号:SimpleMemory

1978年特务案5岁小孩无意间一句话,暴露了潜伏大陆29年的特务在阅读此文之前,麻烦您点击一下关注,既方便您进行讨论与分享,又给您带来不一样的参与感,感谢您的支持!前言1978年的一天,一个名叫李朝红的女人走进了浙江省黄岩县公安局,她对警察说我如果美帝不介入,1949年之后咱们能统一台湾吗?估计不少人都思考过这样一个问题如果美帝不介入,49年之后咱们能打过海峡统一台湾吗?在这个问题上我劝大家耗子尾汁,不要看不起我先总统蒋公中正。还用你打?我老蒋是我民国第一懂王!伟大的朱棣的孙子朱瞻基,对二叔烤糊,处死9子三叔送画,保子孙1426年,朱棣的儿子朱高燧,收到朱瞻基来信,吓得面如死色二哥被扣在300斤大缸内烤糊,9个儿子被处死。朱高燧浑身颤抖,信的内容把整个细节都记录下来,随信寄来的还有朝中大臣列出朱高海南中小学将于2月13日正式开学央广网海口2月1日消息(记者钟宁)根据海南省教育厅此前印发的海南省全日制中小学20222023学年度校历,海南省中小学将于2月12日报到注册,2月13日正式开学。此前受疫情等原因影春节3。08亿游客去哪了我在海南堵车,你在大理看人海钛媒体焦点图片来源视觉中国疫情放开后的第一次出游,感受是云南真美,但建议目前还没出发的不要来了,人太多了1月23日,即将结束春节游的唐笑表示,自己之前没有春节出游的习惯,今年趁着放假早才有此中国4大烧鸡你吃过几种?德州扒鸡,称霸我国铁路几十年烧鸡种类全国各地五花八门,到底哪些传承悠久负有盛名?它们的味道又怎样呢?先说一下作为四大烧鸡之首的德州扒鸡,估计很多朋友对它的认知还局限于绿皮车时代,没错,这的确是德州扒鸡赖以成名忘掉三亚!东方市它才是海南旅居养老最便宜的城市头号有新人这座冷门到全网0攻略小城,真的太适合养老了!一到冬天,就想去海南旅居了!均温23的温暖天气,一望无际的湛蓝海水,真是太舒服了!可近年来,三亚越发人多价高,曾偏冷门的万宁陵泰山队终于要清理门户!功勋中卫要被送出球队,曾被实锤欠钱不还日前,泰山队中卫戴琳成为了媒体和球迷热议的焦点。让戴琳感到尴尬的是他成为热议焦点,并不是他场上表现有多出色。相反,戴琳是因为被女网友实名控诉欠钱不还。这位女网友就是吴兴涵的前女友。1月31日最新8大交易动态,东契奇发话,湖人急出手据fox体育爆料,鹈鹕正在评估英格拉姆的交易价值,在英格拉姆缺阵的比赛鹈鹕胜多负少,考虑到球队已经默认以锡安威廉森为核心,英格拉姆性格上的不安定因素会导致他的离开,有分析师认为要得21周三足球赛事预测分析开罗阿赫利VS奥克兰城世俱杯淘汰赛北京时间2023220300世俱杯第一轮淘汰赛主场由阿尔阿赫利坐镇对战奥克兰城,一边是埃及超NO。1一边是新西兰联NO。2可以说这场比赛不仅仅支是两支球队的比赛关乎的还有两支联赛的孔子是韩国人?从新史观运动到韩国起源论(本文3000字,读完大约需要10分钟)某视频网站截图你一定看过上图这种土嗨视频。内容大概都是这样的韩国说孔子是韩国人,曹操是韩国人,韩国发明了汉字,端午节,活字印刷术,建造了长城
博格巴因伤无缘世界杯对法国队是好事?他曾涉嫌请巫师诅咒队友姆巴佩又一位顶级球星遗憾告别世界杯。一直备受伤病困扰的法国中场博格巴仍然需要一段时间才能康复,基本确定无缘卡塔尔世界杯。经纪人承认他无缘世界杯自今夏由曼联队转会至尤文图斯队后,博格巴一直马科斯阿隆索为巴萨效力是我的愿望能否踢世界杯由恩里克决定直播吧11月7日讯巴萨后卫马科斯阿隆索接受每日体育报独家采访,他谈到了巴萨等情况。关于皮克在诺坎普的最后一场比赛,以及自己的职业生涯?我爸爸当时在执教,我们跟着他去不同的城市,支持世界杯巡礼之马内赛前伤退虚惊一场一人肩负非洲全村的希望出生于1992年的马内,目前正值当打之年,是塞内加尔队的绝对核心,也是德甲豪门拜仁慕尼黑的绝对主力前锋。在塞内加尔的卡塔尔世界杯之旅中,马内的发挥十分关键。2022年对于马内来说是炫酷ARGB和高效静音兼备,德静界PUREBASE500FX中塔机箱推荐AMD锐龙7000处理器Intel酷睿13代处理器英伟达RTX40系显卡的先后发布,在又一年消费者狂欢节(双11)到来之前,吊足了玩家的胃口。那么,如果你正好有装机的打算,不妨考虑精致萌,达尔优小方糖轻易俘获少女心,高颜值强性能爽手感键盘作为生产力工具,每天在上面噼噼啪啪忙个不停。在语音输入尚未普及之前,这将会是我们在互联网世界里,使用最频繁的沟通交流手段。每天上手的东西,必须要手感好性能强,才能用着舒心。不过中国最美的九大雪山,你去过哪座?在广袤的中华大地上,有着地球表面数量最多,颜值也足够拔尖的雪山。在众多的雪山群中,位于西藏川西云南的这十座雪山,被称作中国最美九大雪山。我们一一盘点,看看你去过哪座?一南迦巴瓦走3中国网友到朝鲜旅游的感受,女孩纯洁,街道空旷,自行车很多朝鲜是我国的邻居,对朝鲜很多网友而言,朝鲜陌生又熟悉。一般而言,家里的老人对朝鲜比较熟悉,而年轻人对韩国比较熟悉。曾经朝鲜的影视剧在国内非常流行,现在韩剧在国内很流行。对年轻人来说会说流利汉语的美国总统,靠侵吞中国煤矿暴富胡佛的总统往事美国大萧条的纪念雕像在之前的文章会说流利汉语的美国总统,靠侵吞中国煤矿暴富胡佛的中国往事中,我们介绍了美国第31任总统赫伯特克拉克胡佛(HerbertClarkHoove)在成为美台积电为AMD生产5nm处理器半导体竞争力中国大陆第四丨CSDN芯闻一分钟速览新闻点!台积电将为AMD生产5nm的Zen4热那亚处理器,新品将于本周发布面板驱动IC急冻引爆裁员潮高通2022财年第四财季营收113。96亿美元,净利润同比增长3京东方中国联通干了件非常漂亮的大事花钱少却轰轰烈烈运营商财经吴碧慧文中国联通的业务今年给人感觉声量最大的传播内容是什么?是5G家庭宽带还是政企业务?这些自然不用说,但是,惊人惊叹地是,一个叫争创联通服务标兵的事情却惊人地展现了其传支持无线网卡与蓝牙!12代i5配RTX30603060Ti游戏主机配置推荐众所周知,目前绝大数的台式机均不支持WiFi无线网卡和蓝牙,主要是因为市面上板载无线网卡和蓝牙的主板比较贵,如果你有无线网和蓝牙连接需求,那么就需要自行增加无线网卡和蓝牙适配器。针