java实现校验sql中,表字段在表里是否都存在,不存在的给删除掉

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);
    }
}

🔧 核心特性

  1. 多表支持:自动识别SQL中的所有表(包括JOIN表)
  2. 别名处理:正确处理表别名和字段别名
  3. 字段验证:验证SELECT字段、WHERE条件和JOIN条件中的所有字段
  4. 智能删除:自动删除不存在的字段,同时保持SQL语法正确
  5. 递归处理:深度遍历SQL语法树,处理嵌套表达式
  6. 详细报告:提供删除字段的详细列表和警告信息

📋 处理逻辑

  1. 表识别:从FROM和JOIN子句中提取所有表和别名
  2. 字段验证:对于每个字段,确定其所属的表并验证存在性
  3. 条件处理:递归处理WHERE条件和JOIN条件中的表达式
  4. 结果优化:删除无效字段后重新构建SQL

⚠️ 注意事项

  1. 依赖:需要JSqlParser库

    xml 复制代码
    <dependency>
        <groupId>com.github.jsqlparser</groupId>
        <artifactId>jsqlparser</artifactId>
        <version>4.5</version>
    </dependency>
  2. 性能:首次验证时会缓存表结构信息,提高后续验证速度

  3. 限制:主要针对SELECT语句,对于复杂的子查询、UNION等可能需要额外处理

相关推荐
编程火箭车1 小时前
【Java SE 基础学习打卡】15 分隔符、标识符与关键字
java·java入门·标识符·关键字·编程基础·分隔符·语法规则
灰色人生qwer1 小时前
idea teminal和 window cmd 输出java version不一致
java·ide·intellij-idea
WayneJoon.H2 小时前
Java反序列化 CC7链分析
java·安全·网络安全·cc链·反序列化
baivfhpwxf20232 小时前
删除数据表SQL,不是删除数据,是删除表结构
数据库·sql
liu_bees2 小时前
Jenkins 中修改 admin 账号密码的正确位置与方法
java·运维·tomcat·jenkins
明洞日记2 小时前
【设计模式手册011】享元模式 - 共享细粒度对象的高效之道
java·设计模式·享元模式
码界奇点2 小时前
深入解析MySQL6存储过程游标与触发器的实战应用与性能优化
数据库·sql·性能优化·七牛云存储
G皮T2 小时前
【Java】Java 运行时数据区域(一):名词概念
java·jvm·runtime·运行时·运行时数据区域
z***y8623 小时前
Java数据挖掘开发
java·开发语言·数据挖掘