当前位置: 首页 > news >正文

Sql语句解析工具类

需求:

项目 web-sql模块,需要根据 sql 解析获取数据库表,然后对(金库)表权限进行校验。
金库表:用户查询该表前需要审批。

一、Druid (推荐)

添加依赖:

<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version>
</dependency>

工具类:

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.*;import java.util.ArrayList;
import java.util.List;/*** @author NanNan Wang*/
public class SqlUtil {public static List<String> getTableNamesFromSQL(String sql, String dbType) {List<String> tableNames = new ArrayList<>();// 解析 SQL 语句List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);for (SQLStatement stmt : stmtList) {if (stmt instanceof SQLSelectStatement) {SQLSelectStatement selectStatement = (SQLSelectStatement) stmt;SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) selectStatement.getSelect().getQuery();extractTableNames(queryBlock.getFrom(), tableNames);} else if (stmt instanceof SQLInsertStatement) {SQLInsertStatement insertStatement = (SQLInsertStatement) stmt;tableNames.add(insertStatement.getTableName().getSimpleName());} else if (stmt instanceof SQLUpdateStatement) {SQLUpdateStatement updateStatement = (SQLUpdateStatement) stmt;tableNames.add(updateStatement.getTableName().getSimpleName());} else if (stmt instanceof SQLDeleteStatement) {SQLDeleteStatement deleteStatement = (SQLDeleteStatement) stmt;tableNames.add(deleteStatement.getTableName().getSimpleName());}}return tableNames;}private static void extractTableNames(SQLTableSource tableSource, List<String> tableNames) {if (tableSource instanceof SQLExprTableSource) {// 如果是简单表名,直接添加SQLExprTableSource exprTableSource = (SQLExprTableSource) tableSource;tableNames.add(exprTableSource.getTableName());} else if (tableSource instanceof SQLJoinTableSource) {// 如果是 JOIN,递归获取左表和右表SQLJoinTableSource joinTableSource = (SQLJoinTableSource) tableSource;extractTableNames(joinTableSource.getLeft(), tableNames);extractTableNames(joinTableSource.getRight(), tableNames);} else if (tableSource instanceof SQLSubqueryTableSource) {// 如果是子查询,递归处理子查询中的表SQLSelect subSelect = ((SQLSubqueryTableSource) tableSource).getSelect();extractTableNames(subSelect.getQueryBlock().getFrom(), tableNames);}}
}

测试样例

 @Testvoid getTableNamesFromPGSQL() {String sql = "SELECT e.id, e.name, d.name AS dept_name FROM schema.employee e " +"LEFT JOIN schema.department d ON e.dept_id = d.id WHERE e.salary > 1000";List<String> tableNames = SqlUtil.getTableNamesFromSQL(sql, JdbcConstants.POSTGRESQL.name());System.out.println("Tables: " + tableNames); //Tables: [employee, department]}

二、JSqlParser

添加依赖:

<dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>4.6</version>
</dependency>

工具类:

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.util.TablesNamesFinder;import java.util.ArrayList;
import java.util.List;public class SqlUtil {/*** 使用 JSqlParser 根据 SQL 和数据库类型解析 SQL 中的所有表名* @param sql SQL 语句* @return 表名列表* @throws Exception 解析异常*/public static List<String> extractTableNames(String sql) {// 使用 JSqlParser 解析 SQL 语句Statement statement = null;try {statement = CCJSqlParserUtil.parse(sql);} catch (JSQLParserException e) {throw new RuntimeException(e);}// 使用 TablesNamesFinder 提取表名TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();return tablesNamesFinder.getTableList(statement);}
}

重要:要注意如果是 PostgreSQL 这里支持 模式(schema) 的需要进一步处理!
例如:

@Test
void extractPgTableNames () {String sql = "SELECT e.id, e.name, d.name AS dept_name FROM schema.employee e " +"LEFT JOIN schema.department d ON e.dept_id = d.id WHERE e.salary > 1000";List<String> tableNames = SqlUtil.extractTableNames(sql);System.out.println("Tables: " + tableNames); //Tables: [schema.employee, schema.department]
}

http://www.mrgr.cn/news/47799.html

相关文章:

  • 找到一个或多个多重定义的符号的问题
  • 网络安全 信息收集入门
  • HTML+CSS+JS制作中国传统节日主题网站(内附源码,含5个页面)
  • 【LeetCode: 560. 和为 K 的子数组 + 前缀和 + 哈希表】
  • maven的简单介绍
  • GJSON 使用指南
  • Kafka如何实现高可用
  • 在windows中将文件的扩展名或文件类型显示出来
  • Docker 的数据管理
  • 根据时间复制和打包远程电脑共享文件夹下的文件,并根据选择的时间段筛选
  • 建站:腾讯云+宝塔linux+xftp
  • windows安装RabbitMQ
  • 【c数据结构】队列详解!(模拟实现、OJ练习实操)
  • 【GPT提问技巧】学会提问才是关键!如何让AI用Python生成完整的2048小游戏实战步骤!
  • uniapp 整合 OpenLayer3 - 加载百度地图
  • 一文看懂什么是CPC认证
  • 【优选算法】(第三十三篇)
  • 如何配制PEI转染试剂
  • springboot自定义starter
  • YOLOv10改进目录一览 | 涉及卷积层、轻量化、注意力、损失函数、Backbone、SPPF、Neck、检测头等全方位改进方向
  • 免费又好用的保护网站WAF,基于语义引擎的waf雷池社区版推荐
  • 自然语言处理问答系统
  • 春日编程助手:Spring Boot课程答疑服务
  • 做好不如计划好:生成计划管理
  • YOLOv11改进策略【注意力机制篇】| 2024 SCSA-CBAM 空间和通道的协同注意模块
  • 【Canvas与诗词】要做一棵树,站成永恒