From 80c6edc221d6e3e83d91041b8dda7077cc970c22 Mon Sep 17 00:00:00 2001 From: lbw Date: Thu, 3 Jun 2021 15:56:51 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20DruidSqlLogFilter=20Mybatis=20?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E6=97=A5=E5=BF=97=E6=A0=BC=E5=BC=8F=E5=8C=96?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pigx-common/pigx-common-data/pom.xml | 8 +- .../data/config/PigxMybatisProperties.java | 23 +++ .../data/mybatis/DruidSqlLogFilter.java | 162 ++++++++++++++++++ .../mybatis/MybatisPlusConfiguration.java | 19 +- 4 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/config/PigxMybatisProperties.java create mode 100644 pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/DruidSqlLogFilter.java diff --git a/pigx-common/pigx-common-data/pom.xml b/pigx-common/pigx-common-data/pom.xml index 901b03dd2..20b0070aa 100644 --- a/pigx-common/pigx-common-data/pom.xml +++ b/pigx-common/pigx-common-data/pom.xml @@ -39,11 +39,17 @@ com.pig4cloud pigx-common-core - + com.baomidou mybatis-plus-extension + + + com.alibaba + druid + true + com.pig4cloud diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/config/PigxMybatisProperties.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/config/PigxMybatisProperties.java new file mode 100644 index 000000000..43f789ace --- /dev/null +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/config/PigxMybatisProperties.java @@ -0,0 +1,23 @@ +package com.pig4cloud.pigx.common.data.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; + +/** + * Mybatis 配置 + * + * @author lengleng + * @date 2021/6/3 + */ +@Data +@RefreshScope +@ConfigurationProperties("pigx.mybatis") +public class PigxMybatisProperties { + + /** + * 是否打印可执行 sql + */ + private boolean showSql = true; + +} diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/DruidSqlLogFilter.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/DruidSqlLogFilter.java new file mode 100644 index 000000000..8d1cd3a43 --- /dev/null +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/DruidSqlLogFilter.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pig4cloud.pigx.common.data.mybatis; + +import com.alibaba.druid.DbType; +import com.alibaba.druid.filter.FilterChain; +import com.alibaba.druid.filter.FilterEventAdapter; +import com.alibaba.druid.proxy.jdbc.JdbcParameter; +import com.alibaba.druid.proxy.jdbc.ResultSetProxy; +import com.alibaba.druid.proxy.jdbc.StatementProxy; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.util.StringUtils; +import com.pig4cloud.pigx.common.data.config.PigxMybatisProperties; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.sql.SQLException; +import java.time.temporal.TemporalAccessor; +import java.util.ArrayList; +import java.util.List; + +/** + * 打印可执行的 sql 日志 + * + *

+ * 参考:https://jfinal.com/share/2204 + *

+ * + * @author L.cm + */ +@Slf4j +@RequiredArgsConstructor +public class DruidSqlLogFilter extends FilterEventAdapter { + + private static final SQLUtils.FormatOption FORMAT_OPTION = new SQLUtils.FormatOption(false, false); + + private final PigxMybatisProperties properties; + + @Override + protected void statementExecuteBefore(StatementProxy statement, String sql) { + statement.setLastExecuteStartNano(); + } + + @Override + protected void statementExecuteBatchBefore(StatementProxy statement) { + statement.setLastExecuteStartNano(); + } + + @Override + protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) { + statement.setLastExecuteStartNano(); + } + + @Override + protected void statementExecuteQueryBefore(StatementProxy statement, String sql) { + statement.setLastExecuteStartNano(); + } + + @Override + protected void statementExecuteAfter(StatementProxy statement, String sql, boolean firstResult) { + statement.setLastExecuteTimeNano(); + } + + @Override + protected void statementExecuteBatchAfter(StatementProxy statement, int[] result) { + statement.setLastExecuteTimeNano(); + } + + @Override + protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) { + statement.setLastExecuteTimeNano(); + } + + @Override + protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) { + statement.setLastExecuteTimeNano(); + } + + @Override + public void statement_close(FilterChain chain, StatementProxy statement) throws SQLException { + // 先调用父类关闭 statement + super.statement_close(chain, statement); + // 支持动态开启 + if (!properties.isShowSql()) { + return; + } + + // 是否开启调试 + if (!log.isInfoEnabled()) { + return; + } + + // 打印可执行的 sql + String sql = statement.getBatchSql(); + // sql 为空直接返回 + if (StringUtils.isEmpty(sql)) { + return; + } + int parametersSize = statement.getParametersSize(); + List parameters = new ArrayList<>(parametersSize); + for (int i = 0; i < parametersSize; ++i) { + // 转换参数,处理 java8 时间 + parameters.add(getJdbcParameter(statement.getParameter(i))); + } + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + String formattedSql = SQLUtils.format(sql, DbType.of(dbType), parameters, FORMAT_OPTION); + printSql(formattedSql, statement); + } + + private static Object getJdbcParameter(JdbcParameter jdbcParam) { + if (jdbcParam == null) { + return null; + } + Object value = jdbcParam.getValue(); + // 处理 java8 时间 + if (value instanceof TemporalAccessor) { + return value.toString(); + } + return value; + } + + private static void printSql(String sql, StatementProxy statement) { + // 打印 sql + String sqlLogger = "\n\n======= Sql Logger ======================" + "\n{}" + + "\n======= Sql Execute Time: {} =======\n"; + log.info(sqlLogger, sql.trim(), format(statement.getLastExecuteTimeNano())); + } + + /** + * 格式化执行时间,单位为 ms 和 s,保留三位小数 + * @param nanos 纳秒 + * @return 格式化后的时间 + */ + private static String format(long nanos) { + if (nanos < 1) { + return "0ms"; + } + double millis = (double) nanos / (1000 * 1000); + // 不够 1 ms,最小单位为 ms + if (millis > 1000) { + return String.format("%.3fs", millis / 1000); + } + else { + return String.format("%.3fms", millis); + } + } + +} diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/MybatisPlusConfiguration.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/MybatisPlusConfiguration.java index 160efafd4..be4e80d01 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/MybatisPlusConfiguration.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/MybatisPlusConfiguration.java @@ -17,13 +17,10 @@ package com.pig4cloud.pigx.common.data.mybatis; -import java.util.List; - -import javax.sql.DataSource; - import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.pig4cloud.pigx.common.data.config.PigxMybatisProperties; import com.pig4cloud.pigx.common.data.datascope.DataScopeHandle; import com.pig4cloud.pigx.common.data.datascope.DataScopeInnerInterceptor; import com.pig4cloud.pigx.common.data.datascope.DataScopeSqlInjector; @@ -36,11 +33,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import javax.sql.DataSource; +import java.util.List; + /** * @author lengleng * @date 2020-02-08 @@ -48,6 +49,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @ConditionalOnBean(DataSource.class) @AutoConfigureAfter(DataSourceAutoConfiguration.class) +@EnableConfigurationProperties(PigxMybatisProperties.class) public class MybatisPlusConfiguration implements WebMvcConfigurer { /** @@ -110,4 +112,13 @@ public class MybatisPlusConfiguration implements WebMvcConfigurer { return new DataScopeSqlInjector(); } + /** + * SQL 日志格式化 + * @return DruidSqlLogFilter + */ + @Bean + public DruidSqlLogFilter sqlLogFilter(PigxMybatisProperties properties) { + return new DruidSqlLogFilter(properties); + } + }