java
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;
public class SqlFieldValidator {
private Connection connection;
public SqlFieldValidator(Connection connection) {
this.connection = connection;
}
public static class ValidationResult {
private boolean valid;
private String originalSql;
private String optimizedSql;
private List<String> warnings;
private List<String> removedFields;
public ValidationResult() {
this.warnings = new ArrayList<>();
this.removedFields = new ArrayList<>();
}
public boolean isValid() { return valid; }
public void setValid(boolean valid) { this.valid = valid; }
public String getOriginalSql() { return originalSql; }
public void setOriginalSql(String originalSql) { this.originalSql = originalSql; }
public String getOptimizedSql() { return optimizedSql; }
public void setOptimizedSql(String optimizedSql) { this.optimizedSql = optimizedSql; }
public List<String> getWarnings() { return warnings; }
public List<String> getRemovedFields() { return removedFields; }
public void addWarning(String warning) {
this.warnings.add(warning);
}
public void addRemovedField(String field) {
this.removedFields.add(field);
}
}
/**
* 表字段缓存
*/
private static class TableColumns {
private Map<String, Set<String>> tableColumnCache = new HashMap<>();
public Set<String> getColumns(Connection conn, String tableName) throws SQLException {
String key = tableName.toLowerCase();
if (!tableColumnCache.containsKey(key)) {
tableColumnCache.put(key, loadColumnsFromDB(conn, tableName));
}
return tableColumnCache.get(key);
}
private Set<String> loadColumnsFromDB(Connection conn, String tableName) throws SQLException {
Set<String> columns = new HashSet<>();
DatabaseMetaData metaData = conn.getMetaData();
try (ResultSet rs = metaData.getColumns(null, null, tableName, null)) {
while (rs.next()) {
columns.add(rs.getString("COLUMN_NAME").toLowerCase());
}
}
return columns;
}
public void clearCache() {
tableColumnCache.clear();
}
}
/**
* 表别名映射
*/
private static class TableAliasMapper {
private Map<String, String> aliasToTable = new HashMap<>();
private Map<String, String> tableToAlias = new HashMap<>();
public void addTable(String tableName, String alias) {
if (alias != null) {
aliasToTable.put(alias.toLowerCase(), tableName.toLowerCase());
}
tableToAlias.put(tableName.toLowerCase(), alias);
}
public String getTableName(String aliasOrTableName) {
String key = aliasOrTableName.toLowerCase();
return aliasToTable.getOrDefault(key, key);
}
public boolean containsTable(String tableName) {
return tableToAlias.containsKey(tableName.toLowerCase()) ||
aliasToTable.containsKey(tableName.toLowerCase());
}
}
/**
* 主验证方法
*/
public ValidationResult validateAndRemoveInvalidFields(String sql) {
ValidationResult result = new ValidationResult();
result.setOriginalSql(sql);
try {
// 1. 语法验证
if (!validateSqlSyntax(sql)) {
result.setValid(false);
result.addWarning("SQL语法错误");
return result;
}
// 2. 解析SQL并验证字段
Statement statement = CCJSqlParserUtil.parse(sql);
if (statement instanceof Select) {
String optimizedSql = processSelectStatement((Select) statement, result);
result.setOptimizedSql(optimizedSql);
result.setValid(true);
} else {
result.setValid(false);
result.addWarning("仅支持SELECT语句验证");
}
} catch (Exception e) {
result.setValid(false);
result.addWarning("SQL解析失败: " + e.getMessage());
}
return result;
}
/**
* 处理SELECT语句
*/
private String processSelectStatement(Select select, ValidationResult result) throws SQLException {
SelectBody selectBody = select.getSelectBody();
if (!(selectBody instanceof PlainSelect)) {
result.addWarning("仅支持简单SELECT语句,不支持复杂查询");
return result.getOriginalSql();
}
PlainSelect plainSelect = (PlainSelect) selectBody;
TableColumns tableColumns = new TableColumns();
// 1. 收集所有表和别名
TableAliasMapper tableMapper = collectTablesAndAliases(plainSelect);
// 2. 验证表是否存在
for (String tableName : tableMapper.aliasToTable.values()) {
if (!isTableExists(tableName)) {
result.addWarning("表 '" + tableName + "' 不存在");
return result.getOriginalSql();
}
}
// 3. 处理SELECT字段
processSelectItems(plainSelect, tableMapper, tableColumns, result);
// 4. 处理WHERE条件
processWhereClause(plainSelect, tableMapper, tableColumns, result);
// 5. 处理JOIN条件
processJoinClauses(plainSelect, tableMapper, tableColumns, result);
return plainSelect.toString();
}
/**
* 收集所有表和别名
*/
private TableAliasMapper collectTablesAndAliases(PlainSelect plainSelect) {
TableAliasMapper mapper = new TableAliasMapper();
// 主表
if (plainSelect.getFromItem() instanceof Table) {
Table fromTable = (Table) plainSelect.getFromItem();
mapper.addTable(fromTable.getName(), fromTable.getAlias() != null ?
fromTable.getAlias().getName() : null);
}
// JOIN表
if (plainSelect.getJoins() != null) {
for (Join join : plainSelect.getJoins()) {
if (join.getRightItem() instanceof Table) {
Table joinTable = (Table) join.getRightItem();
mapper.addTable(joinTable.getName(), joinTable.getAlias() != null ?
joinTable.getAlias().getName() : null);
}
}
}
return mapper;
}
/**
* 处理SELECT字段
*/
private void processSelectItems(PlainSelect plainSelect, TableAliasMapper tableMapper,
TableColumns tableColumns, ValidationResult result) throws SQLException {
List<SelectItem> selectItems = plainSelect.getSelectItems();
List<SelectItem> validSelectItems = new ArrayList<>();
for (SelectItem item : selectItems) {
if (item instanceof SelectExpressionItem) {
SelectExpressionItem exprItem = (SelectExpressionItem) item;
if (isExpressionValid(exprItem.getExpression(), tableMapper, tableColumns, result)) {
validSelectItems.add(item);
}
} else {
// 处理 SELECT * 等情况
validSelectItems.add(item);
}
}
// 如果所有字段都被删除了,添加一个默认字段
if (validSelectItems.isEmpty()) {
String defaultTable = getFirstTable(tableMapper);
if (defaultTable != null) {
Set<String> columns = tableColumns.getColumns(connection, defaultTable);
if (!columns.isEmpty()) {
Column defaultColumn = new Column(columns.iterator().next());
validSelectItems.add(new SelectExpressionItem(defaultColumn));
result.addWarning("所有查询字段均无效,已使用默认字段");
}
}
}
plainSelect.setSelectItems(validSelectItems);
}
/**
* 处理WHERE条件
*/
private void processWhereClause(PlainSelect plainSelect, TableAliasMapper tableMapper,
TableColumns tableColumns, ValidationResult result) throws SQLException {
Expression whereExpr = plainSelect.getWhere();
if (whereExpr != null) {
Expression validWhereExpr = processExpression(whereExpr, tableMapper, tableColumns, result);
plainSelect.setWhere(validWhereExpr);
}
}
/**
* 处理JOIN条件
*/
private void processJoinClauses(PlainSelect plainSelect, TableAliasMapper tableMapper,
TableColumns tableColumns, ValidationResult result) throws SQLException {
if (plainSelect.getJoins() != null) {
for (Join join : plainSelect.getJoins()) {
Expression joinExpr = join.getOnExpression();
if (joinExpr != null) {
Expression validJoinExpr = processExpression(joinExpr, tableMapper, tableColumns, result);
join.setOnExpression(validJoinExpr);
}
}
}
}
/**
* 处理表达式(递归)
*/
private Expression processExpression(Expression expr, TableAliasMapper tableMapper,
TableColumns tableColumns, ValidationResult result) throws SQLException {
if (expr == null) {
return null;
}
// 处理列引用
if (expr instanceof Column) {
Column column = (Column) expr;
if (isColumnValid(column, tableMapper, tableColumns)) {
return expr;
} else {
result.addRemovedField(column.toString());
return null;
}
}
// 处理二元表达式(AND, OR, =, >, < 等)
if (expr instanceof BinaryExpression) {
BinaryExpression binaryExpr = (BinaryExpression) expr;
Expression left = processExpression(binaryExpr.getLeftExpression(), tableMapper, tableColumns, result);
Expression right = processExpression(binaryExpr.getRightExpression(), tableMapper, tableColumns, result);
if (left == null && right == null) {
return null;
} else if (left == null) {
return right;
} else if (right == null) {
return left;
} else {
binaryExpr.setLeftExpression(left);
binaryExpr.setRightExpression(right);
return binaryExpr;
}
}
// 处理括号表达式
if (expr instanceof Parenthesis) {
Parenthesis parenthesis = (Parenthesis) expr;
Expression innerExpr = processExpression(parenthesis.getExpression(), tableMapper, tableColumns, result);
if (innerExpr == null) {
return null;
} else {
parenthesis.setExpression(innerExpr);
return parenthesis;
}
}
// 处理函数等其他表达式
return expr;
}
/**
* 检查表达式是否有效
*/
private boolean isExpressionValid(Expression expr, TableAliasMapper tableMapper,
TableColumns tableColumns, ValidationResult result) throws SQLException {
if (expr instanceof Column) {
return isColumnValid((Column) expr, tableMapper, tableColumns);
} else if (expr instanceof BinaryExpression) {
BinaryExpression binaryExpr = (BinaryExpression) expr;
return isExpressionValid(binaryExpr.getLeftExpression(), tableMapper, tableColumns, result) &&
isExpressionValid(binaryExpr.getRightExpression(), tableMapper, tableColumns, result);
} else if (expr instanceof Parenthesis) {
Parenthesis parenthesis = (Parenthesis) expr;
return isExpressionValid(parenthesis.getExpression(), tableMapper, tableColumns, result);
}
// 其他类型的表达式(函数、字面量等)默认有效
return true;
}
/**
* 检查列是否有效
*/
private boolean isColumnValid(Column column, TableAliasMapper tableMapper,
TableColumns tableColumns) throws SQLException {
String columnName = column.getColumnName();
String tableNameOrAlias = column.getTable() != null ? column.getTable().getName() : null;
// 如果没有指定表名,检查所有表
if (tableNameOrAlias == null) {
for (String tableName : tableMapper.aliasToTable.values()) {
Set<String> columns = tableColumns.getColumns(connection, tableName);
if (columns.contains(columnName.toLowerCase())) {
return true;
}
}
return false;
}
// 如果指定了表名或别名
String actualTableName = tableMapper.getTableName(tableNameOrAlias);
if (!tableMapper.containsTable(actualTableName)) {
return false;
}
Set<String> columns = tableColumns.getColumns(connection, actualTableName);
return columns.contains(columnName.toLowerCase());
}
/**
* 获取第一个表名
*/
private String getFirstTable(TableAliasMapper tableMapper) {
if (!tableMapper.aliasToTable.isEmpty()) {
return tableMapper.aliasToTable.values().iterator().next();
}
return null;
}
/**
* 验证表是否存在
*/
private boolean isTableExists(String tableName) throws SQLException {
DatabaseMetaData metaData = connection.getMetaData();
try (ResultSet rs = metaData.getTables(null, null, tableName, new String[]{"TABLE"})) {
return rs.next();
}
}
/**
* 基础SQL语法验证
*/
private boolean validateSqlSyntax(String sql) {
try {
CCJSqlParserUtil.parse(sql);
return true;
} catch (Exception e) {
return false;
}
}
}
🧪 使用示例
java
public class SqlValidatorDemo {
public static void main(String[] args) {
try (Connection conn = createConnection()) {
SqlFieldValidator validator = new SqlFieldValidator(conn);
// 测试SQL - 包含不存在字段的复杂查询
String testSql = "select id,name,age,sex from table_name";
SqlFieldValidator.ValidationResult result = validator.validateAndRemoveInvalidFields(testSql);
System.out.println("原始SQL:");
System.out.println(result.getOriginalSql());
System.out.println("\n优化后SQL:");
System.out.println(result.getOptimizedSql());
System.out.println("\n验证结果: " + (result.isValid() ? "✅ 有效" : "❌ 无效"));
if (!result.getWarnings().isEmpty()) {
System.out.println("\n警告信息:");
for (String warning : result.getWarnings()) {
System.out.println(" ⚠️ " + warning);
}
}
if (!result.getRemovedFields().isEmpty()) {
System.out.println("\n删除的字段:");
for (String field : result.getRemovedFields()) {
System.out.println(" ❌ " + field);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static Connection createConnection() throws SQLException {
// 替换为您的数据库连接信息
String url = "jdbc:mysql://localhost:3306/your_database";
String username = "your_username";
String password = "your_password";
return DriverManager.getConnection(url, username, password);
}
}
🔧 核心特性
- 多表支持:自动识别SQL中的所有表(包括JOIN表)
- 别名处理:正确处理表别名和字段别名
- 字段验证:验证SELECT字段、WHERE条件和JOIN条件中的所有字段
- 智能删除:自动删除不存在的字段,同时保持SQL语法正确
- 递归处理:深度遍历SQL语法树,处理嵌套表达式
- 详细报告:提供删除字段的详细列表和警告信息
📋 处理逻辑
- 表识别:从FROM和JOIN子句中提取所有表和别名
- 字段验证:对于每个字段,确定其所属的表并验证存在性
- 条件处理:递归处理WHERE条件和JOIN条件中的表达式
- 结果优化:删除无效字段后重新构建SQL
⚠️ 注意事项
-
依赖:需要JSqlParser库
xml<dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>4.5</version> </dependency> -
性能:首次验证时会缓存表结构信息,提高后续验证速度
-
限制:主要针对SELECT语句,对于复杂的子查询、UNION等可能需要额外处理