SpringBoot解析MyBatis預編譯SQL

pom.xml

		<profile><!-- 開發環境 --><id>dev</id><activation><!--  默認激活 --><activeByDefault>true</activeByDefault></activation><properties><spring.profiles.active>dev</spring.profiles.active></properties></profile>

application.yml

# 開啟 MyBatis SQL 日志解析
mybatis-log:# 默認:falseenabled: true

MyBatisSqlParsingPlugin.java

默認是dev開啟彩色日志

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.sql.Statement;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "update", args = {Statement.class,}),@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})
})
@Component
@ConditionalOnProperty(prefix = "mybatis-log", value = "enabled", havingValue = "true")
public final class MyBatisSqlParsingPlugin implements Interceptor {private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");@Resourceprivate Environment env;@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();ParameterHandler parameterHandler = statementHandler.getParameterHandler();BoundSql boundSql = statementHandler.getBoundSql();String[] activeProfiles = env.getActiveProfiles();String activeProfile = "";if (activeProfiles.length > 0) {activeProfile = activeProfiles[0];}try {String sql = formatSql(parameterHandler, boundSql);if (!boundSql.getSql().equals(sql)) {// dev改成你自己的pom.xml開發環境配置if (StringUtils.hasText(activeProfile) && "dev".equals(activeProfile)) {log.info("Execute SQL:\033[32m{}\033[0m", sql);} else {log.info("Execute SQL:{}", sql);}}} catch (Exception e) {String sql = boundSql.getSql();if (StringUtils.hasText(activeProfile) && "dev".equals(activeProfile)) {log.error("Execute SQL:\033[31m{}\033[0m \nException:", sql, e);} else {log.error("Execute SQL:{}\nException:", sql, e);}}return invocation.proceed();}/*** 格式化SQL及其參數*/private String formatSql(ParameterHandler parameterHandler, BoundSql boundSql) throws NoSuchFieldException, IllegalAccessException {Class<? extends ParameterHandler> parameterHandlerClass = parameterHandler.getClass();Field mappedStatementField = parameterHandlerClass.getDeclaredField("mappedStatement");mappedStatementField.setAccessible(true);MappedStatement mappedStatement = (MappedStatement) mappedStatementField.get(parameterHandler);String sql = boundSql.getSql().replaceAll("\\s+", " ");// sql字符串是空或存儲過程,直接跳過if (!StringUtils.hasText(sql) || sql.trim().charAt(0) == '{') {return "";}// 不傳參數的場景,直接把Sql美化一下返回出去Object parameterObject = parameterHandler.getParameterObject();List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();if (Objects.isNull(parameterObject) || parameterMappingList.isEmpty()) {return sql;}return handleCommonParameter(boundSql, mappedStatement);}//替換預編譯SQLprivate String handleCommonParameter(BoundSql boundSql, MappedStatement mappedStatement) {String sql = boundSql.getSql();Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();Configuration configuration = mappedStatement.getConfiguration();TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();List<String> params = new ArrayList<>();for (ParameterMapping parameterMapping : parameterMappings) {if (parameterMapping.getMode() == ParameterMode.OUT) {continue;}Object propertyValue;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {propertyValue = boundSql.getAdditionalParameter(propertyName);} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {propertyValue = parameterObject;} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);propertyValue = metaObject.getValue(propertyName);}params.add(this.formatParam(propertyValue));}//轉譯百分號if (sql.contains("%")) {//如果參數不一致直接返回SQLPattern pattern = Pattern.compile("\\?");Matcher matcher = pattern.matcher(sql);int count = 0;while (matcher.find()) {count++;}if (count == 0 || params.isEmpty()) {return sql;}if (params.size() != count) {log.error("SQL:{}", sql);log.error("SQL parameters:{}", params);return sql;}sql = sql.replaceAll("%", "%%");}sql = sql.replaceAll("\\?", "%s");return String.format(sql, params.toArray());}private String formatParam(Object object) {if (object == null) {return "null";}if (object instanceof String) {return formatString((String) object);}if (object instanceof Date) {return formatDate((Date) object);}if (object instanceof LocalDate) {return formatLocalDate((LocalDate) object);}if (object instanceof LocalDateTime) {return formatLocalDateTime((LocalDateTime) object);}return object.toString();}private static String formatString(String str) {return "'" + str + "'";}private String formatDate(Date date) {return "'" + DATE_TIME_FORMATTER.format(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()) + "'";}private String formatLocalDate(LocalDate date) {return "'" + DATE_FORMATTER.format(date) + "'";}private String formatLocalDateTime(LocalDateTime dateTime) {return "'" + DATE_TIME_FORMATTER.format(dateTime) + "'";}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/13036.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/13036.shtml
英文地址,請注明出處:http://en.pswp.cn/web/13036.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Unity 模擬放大鏡局部放大UI 效果實現

UI 放大實現 RectTransformUtility.ScreenPointToLocalPointInRectangle(rectScale, eventData.position, eventData.pressEventCamera, out localPos); 使用IPointerDownHandler 獲取鼠標點擊時的有效負載&#xff0c;并將鼠標坐標轉成對應的UI 坐標&#xff0c;rectScale 為…

【Win】一鍵恢復IE11工具:讓舊版瀏覽器在新系統中重生

微軟在2020年8月的時候就已經公告IE11的生命周期終點&#xff0c;多次提醒將在2022年6月15日起不再支持IE 11&#xff0c;呼吁用戶盡快轉換到Chromium-based Microsoft Edge。微軟也陸續終止旗下服務支持這個舊式瀏覽器。2021年3月&#xff0c;Chrome瀏覽器已不支持舊IE App。2…

字符串解析-KMP魔改

題目 已知存在一種字符串解析語法&#xff0c;其中的語法元素如下 N:用于匹配單個數字(0-9) A:用于匹配單個字母(a-z,A-Z) n():用于表示一個分組&#xff0c;分組中至少有一個N語法元素或者A語法元素&#xff0c;n為一個數值&#xff0c;表示匹配n次&#xff0c;1<n< 20…

歡迎光臨Java中的客“棧”

就目前而言&#xff0c;相信大家對數組、鏈表還有棧都基本已經有了一些了解&#xff0c;本篇文章將以棧為主體&#xff0c;探究棧和數組&#xff0c;棧和鏈表之間的一些聯系。 當然在開始對棧的學習之前&#xff0c;我們先回顧有關數組、鏈表的基礎知識點。 學習代碼就是一個…

四川景源暢信:如何更好的為抖音小店做引流?

在數字化營銷的浪潮中&#xff0c;抖音小店作為新興的電商形態&#xff0c;正以其獨特的社交屬性和流量優勢吸引著眾多商家的目光。如何為抖音小店引流&#xff0c;成為許多店主心中的疑問。本文將深入探討有效提升店鋪流量的策略&#xff0c;助你在抖音平臺上快速崛起。 一、內…

代碼隨想錄算法訓練營第二十五天:樹的最后學習

代碼隨想錄算法訓練營第二十五天&#xff1a;樹的最后學習 如果不對遞歸有深刻的理解&#xff0c;本題有點難 單純移除一個節點那還不夠&#xff0c;要修剪&#xff01; #669. 修剪二叉搜索樹 力扣題目鏈接(opens new window) 給定一個二叉搜索樹&#xff0c;同時給定最小邊界…

shell腳本之sort,uniq,tr,cut,sphit,paste,ecal與正則表達式

sort命令 uniq命令 tr命令 cut命令 sphit命令 paste命令 ecal命令 正則表達式 sort命令 sort命令---以行為單位對文件內容進行排序&#xff0c;也可以根據不同的數據類型來排序 比較原則是從首字符向后&#xff0c;依次按ASCII碼值進行比較&#xff0c;最后將他們按升序…

通過java將數據導出為PDF,包扣合并單元格操作

最近項目中需要將查詢出來的表格數據以PDF形式導出&#xff0c;并且表格的形式包含橫向行與縱向列的單元格合并操作&#xff0c;導出的最終效果如圖所示&#xff1a; 首先引入操作依賴 <!--導出pdf所需包--><dependency><groupId>com.itextpdf</groupId&…

【js獲取月份最后一天】

功能 獲取月份最后一天 代碼 function getLastDay(year, month) {//返回月份最后一天&#xff0c;不寫參數默認返回本月最后一天var date new Date(),date2, day;if (year undefined) year date.getFullYear(); //獲取今年年份if (month undefined) month date.getMont…

Linux- cron調度進程

cron 是一個 Unix 類操作系統中的時間調度守護進程&#xff0c;用于在特定的時間或間隔運行指定的命令或腳本。它非常適合自動化系統管理和維護任務&#xff0c;如備份、日志輪轉、系統監控等。以下是 cron 守護進程的詳細介紹。 cron 守護進程的工作原理 crontab 文件&#x…

上海市計算機學會競賽平臺2022年5月月賽丙組三數排序

題目描述 給定三個整數 &#x1d44e;,&#x1d44f;,&#x1d450;a,b,c&#xff0c;請將它們以從小到大的順序排序后輸出。 輸入格式 單獨一行&#xff1a;三個整數表示 &#x1d44e;,&#x1d44f;,&#x1d450;a,b,c。 輸出格式 單獨一行&#xff1a;表示按升序排列…

匯聚榮:拼多多長期沒有流量如何提高?

在電商的海洋中&#xff0c;拼多多以其獨特的團購模式吸引了眾多消費者的目光。然而&#xff0c;隨著市場競爭的加劇和消費者需求的多樣化&#xff0c;一些商家發現自家店鋪的流量持續低迷&#xff0c;銷售業績難以突破。面對這樣的挑戰&#xff0c;如何有效提升拼多多店鋪的客…

【Python】學生管理系統

為了了解Json以及在python中如何處理Json數據&#xff0c;我在這里整理了一段全面詳細的 Python 代碼&#xff0c;演示了如何加載、處理和操作 JSON 數據。該代碼包括讀取 JSON 數據、查詢學生信息、添加新學生、更新課程信息等操作。 示例代碼 import json# 示例 JSON 數據 …

深視 線掃相機 獲取點云數據

Qt hello - 專注于Qt的技術分享平臺 最近項目上用到了深視的線掃相機&#xff0c;集成了三天才搞定&#xff0c;分享下代碼。 順便吐槽一下&#xff0c;想用相機取圖&#xff0c;這么簡單的功能&#xff0c;搞得如此麻煩。 1&#xff0c;文檔有三份&#xff0c;就不能集成到…

【計算機畢業設計】springboot反詐科普平臺的設計與實現

相比于以前的傳統手工管理方式&#xff0c;智能化的管理方式可以大幅降低反詐科普平臺的運營人員成本&#xff0c;實現了反詐科普平臺的 標準化、制度化、程序化的管理&#xff0c;有效地防止了反詐科普平臺的隨意管理&#xff0c;提高了信息的處理速度和精確度&#xff0c;能夠…

python中字符串的 format() 方法

文章目錄 前言1、位置參數2、索引參數3、命名參數3、格式化參數 前言 format() 是 Python 字符串對象的方法&#xff0c;用于將值插入到格式化字符串的占位符中。它是一種靈活和強大的字符串格式化工具。format() 方法可以在字符串中使用占位符 {}&#xff0c;并通過傳遞參數將…

[vue] nvm

nvm ls // 看安裝的所有node.js的版本nvm list available // 查顯示可以安裝的所有node.js的版本可以在可選列表里。選擇任意版本安裝&#xff0c;比如安裝16.15.0 執行&#xff1a; nvm install 16.15.0安裝好了之后。可以執行&#xff1a; …

字符數組以及字符串相關的幾個函數

一.字符數組 1.定義&#xff1a;格式如下 char a[10]; //此處就表示定義了一個長度為10的字符數組 2.引用&#xff1a; 也和其余的數組一樣&#xff0c;是下標引用。 3.初始化&#xff1a; 如下代碼為字符數組初始化的幾種情況&#xff1a; int main() {char arr[5] {…

25考研英語長難句Day03

25考研英語長難句Day03 【a.詞組】【b.斷句】 多虧了電子學和微力學的不斷小型化&#xff0c;現在已經有一些機器人系統可以進行精確到毫米以下的腦部和骨骼手術&#xff0c;比技術高超的醫生用手能做到的精確得多。 【a.詞組】 詞組翻譯thanks to多虧了&#xff0c;由于cont…

【JavaEE進階】 Bean的作用域與生命周期

文章目錄 &#x1f343;Bean的作用域&#x1f6a9;作用域的使用&#x1f6a9;觀察Bean的作用域&#x1f388;單例作用域&#x1f388;多例作用域&#x1f388;請求作用域&#x1f388;會話作?域&#x1f388;Application作?域 &#x1f384;Bean的?命周期?總結 &#x1f34…