想要实现一个插件功能,得到请求与表字段之间的映射关系,比如:
功能A
表1
字段a
字段b
功能B
表1
字段c
表2
字段d
字段e
...
思路主要类似分布式日志一样,各服务请求透传一个唯一标识,比如请求路径,然后再通过拦截器获取具体执行的Sql语句,通过解析sql来获取表及字段,从而构建映射关系。
刚开始用以为自己去遍历递归,后来查到神器JSqlParse,看到Visitor设计模式实现效果,感觉真心强。
JDK1.8
Maven版本
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.6</version>
</dependency>
对于复杂的Sql处理,各种嵌套、函数、子查询,都可解析,只要自己去实现各个具体的方法。
以下是仅是解析Sql简单的例子,有的地方还需要根据自己实际需求去调整,仅供参考。
package test;
import java.util.ArrayList;
import java.util.List;
import net.sf.jsqlparser.expression.AllValue;
import net.sf.jsqlparser.expression.AnalyticExpression;
import net.sf.jsqlparser.expression.AnyComparisonExpression;
import net.sf.jsqlparser.expression.ArrayConstructor;
import net.sf.jsqlparser.expression.ArrayExpression;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.CaseExpression;
import net.sf.jsqlparser.expression.CastExpression;
import net.sf.jsqlparser.expression.CollateExpression;
import net.sf.jsqlparser.expression.ConnectByRootOperator;
import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
import net.sf.jsqlparser.expression.DateValue;
import net.sf.jsqlparser.expression.DoubleValue;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.expression.ExtractExpression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.HexValue;
import net.sf.jsqlparser.expression.IntervalExpression;
import net.sf.jsqlparser.expression.JdbcNamedParameter;
import net.sf.jsqlparser.expression.JdbcParameter;
import net.sf.jsqlparser.expression.JsonAggregateFunction;
import net.sf.jsqlparser.expression.JsonExpression;
import net.sf.jsqlparser.expression.JsonFunction;
import net.sf.jsqlparser.expression.KeepExpression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.MySQLGroupConcat;
import net.sf.jsqlparser.expression.NextValExpression;
import net.sf.jsqlparser.expression.NotExpression;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.NumericBind;
import net.sf.jsqlparser.expression.OracleHierarchicalExpression;
import net.sf.jsqlparser.expression.OracleHint;
import net.sf.jsqlparser.expression.OracleNamedFunctionParameter;
import net.sf.jsqlparser.expression.OverlapsCondition;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.RowConstructor;
import net.sf.jsqlparser.expression.RowGetExpression;
import net.sf.jsqlparser.expression.SafeCastExpression;
import net.sf.jsqlparser.expression.SignedExpression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.TimeKeyExpression;
import net.sf.jsqlparser.expression.TimeValue;
import net.sf.jsqlparser.expression.TimestampValue;
import net.sf.jsqlparser.expression.TimezoneExpression;
import net.sf.jsqlparser.expression.TryCastExpression;
import net.sf.jsqlparser.expression.UserVariable;
import net.sf.jsqlparser.expression.ValueListExpression;
import net.sf.jsqlparser.expression.VariableAssignment;
import net.sf.jsqlparser.expression.WhenClause;
import net.sf.jsqlparser.expression.XMLSerializeExpr;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseRightShift;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision;
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.conditional.XorExpression;
import net.sf.jsqlparser.expression.operators.relational.Between;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.FullTextSearch;
import net.sf.jsqlparser.expression.operators.relational.GeometryDistance;
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsListVisitor;
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.Matches;
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
import net.sf.jsqlparser.expression.operators.relational.NamedExpressionList;
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator;
import net.sf.jsqlparser.expression.operators.relational.RegExpMySQLOperator;
import net.sf.jsqlparser.expression.operators.relational.SimilarToExpression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.AllColumns;
import net.sf.jsqlparser.statement.select.AllTableColumns;
import net.sf.jsqlparser.statement.select.FromItemVisitor;
import net.sf.jsqlparser.statement.select.LateralSubSelect;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.OrderByVisitor;
import net.sf.jsqlparser.statement.select.ParenthesisFromItem;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import net.sf.jsqlparser.statement.select.SelectItemVisitor;
import net.sf.jsqlparser.statement.select.SelectVisitor;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.select.SubJoin;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.statement.select.TableFunction;
import net.sf.jsqlparser.statement.select.ValuesList;
import net.sf.jsqlparser.statement.select.WithItem;
import net.sf.jsqlparser.statement.values.ValuesStatement;
public class SelectTablesColumns implements SelectVisitor,SelectItemVisitor,FromItemVisitor,ExpressionVisitor,ItemsListVisitor,OrderByVisitor{
public SelectTablesColumns(String id){
this.id = id;
}
private String id;
private List<String> tables;
public List<String> getTableList(Select select) {
tables = new ArrayList<String>();
select.getSelectBody().accept(this);
return tables;
}
public void visit(Table tableName) {
String tableWholeName = tableName.getDBLinkName();
tables.add(tableWholeName+" "+tableName.getAlias());
}
public void visit(SubSelect subSelect) {
subSelect.getSelectBody().accept(this);
}
@Override
public void visit(PlainSelect plainSelect) {
if(null!=plainSelect.getSelectItems()){
plainSelect.getSelectItems().stream().forEach(o->o.accept(this));
}
if(null!=plainSelect.getFromItem()){
plainSelect.getFromItem().accept(this);
}
if(null!=plainSelect.getJoins()){
plainSelect.getJoins().stream().forEach(o->o.getRightItem().accept(this));
}
if(null!=plainSelect.getWhere()){
plainSelect.getWhere().accept(this);
}
if(null!=plainSelect.getOrderByElements()){
plainSelect.getOrderByElements().stream().forEach(o->o.accept(this));
}
}
@Override
public void visit(SetOperationList setOpList) {
System.out.println("SetOperationList");
}
@Override
public void visit(WithItem withItem) {
System.out.println("WithItem");
}
@Override
public void visit(ValuesStatement aThis) {
System.out.println("ValuesStatement");
}
@Override
public void visit(SelectExpressionItem selectExpressionItem) {
System.out.println("SelectExpressionItem");
selectExpressionItem.getExpression().accept(this);
}
@Override
public void visit(SubJoin subjoin) {
System.out.println("SubJoin:");
}
@Override
public void visit(LateralSubSelect lateralSubSelect) {
System.out.println("LateralSubSelect");
}
@Override
public void visit(ValuesList valuesList) {
System.out.println("ValuesList");
}
@Override
public void visit(TableFunction tableFunction) {
System.out.println("TableFunction");
}
@Override
public void visit(ParenthesisFromItem aThis) {
System.out.println("ParenthesisFromItem");
}
@Override
public void visit(BitwiseRightShift aThis) {
System.out.println("BitwiseRightShift");
}
@Override
public void visit(BitwiseLeftShift aThis) {
System.out.println("BitwiseLeftShift");
}
@Override
public void visit(NullValue nullValue) {
System.out.println("NullValue");
}
@Override
public void visit(Function function) {
System.out.println("Function");
//SUB_STR(ID2,1,6)
System.out.println(function.getMultipartName());//[SUB_STR]
// System.out.println(function.getParameters());// ID2,1,6
//
// System.out.println(function.getAttribute());//null
// System.out.println(function.getName());//SUB_STR
// System.out.println(function.getKeep());//null
// System.out.println(function.getNamedParameters());//null
// System.out.println();//null
if(null!=function.getParameters()){
function.getParameters().getExpressions().stream().forEach(o->o.accept(this));
}
}
@Override
public void visit(SignedExpression signedExpression) {
System.out.println("SignedExpression");
}
@Override
public void visit(JdbcParameter jdbcParameter) {
System.out.println("JdbcParameter");
}
@Override
public void visit(JdbcNamedParameter jdbcNamedParameter) {
System.out.println("JdbcNamedParameter");
}
@Override
public void visit(DoubleValue doubleValue) {
System.out.println("DoubleValue");
System.out.println("DoubleValue="+doubleValue);
}
@Override
public void visit(LongValue longValue) {
System.out.println("LongValue");
System.out.println("LongValue="+longValue);
}
@Override
public void visit(HexValue hexValue) {
System.out.println("HexValue");
System.out.println("HexValue="+hexValue);
}
@Override
public void visit(DateValue dateValue) {
System.out.println("DateValue");
System.out.println("DateValue="+dateValue);
}
@Override
public void visit(TimeValue timeValue) {
System.out.println("TimeValue");
System.out.println("TimeValue="+timeValue);
}
@Override
public void visit(TimestampValue timestampValue) {
System.out.println("TimestampValue");
System.out.println("TimestampValue="+timestampValue);
}
@Override
public void visit(Parenthesis parenthesis) {
System.out.println("Parenthesis");
System.out.println("Parenthesis="+parenthesis);
}
@Override
public void visit(StringValue stringValue) {
System.out.println("StringValue");
System.out.println("StringValue="+stringValue);
}
@Override
public void visit(Addition addition) {
System.out.println("Addition");
visitBinaryExpression(addition);
}
@Override
public void visit(Division division) {
System.out.println("Division");
visitBinaryExpression(division);
}
@Override
public void visit(IntegerDivision division) {
System.out.println("IntegerDivision");
visitBinaryExpression(division);
}
@Override
public void visit(Multiplication multiplication) {
System.out.println("Multiplication");
visitBinaryExpression(multiplication);
}
@Override
public void visit(Subtraction subtraction) {
System.out.println("Subtraction");
visitBinaryExpression(subtraction);
}
@Override
public void visit(AndExpression andExpression) {
System.out.println("AndExpression");
visitBinaryExpression(andExpression);
}
@Override
public void visit(OrExpression orExpression) {
System.out.println("OrExpression");
visitBinaryExpression(orExpression);
}
public void visitBinaryExpression(BinaryExpression binaryExpression) {
binaryExpression.getLeftExpression().accept(this);
binaryExpression.getRightExpression().accept(this);
}
@Override
public void visit(XorExpression orExpression) {
System.out.println("XorExpression");
visitBinaryExpression(orExpression);
}
@Override
public void visit(Between between) {
System.out.println("Between");
between.getBetweenExpressionStart().accept(this);
between.getBetweenExpressionEnd().accept(this);
}
@Override
public void visit(OverlapsCondition overlapsCondition) {
System.out.println("OverlapsCondition");
overlapsCondition.getLeft().getExpressions().stream().forEach(o->o.accept(this));
overlapsCondition.getRight().getExpressions().stream().forEach(o->o.accept(this));
}
@Override
public void visit(EqualsTo equalsTo) {
System.out.println("EqualsTo");
visitBinaryExpression(equalsTo);
}
@Override
public void visit(GreaterThan greaterThan) {
System.out.println("GreaterThan");
visitBinaryExpression(greaterThan);
}
@Override
public void visit(GreaterThanEquals greaterThanEquals) {
System.out.println("GreaterThanEquals");
visitBinaryExpression(greaterThanEquals);
}
@Override
public void visit(InExpression inExpression) {
System.out.println("InExpression");
inExpression.getLeftExpression().accept(this);
inExpression.getRightExpression().accept(this);
}
@Override
public void visit(FullTextSearch fullTextSearch) {
System.out.println("FullTextSearch");
}
@Override
public void visit(IsNullExpression isNullExpression) {
System.out.println("IsNullExpression");
}
@Override
public void visit(IsBooleanExpression isBooleanExpression) {
System.out.println("IsBooleanExpression");
}
@Override
public void visit(LikeExpression likeExpression) {
System.out.println("LikeExpression");
visitBinaryExpression(likeExpression);
}
@Override
public void visit(MinorThan minorThan) {
System.out.println("MinorThan");
visitBinaryExpression(minorThan);
}
@Override
public void visit(MinorThanEquals minorThanEquals) {
System.out.println("MinorThanEquals");
visitBinaryExpression(minorThanEquals);
}
@Override
public void visit(NotEqualsTo notEqualsTo) {
System.out.println("NotEqualsTo");
visitBinaryExpression(notEqualsTo);
}
@Override
public void visit(Column tableColumn) {
System.out.println("Column");
System.out.println(tableColumn.toString());
}
@Override
public void visit(CaseExpression caseExpression) {
System.out.println("CaseExpression");
}
@Override
public void visit(WhenClause whenClause) {
System.out.println("WhenClause");
}
@Override
public void visit(ExistsExpression existsExpression) {
System.out.println("ExistsExpression");
}
@Override
public void visit(AnyComparisonExpression anyComparisonExpression) {
System.out.println("AnyComparisonExpression");
}
@Override
public void visit(Concat concat) {
System.out.println("Concat");
visitBinaryExpression(concat);
}
@Override
public void visit(Matches matches) {
System.out.println("Matches");
visitBinaryExpression(matches);
}
@Override
public void visit(BitwiseAnd bitwiseAnd) {
System.out.println("BitwiseAnd");
visitBinaryExpression(bitwiseAnd);
}
@Override
public void visit(BitwiseOr bitwiseOr) {
System.out.println("BitwiseOr");
visitBinaryExpression(bitwiseOr);
}
@Override
public void visit(BitwiseXor bitwiseXor) {
System.out.println("BitwiseXor");
visitBinaryExpression(bitwiseXor);
}
@Override
public void visit(CastExpression cast) {
System.out.println("CastExpression");
}
@Override
public void visit(TryCastExpression cast) {
System.out.println("TryCastExpression");
}
@Override
public void visit(SafeCastExpression cast) {
System.out.println("SafeCastExpression");
}
@Override
public void visit(Modulo modulo) {
System.out.println("Modulo");
visitBinaryExpression(modulo);
}
@Override
public void visit(AnalyticExpression aexpr) {
System.out.println("AnalyticExpression");
}
@Override
public void visit(ExtractExpression eexpr) {
System.out.println("ExtractExpression");
}
@Override
public void visit(IntervalExpression iexpr) {
System.out.println("IntervalExpression");
}
@Override
public void visit(OracleHierarchicalExpression oexpr) {
System.out.println("OracleHierarchicalExpression");
}
@Override
public void visit(RegExpMatchOperator rexpr) {
System.out.println("RegExpMatchOperator");
visitBinaryExpression(rexpr);
}
@Override
public void visit(JsonExpression jsonExpr) {
System.out.println("JsonExpression");
}
@Override
public void visit(JsonOperator jsonExpr) {
System.out.println("JsonOperator");
visitBinaryExpression(jsonExpr);
}
@Override
public void visit(RegExpMySQLOperator regExpMySQLOperator) {
System.out.println("RegExpMySQLOperator");
visitBinaryExpression(regExpMySQLOperator);
}
@Override
public void visit(UserVariable var) {
System.out.println("UserVariable");
}
@Override
public void visit(NumericBind bind) {
System.out.println("NumericBind");
}
@Override
public void visit(KeepExpression aexpr) {
System.out.println("KeepExpression");
}
@Override
public void visit(MySQLGroupConcat groupConcat) {
System.out.println("MySQLGroupConcat");
}
@Override
public void visit(ValueListExpression valueList) {
System.out.println("ValueListExpression");
}
@Override
public void visit(RowConstructor rowConstructor) {
System.out.println("RowConstructor");
}
@Override
public void visit(RowGetExpression rowGetExpression) {
System.out.println("RowGetExpression");
}
@Override
public void visit(OracleHint hint) {
System.out.println("OracleHint");
}
@Override
public void visit(TimeKeyExpression timeKeyExpression) {
System.out.println("TimeKeyExpression");
}
@Override
public void visit(DateTimeLiteralExpression literal) {
System.out.println("DateTimeLiteralExpression");
}
@Override
public void visit(NotExpression aThis) {
System.out.println("NotExpression");
}
@Override
public void visit(NextValExpression aThis) {
System.out.println("NextValExpression");
}
@Override
public void visit(CollateExpression aThis) {
System.out.println("CollateExpression");
}
@Override
public void visit(SimilarToExpression aThis) {
System.out.println("SimilarToExpression");
visitBinaryExpression(aThis);
}
@Override
public void visit(ArrayExpression aThis) {
System.out.println("ArrayExpression");
}
@Override
public void visit(ArrayConstructor aThis) {
System.out.println("ArrayConstructor");
}
@Override
public void visit(VariableAssignment aThis) {
System.out.println("VariableAssignment");
}
@Override
public void visit(XMLSerializeExpr aThis) {
System.out.println("XMLSerializeExpr");
}
@Override
public void visit(TimezoneExpression aThis) {
System.out.println("TimezoneExpression");
}
@Override
public void visit(JsonAggregateFunction aThis) {
System.out.println("JsonAggregateFunction");
}
@Override
public void visit(JsonFunction aThis) {
System.out.println("JsonFunction");
}
@Override
public void visit(ConnectByRootOperator aThis) {
System.out.println("ConnectByRootOperator");
}
@Override
public void visit(OracleNamedFunctionParameter aThis) {
System.out.println("OracleNamedFunctionParameter");
}
@Override
public void visit(AllColumns allColumns) {
System.out.println("AllColumns");
System.out.println(allColumns);
}
@Override
public void visit(AllTableColumns allTableColumns) {
System.out.println("AllTableColumns");
}
@Override
public void visit(AllValue allValue) {
System.out.println("AllValue");
}
@Override
public void visit(IsDistinctExpression isDistinctExpression) {
System.out.println("IsDistinctExpression");
visitBinaryExpression(isDistinctExpression);
}
@Override
public void visit(GeometryDistance geometryDistance) {
System.out.println("GeometryDistance");
visitBinaryExpression(geometryDistance);
}
@Override
public void visit(ExpressionList expressionList) {
System.out.println("ExpressionList");
}
@Override
public void visit(NamedExpressionList namedExpressionList) {
System.out.println("NamedExpressionList");
}
@Override
public void visit(MultiExpressionList multiExprList) {
System.out.println("MultiExpressionList");
}
@Override
public void visit(OrderByElement orderBy) {
System.out.println("OrderByElement");
orderBy.getExpression().accept(this);
if(orderBy.isAsc()){
System.out.println("ASC");
}else{
System.out.println("DESC");
}
}
}
测试样例:
package test;
import java.io.StringReader;
import java.util.List;
import cold.light.level.util.ClDateUtil;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.update.Update;
public class TestSql {
public static void main(String[] args) throws JSQLParserException {
CCJSqlParserManager pm = new CCJSqlParserManager();
String id = ClDateUtil.getDateTimeMS();
String initSql = "SELECT * FROM MY_TABLE1 a, MY_TABLE2 b, (SELECT * FROM MY_TABLE3) c LEFT OUTER JOIN MY_TABLE4 d"+
" WHERE ID = (SELECT MAX(ID) FROM MY_TABLE5) OR ID2 IN (SELECT * FROM MY_TABLE6 WHERE NAME='AA') AND MAX(ID1,ID2,ID3) > 4 ORDER BY ID1 ASC,SUB_STR(IFNULL(ID2,'123456'),1,6) DESC" ;
System.out.println(initSql);
Statement statement = pm.parse(new StringReader(initSql));
if (statement instanceof Select) {
Select selectStatement = (Select) statement;
SelectTablesColumns tablesNamesFinder = new SelectTablesColumns(id);
List tableList = tablesNamesFinder.getTableList(selectStatement);
// for (Iterator iter = tableList.iterator(); iter.hasNext();) {
// System.out.println(iter.next());
// }
}
}
}
输出结果:
SELECT * FROM MY_TABLE1 a, MY_TABLE2 b, (SELECT * FROM MY_TABLE3) c LEFT OUTER JOIN MY_TABLE4 d WHERE ID = (SELECT MAX(ID) FROM MY_TABLE5) OR ID2 IN (SELECT * FROM MY_TABLE6 WHERE NAME='AA') AND MAX(ID1,ID2,ID3) > 4 ORDER BY ID1 ASC,SUB_STR(IFNULL(ID2,'123456'),1,6) DESC
AllColumns
*
AllColumns
*
OrExpression
EqualsTo
Column
ID
SelectExpressionItem
Function
[MAX]
Column
ID
AndExpression
InExpression
Column
ID2
AllColumns
*
EqualsTo
Column
NAME
StringValue
StringValue='AA'
GreaterThan
Function
[MAX]
Column
ID1
Column
ID2
Column
ID3
LongValue
LongValue=4
OrderByElement
Column
ID1
ASC
OrderByElement
Function
[SUB_STR]
Function
[IFNULL]
Column
ID2
StringValue
StringValue='123456'
LongValue
LongValue=1
LongValue
LongValue=6
DESC
同理可实现Update、Insert、Delete等Sql的解析。