我們在執行語句的時候會使用Mybatis自帶的日志打印工具,但是打印的時候參數會用?
代替,顯得看起來不是那么直觀,所以通過實現了InnerInterceptor接口,并重寫了beforeQuery
和beforeUpdate
方法。在這兩個方法中,它會獲取到執行的SQL語句、參數等信息,并通過日志輸出。
@Configuration
public class MybatisConfiguration {public MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new MybatisPlusAllSqlLog());return mybatisPlusInterceptor;}
}
public class MybatisPlusAllSqlLog implements InnerInterceptor {public static final Logger log = LoggerFactory.getLogger("sys-sql");@Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {logInfo(boundSql, ms, parameter);}@Overridepublic void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameter);logInfo(boundSql, ms, parameter);}private static void logInfo(BoundSql boundSql, MappedStatement ms, Object parameter) {try {log.info("parameter = " + parameter);// 獲取到節點的id,即sql語句的idString sqlId = ms.getId();log.info("sqlId = " + sqlId);// 獲取節點的配置Configuration configuration = ms.getConfiguration();// 獲取到最終的sql語句String sql = getSql(configuration, boundSql, sqlId);log.info("完整的sql:{}", sql);} catch (Exception e) {log.error("異常:{}", e.getLocalizedMessage(), e);}}// 封裝了一下sql語句,使得結果返回完整xml路徑下的sql語句節點id + sql語句public static String getSql(Configuration configuration, BoundSql boundSql, String sqlId) {return sqlId + ":" + showSql(configuration, boundSql);}// 進行?的替換public static String showSql(Configuration configuration, BoundSql boundSql) {// 獲取參數Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();// sql語句中多個空格都用一個空格代替String sql = boundSql.getSql().replaceAll("[\\s]+", " ");if (!CollectionUtils.isEmpty(parameterMappings) && 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)) {// 該分支是動態sqlObject obj = boundSql.getAdditionalParameter(propertyName);sql = sql.replaceFirst("\\?",Matcher.quoteReplacement(getParameterValue(obj)));} else {// 打印出缺失,提醒該參數缺失并防止錯位sql = sql.replaceFirst("\\?", "缺失");}}}}return sql;}// 如果參數是String,則添加單引號, 如果是日期,則轉換為時間格式器并加單引號; 對參數是null和不是null的情況作了處理private static String getParameterValue(Object obj) {String value;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;}}