Bläddra i källkod

:zap: user list

shc 9 månader sedan
förälder
incheckning
994b7bf22a

+ 6 - 1
hnqz-common/hnqz-common-bom/pom.xml

@@ -19,7 +19,7 @@
         <hnqz.version>3.9.0</hnqz.version>
         <mybatis-plus.version>3.4.2</mybatis-plus.version>
         <dynamic-ds.version>3.0.0</dynamic-ds.version>
-        <druid.version>1.1.22</druid.version>
+        <druid.version>1.2.20</druid.version>
         <mysql.connector.version>8.0.20</mysql.connector.version>
         <mp.weixin.version>4.6.0</mp.weixin.version>
         <groovy.version>3.0.3</groovy.version>
@@ -33,6 +33,11 @@
 
     <dependencyManagement>
         <dependencies>
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
             <dependency>
                 <groupId>com.qunzhixinxi</groupId>
                 <artifactId>hnqz-common-core</artifactId>

+ 5 - 0
hnqz-common/hnqz-common-data/pom.xml

@@ -15,6 +15,11 @@
 
 
 	<dependencies>
+		<!-- druid 连接池 -->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>druid</artifactId>
+		</dependency>
 		<!--工具类核心包-->
 		<dependency>
 			<groupId>com.qunzhixinxi</groupId>

+ 189 - 0
hnqz-common/hnqz-common-data/src/main/java/com/qunzhixinxi/hnqz/common/data/mybatis/DruidSqlLogFilter.java

@@ -0,0 +1,189 @@
+package com.qunzhixinxi.hnqz.common.data.mybatis;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+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.sql.ast.SQLStatement;
+import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor;
+import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
+import com.alibaba.druid.stat.TableStat;
+import com.alibaba.druid.util.StringUtils;
+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;
+import java.util.Map;
+
+@Slf4j
+@RequiredArgsConstructor
+public class DruidSqlLogFilter extends FilterEventAdapter {
+
+    private static final SQLUtils.FormatOption FORMAT_OPTION = new SQLUtils.FormatOption(false, false);
+
+    private final HnqzMybatisProperties 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;
+        }
+
+        String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType();
+
+        // 判断表名是配置了匹配过滤
+        if (CollUtil.isNotEmpty(properties.getSkipTable())) {
+            List<String> skipTableList = properties.getSkipTable();
+
+            List<String> tableNameList = getTablesBydruid(sql, dbType);
+            if (tableNameList.stream()
+                .anyMatch(tableName -> StrUtil.containsAnyIgnoreCase(tableName,
+                    ArrayUtil.toArray(skipTableList, String.class)))) {
+                return;
+            }
+        }
+
+        int parametersSize = statement.getParametersSize();
+        List<Object> parameters = new ArrayList<>(parametersSize);
+        for (int i = 0; i < parametersSize; ++i) {
+            // 转换参数,处理 java8 时间
+            parameters.add(getJdbcParameter(statement.getParameter(i)));
+        }
+        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 =
+                        
+            "======= 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);
+        }
+    }
+
+    /**
+     * 从SQL中提取表名(sql中出现的所有表)
+     *
+     * @param sql    sql语句
+     * @param dbType dbType
+     * @return List<String>
+     */
+    public static List<String> getTablesBydruid(String sql, String dbType) {
+        List<String> result = new ArrayList<String>();
+        List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);
+        for (SQLStatement stmt : stmtList) {
+            // 也可以用更精确的解析器,如MySqlSchemaStatVisitor
+            SchemaStatVisitor visitor;
+            // SQL server 数据库特殊处理
+            if (DbType.sqlserver.name().equalsIgnoreCase(dbType)) {
+                visitor = new SQLServerSchemaStatVisitor();
+            } else {
+                visitor = new SchemaStatVisitor();
+            }
+            stmt.accept(visitor);
+            Map<TableStat.Name, TableStat> tables = visitor.getTables();
+            for (TableStat.Name name : tables.keySet()) {
+                result.add(name.getName());
+            }
+        }
+        return result;
+    }
+
+}

+ 25 - 0
hnqz-common/hnqz-common-data/src/main/java/com/qunzhixinxi/hnqz/common/data/mybatis/HnqzMybatisProperties.java

@@ -0,0 +1,25 @@
+package com.qunzhixinxi.hnqz.common.data.mybatis;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@RefreshScope
+@ConfigurationProperties("lettuce.mybatis")
+public class HnqzMybatisProperties {
+
+    /**
+     * 是否打印可执行 sql
+     */
+    private boolean showSql = true;
+
+    /**
+     * 跳过表
+     */
+    private List<String> skipTable = new ArrayList<>();
+
+}

+ 10 - 0
hnqz-common/hnqz-common-data/src/main/java/com/qunzhixinxi/hnqz/common/data/mybatis/MybatisPlusConfiguration.java

@@ -85,4 +85,14 @@ public class MybatisPlusConfiguration {
 		return new DataScopeSqlInjector();
 	}
 
+	/**
+	 * SQL 日志格式化
+	 *
+	 * @return DruidSqlLogFilter
+	 */
+	@Bean
+	public DruidSqlLogFilter sqlLogFilter(HnqzMybatisProperties properties) {
+		return new DruidSqlLogFilter(properties);
+	}
+
 }