jsqlparse
介绍
JSqlParse是一款很精简的sql解析工具,它可以将常用的sql文本解析成具有层级结构的“语法树”,我们可以针对解析后的“树节点(也即官网里说的有层次结构的java类)”进行处理进而生成符合我们要求的sql形式。
官网给的介绍很简洁:JSqlParser 解析 SQL 语句并将其转换为 Java 类的层次结构。生成的层次结构可以使用访问者模式进行访问(官网地址:JSqlParser - Home)。
参考文献:
Sql解析转换之JSqlParse完整介绍_jsqlparser_Interest1_wyt的博客-CSDN博客
将等号替换为in
在业务需求中,以前开发过程中是一对一关系,要改成一对多的关系,并且要加上权限控制,权限控制可以参考mybatis-plus拦截,这里分享下如何将等于替换成In关系
观察
一般我们要修改字段名称,修改表名,重写ExpressionVisitorAdapter的visit方法就好了,但是不能替换为其他对象
因为在代码中一般都是 whsId = 1 , 通过CCJSqlParserUtil.parseExpression(sql) 转成的对象是 EqualsTo, 尝试了下,直接把需要替换的expression覆盖 ExpressionVisitorAdapter的visit(EqualsTo eualsTo)中的eualsTo对象是行不通的
后面发现sql的解析是一颗树,实现了BinaryExpression接口:
public abstract class BinaryExpression extends ASTNodeAccessImpl implements Expression {
// 左节点
private Expression leftExpression;
// 右节点
private Expression rightExpression;
... ...
}
多条件时
例如: a = 1 and b = 2 大概是这样这样子的
所以发现直接操作 EqualsTo 对象是不行的,我们需要操作and的对象 AndExpression
单条件时
当只有 a = 1 时,解析出来是EqualsTo对象,直接把对象全部替换掉就行了
代码如下
@Slf4j
public class JSqlMain {
public static void main(String[] args) throws Exception{
String sql1 = "whs_id = 1";
extracted(sql1);
// 或
String sql2 = "whs_id = 1 or a = 1";
extracted(sql2);
String sql3 = "whs_id = 1 and a = 1 and b = 1 + 1";
extracted(sql3);
}
private static void extracted(String sql) throws JSQLParserException {
log.info("old sql:[{}]", sql);
//2、创建解析器
Expression where = CCJSqlParserUtil.parseExpression(sql);
Expression expression = CCJSqlParserUtil.parseExpression("aaa in (1, 2 ,344444444)");
if (where instanceof EqualsTo && ((BinaryExpression)where).getLeftExpression().toString().equals("whs_id")){
where = expression;
} else {
//4、将自定义访问者传入解析后的sql对象 需要自定义字段名,可以在这传进去
where.accept(new MyJSqlVisitor(expression));
}
//5、打印转换后的sql语句
log.info("new sql:[{}] \n", where);
}
}
public class MyJSqlVisitor extends ExpressionVisitorAdapter{
/** 待替换表达式 */
private Expression expression;
public MyJSqlVisitor() {
}
public MyJSqlVisitor(Expression expression) {
this.expression = expression;
}
@Override
public void visit(AndExpression andExpression) {
Expression leftExpression = andExpression.getLeftExpression();
Expression rightExpression = andExpression.getRightExpression();
if (Objects.nonNull(leftExpression) && leftExpression instanceof BinaryExpression && ((BinaryExpression) leftExpression).getLeftExpression().toString().equals("whs_id")){
System.out.println(expression.getClass());
andExpression.setLeftExpression(expression);
super.visit(andExpression);
}
if (Objects.nonNull(rightExpression) && rightExpression instanceof BinaryExpression && ((BinaryExpression) rightExpression).getLeftExpression().toString().equals("whs_id")){
System.out.println(expression.getClass());
andExpression.setRightExpression(expression);
super.visit(andExpression);
}
super.visit(andExpression);
}
/**
* or wsh = 1; 用or开头会走走这里
* @param orExpression
*/
@Override
public void visit(OrExpression orExpression) {
Expression leftExpression = orExpression.getLeftExpression();
Expression rightExpression = orExpression.getRightExpression();
if (Objects.nonNull(leftExpression) && leftExpression instanceof BinaryExpression && ((BinaryExpression) leftExpression).getLeftExpression().toString().equals("whs_id")){
System.out.println(expression.getClass());
orExpression.setLeftExpression(expression);
super.visit(orExpression);
}
if (Objects.nonNull(rightExpression) && rightExpression instanceof BinaryExpression && ((BinaryExpression) rightExpression).getLeftExpression().toString().equals("whs_id")){
System.out.println(expression.getClass());
orExpression.setRightExpression(expression);
super.visit(orExpression);
}
super.visit(orExpression);
}
public void visit(EqualsTo equalsTo){
// 不能这样, 直接删除
// if (equalsTo.getLeftExpression().toString().equals("whs_id")){
// super.visit(expression);
// }
super.visit(equalsTo);
}
}
Ps: 主要提供替换是思路,有什么更好的其他方法替换可以留言