mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-01-03 12:05:28 +08:00
升级spring boot 3.4.4
This commit is contained in:
@ -112,7 +112,15 @@
|
|||||||
<!-- mybatis-plus -->
|
<!-- mybatis-plus -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<!--JDK 11+-->
|
||||||
|
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||||
|
<!--JDK 8+-->
|
||||||
|
<!--<artifactId>mybatis-plus-jsqlparser-4.9</artifactId>-->
|
||||||
<version>${mybatis-plus.version}</version>
|
<version>${mybatis-plus.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import org.jeecg.common.system.vo.LoginUser;
|
|||||||
import org.jeecg.common.util.IpUtils;
|
import org.jeecg.common.util.IpUtils;
|
||||||
import org.jeecg.common.util.SpringContextUtils;
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
|
||||||
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
|
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
|
|||||||
@ -1,33 +1,33 @@
|
|||||||
package org.jeecg.common.util.sqlInjection;
|
//package org.jeecg.common.util.sqlInjection;
|
||||||
|
//
|
||||||
import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor;
|
//import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor;
|
||||||
import net.sf.jsqlparser.parser.SimpleNode;
|
//import net.sf.jsqlparser.parser.SimpleNode;
|
||||||
import net.sf.jsqlparser.statement.select.UnionOp;
|
//import net.sf.jsqlparser.statement.select.UnionOp;
|
||||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
//import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 基于抽象语法树(AST)的注入攻击分析实现
|
// * 基于抽象语法树(AST)的注入攻击分析实现
|
||||||
*
|
// *
|
||||||
* @author guyadong
|
// * @author guyadong
|
||||||
*/
|
// */
|
||||||
public class InjectionAstNodeVisitor extends CCJSqlParserDefaultVisitor {
|
//public class InjectionAstNodeVisitor extends CCJSqlParserDefaultVisitor {
|
||||||
public InjectionAstNodeVisitor() {
|
// public InjectionAstNodeVisitor() {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 处理禁止联合查询
|
// * 处理禁止联合查询
|
||||||
*
|
// *
|
||||||
* @param node
|
// * @param node
|
||||||
* @param data
|
// * @param data
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
@Override
|
// @Override
|
||||||
public Object visit(SimpleNode node, Object data) {
|
// public Object visit(SimpleNode node, Object data) {
|
||||||
Object value = node.jjtGetValue();
|
// Object value = node.jjtGetValue();
|
||||||
if (value instanceof UnionOp) {
|
// if (value instanceof UnionOp) {
|
||||||
throw new JeecgSqlInjectionException("DISABLE UNION");
|
// throw new JeecgSqlInjectionException("DISABLE UNION");
|
||||||
}
|
// }
|
||||||
return super.visit(node, data);
|
// return super.visit(node, data);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
|
|||||||
@ -1,172 +1,172 @@
|
|||||||
package org.jeecg.common.util.sqlInjection;
|
//package org.jeecg.common.util.sqlInjection;
|
||||||
|
//
|
||||||
|
//
|
||||||
import net.sf.jsqlparser.expression.BinaryExpression;
|
//import net.sf.jsqlparser.expression.BinaryExpression;
|
||||||
import net.sf.jsqlparser.expression.Expression;
|
//import net.sf.jsqlparser.expression.Expression;
|
||||||
import net.sf.jsqlparser.expression.Function;
|
//import net.sf.jsqlparser.expression.Function;
|
||||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
//import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
//import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
//import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
||||||
import net.sf.jsqlparser.schema.Column;
|
//import net.sf.jsqlparser.schema.Column;
|
||||||
import net.sf.jsqlparser.statement.select.Join;
|
//import net.sf.jsqlparser.statement.select.Join;
|
||||||
import net.sf.jsqlparser.statement.select.OrderByElement;
|
//import net.sf.jsqlparser.statement.select.OrderByElement;
|
||||||
import net.sf.jsqlparser.statement.select.PlainSelect;
|
//import net.sf.jsqlparser.statement.select.PlainSelect;
|
||||||
import net.sf.jsqlparser.statement.select.SelectItem;
|
//import net.sf.jsqlparser.statement.select.SelectItem;
|
||||||
import net.sf.jsqlparser.statement.select.SubSelect;
|
//import net.sf.jsqlparser.statement.select.SubSelect;
|
||||||
import net.sf.jsqlparser.statement.select.WithItem;
|
//import net.sf.jsqlparser.statement.select.WithItem;
|
||||||
import net.sf.jsqlparser.util.TablesNamesFinder;
|
//import net.sf.jsqlparser.util.TablesNamesFinder;
|
||||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
//import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||||
import org.jeecg.common.util.sqlInjection.parse.ConstAnalyzer;
|
//import org.jeecg.common.util.sqlInjection.parse.ConstAnalyzer;
|
||||||
import org.jeecg.common.util.sqlInjection.parse.ParserSupport;
|
//import org.jeecg.common.util.sqlInjection.parse.ParserSupport;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 基于SQL语法对象的SQL注入攻击分析实现
|
// * 基于SQL语法对象的SQL注入攻击分析实现
|
||||||
*
|
// *
|
||||||
* @author guyadong
|
// * @author guyadong
|
||||||
*/
|
// */
|
||||||
public class InjectionSyntaxObjectAnalyzer extends TablesNamesFinder {
|
//public class InjectionSyntaxObjectAnalyzer extends TablesNamesFinder {
|
||||||
/**
|
// /**
|
||||||
* 危险函数名
|
// * 危险函数名
|
||||||
*/
|
// */
|
||||||
private static final String DANGROUS_FUNCTIONS = "(sleep|benchmark|extractvalue|updatexml|ST_LatFromGeoHash|ST_LongFromGeoHash|GTID_SUBSET|GTID_SUBTRACT|floor|ST_Pointfromgeohash"
|
// private static final String DANGROUS_FUNCTIONS = "(sleep|benchmark|extractvalue|updatexml|ST_LatFromGeoHash|ST_LongFromGeoHash|GTID_SUBSET|GTID_SUBTRACT|floor|ST_Pointfromgeohash"
|
||||||
+ "|geometrycollection|multipoint|polygon|multipolygon|linestring|multilinestring)";
|
// + "|geometrycollection|multipoint|polygon|multipolygon|linestring|multilinestring)";
|
||||||
|
//
|
||||||
private static ThreadLocal<Boolean> disableSubselect = new ThreadLocal<Boolean>() {
|
// private static ThreadLocal<Boolean> disableSubselect = new ThreadLocal<Boolean>() {
|
||||||
@Override
|
// @Override
|
||||||
protected Boolean initialValue() {
|
// protected Boolean initialValue() {
|
||||||
return true;
|
// return true;
|
||||||
}
|
|
||||||
};
|
|
||||||
private ConstAnalyzer constAnalyzer = new ConstAnalyzer();
|
|
||||||
|
|
||||||
public InjectionSyntaxObjectAnalyzer() {
|
|
||||||
super();
|
|
||||||
init(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitBinaryExpression(BinaryExpression binaryExpression) {
|
|
||||||
if (binaryExpression instanceof ComparisonOperator) {
|
|
||||||
if (isConst(binaryExpression.getLeftExpression()) && isConst(binaryExpression.getRightExpression())) {
|
|
||||||
/** 禁用恒等式 */
|
|
||||||
throw new JeecgSqlInjectionException("DISABLE IDENTICAL EQUATION " + binaryExpression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.visitBinaryExpression(binaryExpression);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(AndExpression andExpression) {
|
|
||||||
super.visit(andExpression);
|
|
||||||
checkConstExpress(andExpression.getLeftExpression());
|
|
||||||
checkConstExpress(andExpression.getRightExpression());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(OrExpression orExpression) {
|
|
||||||
super.visit(orExpression);
|
|
||||||
checkConstExpress(orExpression.getLeftExpression());
|
|
||||||
checkConstExpress(orExpression.getRightExpression());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Function function) {
|
|
||||||
if (function.getName().matches(DANGROUS_FUNCTIONS)) {
|
|
||||||
/** 禁用危险函数 */
|
|
||||||
throw new JeecgSqlInjectionException("DANGROUS FUNCTION: " + function.getName());
|
|
||||||
}
|
|
||||||
super.visit(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(WithItem withItem) {
|
|
||||||
try {
|
|
||||||
/** 允许 WITH 语句中的子查询 */
|
|
||||||
disableSubselect.set(false);
|
|
||||||
super.visit(withItem);
|
|
||||||
} finally {
|
|
||||||
disableSubselect.set(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(SubSelect subSelect) {
|
|
||||||
try {
|
|
||||||
/** 允许语句中的子查询 */
|
|
||||||
disableSubselect.set(false);
|
|
||||||
super.visit(subSelect);
|
|
||||||
} finally {
|
|
||||||
disableSubselect.set(true);
|
|
||||||
}
|
|
||||||
// if (disableSubselect.get()) {
|
|
||||||
// // 禁用子查询
|
|
||||||
// throw new JeecgSqlInjectionException("DISABLE subselect " + subSelect);
|
|
||||||
// }
|
// }
|
||||||
}
|
// };
|
||||||
|
// private ConstAnalyzer constAnalyzer = new ConstAnalyzer();
|
||||||
@Override
|
//
|
||||||
public void visit(Column tableColumn) {
|
// public InjectionSyntaxObjectAnalyzer() {
|
||||||
if (ParserSupport.isBoolean(tableColumn)) {
|
// super();
|
||||||
throw new JeecgSqlInjectionException("DISABLE CONST BOOL " + tableColumn);
|
// init(true);
|
||||||
}
|
//
|
||||||
super.visit(tableColumn);
|
// }
|
||||||
}
|
//
|
||||||
|
// @Override
|
||||||
@Override
|
// public void visitBinaryExpression(BinaryExpression binaryExpression) {
|
||||||
public void visit(PlainSelect plainSelect) {
|
// if (binaryExpression instanceof ComparisonOperator) {
|
||||||
if (plainSelect.getSelectItems() != null) {
|
// if (isConst(binaryExpression.getLeftExpression()) && isConst(binaryExpression.getRightExpression())) {
|
||||||
for (SelectItem item : plainSelect.getSelectItems()) {
|
// /** 禁用恒等式 */
|
||||||
item.accept(this);
|
// throw new JeecgSqlInjectionException("DISABLE IDENTICAL EQUATION " + binaryExpression);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// super.visitBinaryExpression(binaryExpression);
|
||||||
if (plainSelect.getFromItem() != null) {
|
// }
|
||||||
plainSelect.getFromItem().accept(this);
|
//
|
||||||
}
|
// @Override
|
||||||
|
// public void visit(AndExpression andExpression) {
|
||||||
if (plainSelect.getJoins() != null) {
|
// super.visit(andExpression);
|
||||||
for (Join join : plainSelect.getJoins()) {
|
// checkConstExpress(andExpression.getLeftExpression());
|
||||||
join.getRightItem().accept(this);
|
// checkConstExpress(andExpression.getRightExpression());
|
||||||
for (Expression e : join.getOnExpressions()) {
|
// }
|
||||||
e.accept(this);
|
//
|
||||||
}
|
// @Override
|
||||||
}
|
// public void visit(OrExpression orExpression) {
|
||||||
}
|
// super.visit(orExpression);
|
||||||
if (plainSelect.getWhere() != null) {
|
// checkConstExpress(orExpression.getLeftExpression());
|
||||||
plainSelect.getWhere().accept(this);
|
// checkConstExpress(orExpression.getRightExpression());
|
||||||
checkConstExpress(plainSelect.getWhere());
|
// }
|
||||||
}
|
//
|
||||||
|
// @Override
|
||||||
if (plainSelect.getHaving() != null) {
|
// public void visit(Function function) {
|
||||||
plainSelect.getHaving().accept(this);
|
// if (function.getName().matches(DANGROUS_FUNCTIONS)) {
|
||||||
}
|
// /** 禁用危险函数 */
|
||||||
|
// throw new JeecgSqlInjectionException("DANGROUS FUNCTION: " + function.getName());
|
||||||
if (plainSelect.getOracleHierarchical() != null) {
|
// }
|
||||||
plainSelect.getOracleHierarchical().accept(this);
|
// super.visit(function);
|
||||||
}
|
// }
|
||||||
if (plainSelect.getOrderByElements() != null) {
|
//
|
||||||
for (OrderByElement orderByElement : plainSelect.getOrderByElements()) {
|
// @Override
|
||||||
orderByElement.getExpression().accept(this);
|
// public void visit(WithItem withItem) {
|
||||||
}
|
// try {
|
||||||
}
|
// /** 允许 WITH 语句中的子查询 */
|
||||||
if (plainSelect.getGroupBy() != null) {
|
// disableSubselect.set(false);
|
||||||
for (Expression expression : plainSelect.getGroupBy().getGroupByExpressionList().getExpressions()) {
|
// super.visit(withItem);
|
||||||
expression.accept(this);
|
// } finally {
|
||||||
}
|
// disableSubselect.set(true);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private boolean isConst(Expression expression) {
|
// @Override
|
||||||
return constAnalyzer.isConstExpression(expression);
|
// public void visit(SubSelect subSelect) {
|
||||||
}
|
// try {
|
||||||
|
// /** 允许语句中的子查询 */
|
||||||
private void checkConstExpress(Expression expression) {
|
// disableSubselect.set(false);
|
||||||
if (constAnalyzer.isConstExpression(expression)) {
|
// super.visit(subSelect);
|
||||||
/** 禁用常量表达式 */
|
// } finally {
|
||||||
throw new JeecgSqlInjectionException("DISABLE CONST EXPRESSION " + expression);
|
// disableSubselect.set(true);
|
||||||
}
|
// }
|
||||||
}
|
//// if (disableSubselect.get()) {
|
||||||
}
|
//// // 禁用子查询
|
||||||
|
//// throw new JeecgSqlInjectionException("DISABLE subselect " + subSelect);
|
||||||
|
//// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void visit(Column tableColumn) {
|
||||||
|
// if (ParserSupport.isBoolean(tableColumn)) {
|
||||||
|
// throw new JeecgSqlInjectionException("DISABLE CONST BOOL " + tableColumn);
|
||||||
|
// }
|
||||||
|
// super.visit(tableColumn);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void visit(PlainSelect plainSelect) {
|
||||||
|
// if (plainSelect.getSelectItems() != null) {
|
||||||
|
// for (SelectItem item : plainSelect.getSelectItems()) {
|
||||||
|
// item.accept(this);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (plainSelect.getFromItem() != null) {
|
||||||
|
// plainSelect.getFromItem().accept(this);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (plainSelect.getJoins() != null) {
|
||||||
|
// for (Join join : plainSelect.getJoins()) {
|
||||||
|
// join.getRightItem().accept(this);
|
||||||
|
// for (Expression e : join.getOnExpressions()) {
|
||||||
|
// e.accept(this);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (plainSelect.getWhere() != null) {
|
||||||
|
// plainSelect.getWhere().accept(this);
|
||||||
|
// checkConstExpress(plainSelect.getWhere());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (plainSelect.getHaving() != null) {
|
||||||
|
// plainSelect.getHaving().accept(this);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (plainSelect.getOracleHierarchical() != null) {
|
||||||
|
// plainSelect.getOracleHierarchical().accept(this);
|
||||||
|
// }
|
||||||
|
// if (plainSelect.getOrderByElements() != null) {
|
||||||
|
// for (OrderByElement orderByElement : plainSelect.getOrderByElements()) {
|
||||||
|
// orderByElement.getExpression().accept(this);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (plainSelect.getGroupBy() != null) {
|
||||||
|
// for (Expression expression : plainSelect.getGroupBy().getGroupByExpressionList().getExpressions()) {
|
||||||
|
// expression.accept(this);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private boolean isConst(Expression expression) {
|
||||||
|
// return constAnalyzer.isConstExpression(expression);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private void checkConstExpress(Expression expression) {
|
||||||
|
// if (constAnalyzer.isConstExpression(expression)) {
|
||||||
|
// /** 禁用常量表达式 */
|
||||||
|
// throw new JeecgSqlInjectionException("DISABLE CONST EXPRESSION " + expression);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|||||||
@ -1,65 +1,65 @@
|
|||||||
package org.jeecg.common.util.sqlInjection;
|
//package org.jeecg.common.util.sqlInjection;
|
||||||
|
//
|
||||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
//import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||||
import org.jeecg.common.util.sqlInjection.parse.ParserSupport;
|
//import org.jeecg.common.util.sqlInjection.parse.ParserSupport;
|
||||||
;
|
//;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* SQL注入攻击分析器
|
// * SQL注入攻击分析器
|
||||||
*
|
// *
|
||||||
* @author guyadong
|
// * @author guyadong
|
||||||
* 参考:
|
// * 参考:
|
||||||
* https://blog.csdn.net/10km/article/details/127767358
|
// * https://blog.csdn.net/10km/article/details/127767358
|
||||||
* https://gitee.com/l0km/sql2java/tree/dev/sql2java-manager/src/main/java/gu/sql2java/parser
|
// * https://gitee.com/l0km/sql2java/tree/dev/sql2java-manager/src/main/java/gu/sql2java/parser
|
||||||
*/
|
// */
|
||||||
public class SqlInjectionAnalyzer {
|
//public class SqlInjectionAnalyzer {
|
||||||
|
//
|
||||||
//启用/关闭注入攻击检查
|
// //启用/关闭注入攻击检查
|
||||||
private boolean injectCheckEnable = true;
|
// private boolean injectCheckEnable = true;
|
||||||
//防止SQL注入攻击分析实现
|
// //防止SQL注入攻击分析实现
|
||||||
private final InjectionSyntaxObjectAnalyzer injectionChecker;
|
// private final InjectionSyntaxObjectAnalyzer injectionChecker;
|
||||||
private final InjectionAstNodeVisitor injectionVisitor;
|
// private final InjectionAstNodeVisitor injectionVisitor;
|
||||||
|
//
|
||||||
public SqlInjectionAnalyzer() {
|
// public SqlInjectionAnalyzer() {
|
||||||
this.injectionChecker = new InjectionSyntaxObjectAnalyzer();
|
// this.injectionChecker = new InjectionSyntaxObjectAnalyzer();
|
||||||
this.injectionVisitor = new InjectionAstNodeVisitor();
|
// this.injectionVisitor = new InjectionAstNodeVisitor();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 启用/关闭注入攻击检查,默认启动
|
// * 启用/关闭注入攻击检查,默认启动
|
||||||
*
|
// *
|
||||||
* @param enable
|
// * @param enable
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
public SqlInjectionAnalyzer injectCheckEnable(boolean enable) {
|
// public SqlInjectionAnalyzer injectCheckEnable(boolean enable) {
|
||||||
injectCheckEnable = enable;
|
// injectCheckEnable = enable;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 对解析后的SQL对象执行注入攻击分析,有注入攻击的危险则抛出异常{@link JeecgSqlInjectionException}
|
// * 对解析后的SQL对象执行注入攻击分析,有注入攻击的危险则抛出异常{@link JeecgSqlInjectionException}
|
||||||
*
|
// *
|
||||||
* @param sqlParserInfo
|
// * @param sqlParserInfo
|
||||||
* @throws JeecgSqlInjectionException
|
// * @throws JeecgSqlInjectionException
|
||||||
*/
|
// */
|
||||||
public ParserSupport.SqlParserInfo injectAnalyse(ParserSupport.SqlParserInfo sqlParserInfo) throws JeecgSqlInjectionException {
|
// public ParserSupport.SqlParserInfo injectAnalyse(ParserSupport.SqlParserInfo sqlParserInfo) throws JeecgSqlInjectionException {
|
||||||
if (null != sqlParserInfo && injectCheckEnable) {
|
// if (null != sqlParserInfo && injectCheckEnable) {
|
||||||
/** SQL注入攻击检查 */
|
// /** SQL注入攻击检查 */
|
||||||
sqlParserInfo.statement.accept(injectionChecker);
|
// sqlParserInfo.statement.accept(injectionChecker);
|
||||||
sqlParserInfo.simpleNode.jjtAccept(injectionVisitor, null);
|
// sqlParserInfo.simpleNode.jjtAccept(injectionVisitor, null);
|
||||||
}
|
// }
|
||||||
return sqlParserInfo;
|
// return sqlParserInfo;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* sql校验
|
// * sql校验
|
||||||
*/
|
// */
|
||||||
public static void checkSql(String sql,boolean check){
|
// public static void checkSql(String sql,boolean check){
|
||||||
SqlInjectionAnalyzer sqlInjectionAnalyzer = new SqlInjectionAnalyzer();
|
// SqlInjectionAnalyzer sqlInjectionAnalyzer = new SqlInjectionAnalyzer();
|
||||||
sqlInjectionAnalyzer.injectCheckEnable(check);
|
// sqlInjectionAnalyzer.injectCheckEnable(check);
|
||||||
ParserSupport.SqlParserInfo sqlParserInfo = ParserSupport.parse0(sql, null,null);
|
// ParserSupport.SqlParserInfo sqlParserInfo = ParserSupport.parse0(sql, null,null);
|
||||||
sqlInjectionAnalyzer.injectAnalyse(sqlParserInfo);
|
// sqlInjectionAnalyzer.injectAnalyse(sqlParserInfo);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,177 +1,177 @@
|
|||||||
package org.jeecg.common.util.sqlInjection.parse;
|
//package org.jeecg.common.util.sqlInjection.parse;
|
||||||
|
//
|
||||||
import lombok.extern.slf4j.Slf4j;
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
import net.sf.jsqlparser.JSQLParserException;
|
//import net.sf.jsqlparser.JSQLParserException;
|
||||||
import net.sf.jsqlparser.parser.*;
|
//import net.sf.jsqlparser.parser.*;
|
||||||
import net.sf.jsqlparser.schema.Column;
|
//import net.sf.jsqlparser.schema.Column;
|
||||||
import net.sf.jsqlparser.statement.Statement;
|
//import net.sf.jsqlparser.statement.Statement;
|
||||||
import net.sf.jsqlparser.statement.select.PlainSelect;
|
//import net.sf.jsqlparser.statement.select.PlainSelect;
|
||||||
import net.sf.jsqlparser.statement.select.Select;
|
//import net.sf.jsqlparser.statement.select.Select;
|
||||||
import net.sf.jsqlparser.statement.select.SelectBody;
|
//import net.sf.jsqlparser.statement.select.SelectBody;
|
||||||
|
//
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
//import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
//import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
//
|
||||||
import java.lang.reflect.InvocationTargetException;
|
//import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.regex.Matcher;
|
//import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
//import java.util.regex.Pattern;
|
||||||
|
//
|
||||||
import com.google.common.base.Throwables;
|
//import com.google.common.base.Throwables;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
//import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
//import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 解析sql支持
|
// * 解析sql支持
|
||||||
*/
|
// */
|
||||||
@Slf4j
|
//@Slf4j
|
||||||
public class ParserSupport {
|
//public class ParserSupport {
|
||||||
/**
|
// /**
|
||||||
* 解析SELECT SQL语句,解析失败或非SELECT语句则抛出异常
|
// * 解析SELECT SQL语句,解析失败或非SELECT语句则抛出异常
|
||||||
*
|
// *
|
||||||
* @param sql
|
// * @param sql
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
public static Select parseSelect(String sql) {
|
// public static Select parseSelect(String sql) {
|
||||||
Statement stmt;
|
// Statement stmt;
|
||||||
try {
|
// try {
|
||||||
stmt = CCJSqlParserUtil.parse(checkNotNull(sql, "sql is null"));
|
// stmt = CCJSqlParserUtil.parse(checkNotNull(sql, "sql is null"));
|
||||||
} catch (JSQLParserException e) {
|
// } catch (JSQLParserException e) {
|
||||||
throw new JeecgBootException(e);
|
// throw new JeecgBootException(e);
|
||||||
}
|
// }
|
||||||
checkArgument(stmt instanceof Select, "%s is not SELECT statment", sql);
|
// checkArgument(stmt instanceof Select, "%s is not SELECT statment", sql);
|
||||||
Select select = (Select) stmt;
|
// Select select = (Select) stmt;
|
||||||
SelectBody selectBody = select.getSelectBody();
|
// SelectBody selectBody = select.getSelectBody();
|
||||||
// 暂时只支持简单的SELECT xxxx FROM ....语句不支持复杂语句如WITH
|
// // 暂时只支持简单的SELECT xxxx FROM ....语句不支持复杂语句如WITH
|
||||||
checkArgument(selectBody instanceof PlainSelect, "ONLY SUPPORT plain select statement %s", sql);
|
// checkArgument(selectBody instanceof PlainSelect, "ONLY SUPPORT plain select statement %s", sql);
|
||||||
return (Select) stmt;
|
// return (Select) stmt;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 解析SELECT SQL语句,解析失败或非SELECT语句则
|
// * 解析SELECT SQL语句,解析失败或非SELECT语句则
|
||||||
*
|
// *
|
||||||
* @param sql
|
// * @param sql
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
public static Select parseSelectUnchecked(String sql) {
|
// public static Select parseSelectUnchecked(String sql) {
|
||||||
try {
|
// try {
|
||||||
return parseSelect(sql);
|
// return parseSelect(sql);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 实现SQL语句解析,解析成功则返回解析后的{@link Statement},
|
// * 实现SQL语句解析,解析成功则返回解析后的{@link Statement},
|
||||||
* 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。
|
// * 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。
|
||||||
*
|
// *
|
||||||
* @param sql SQL语句
|
// * @param sql SQL语句
|
||||||
* @param visitor 遍历所有节点的{@link SimpleNodeVisitor}接口实例,为{@code null}忽略
|
// * @param visitor 遍历所有节点的{@link SimpleNodeVisitor}接口实例,为{@code null}忽略
|
||||||
* @param sqlSyntaxNormalizer SQL语句分析转换器,为{@code null}忽略
|
// * @param sqlSyntaxNormalizer SQL语句分析转换器,为{@code null}忽略
|
||||||
* @throws JSQLParserException 输入的SQL语句有语法错误
|
// * @throws JSQLParserException 输入的SQL语句有语法错误
|
||||||
* @see #parse0(String, CCJSqlParserVisitor, SqlSyntaxNormalizer)
|
// * @see #parse0(String, CCJSqlParserVisitor, SqlSyntaxNormalizer)
|
||||||
*/
|
// */
|
||||||
public static Statement parse(String sql, CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxNormalizer) throws JSQLParserException {
|
// public static Statement parse(String sql, CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxNormalizer) throws JSQLParserException {
|
||||||
return parse0(sql, visitor, sqlSyntaxNormalizer).statement;
|
// return parse0(sql, visitor, sqlSyntaxNormalizer).statement;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 参照{@link CCJSqlParserUtil#parseAST(String)}和{@link CCJSqlParserUtil#parse(String)}实现SQL语句解析,
|
// * 参照{@link CCJSqlParserUtil#parseAST(String)}和{@link CCJSqlParserUtil#parse(String)}实现SQL语句解析,
|
||||||
* 解析成功则返回解析后的{@link SqlParserInfo}对象,
|
// * 解析成功则返回解析后的{@link SqlParserInfo}对象,
|
||||||
* 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。
|
// * 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。
|
||||||
*
|
// *
|
||||||
* @param sql SQL语句
|
// * @param sql SQL语句
|
||||||
* @param visitor 遍历所有节点的{@link SimpleNodeVisitor}接口实例,为{@code null}忽略
|
// * @param visitor 遍历所有节点的{@link SimpleNodeVisitor}接口实例,为{@code null}忽略
|
||||||
* @param sqlSyntaxAnalyzer SQL语句分析转换器,为{@code null}忽略
|
// * @param sqlSyntaxAnalyzer SQL语句分析转换器,为{@code null}忽略
|
||||||
* @throws JSQLParserException 输入的SQL语句有语法错误
|
// * @throws JSQLParserException 输入的SQL语句有语法错误
|
||||||
* @see net.sf.jsqlparser.parser.Node#jjtAccept(SimpleNodeVisitor, Object)
|
// * @see net.sf.jsqlparser.parser.Node#jjtAccept(SimpleNodeVisitor, Object)
|
||||||
*/
|
// */
|
||||||
public static SqlParserInfo parse0(String sql, CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxAnalyzer) throws JeecgSqlInjectionException {
|
// public static SqlParserInfo parse0(String sql, CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxAnalyzer) throws JeecgSqlInjectionException {
|
||||||
|
//
|
||||||
//检查是否非select开头,暂不支持
|
// //检查是否非select开头,暂不支持
|
||||||
if(!sql.toLowerCase().trim().startsWith("select ")) {
|
// if(!sql.toLowerCase().trim().startsWith("select ")) {
|
||||||
log.warn("传入sql 非select开头,不支持非select开头的语句解析!");
|
// log.warn("传入sql 非select开头,不支持非select开头的语句解析!");
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
//检查是否存储过程,暂不支持
|
// //检查是否存储过程,暂不支持
|
||||||
if(sql.toLowerCase().trim().startsWith("call ")){
|
// if(sql.toLowerCase().trim().startsWith("call ")){
|
||||||
log.warn("传入call 开头存储过程,不支持存储过程解析!");
|
// log.warn("传入call 开头存储过程,不支持存储过程解析!");
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
//检查特殊语义的特殊字符,目前检查冒号、$、#三种特殊语义字符
|
// //检查特殊语义的特殊字符,目前检查冒号、$、#三种特殊语义字符
|
||||||
String specialCharacters = "[:$#]";
|
// String specialCharacters = "[:$#]";
|
||||||
Pattern pattern = Pattern.compile(specialCharacters);
|
// Pattern pattern = Pattern.compile(specialCharacters);
|
||||||
Matcher matcher = pattern.matcher(sql);
|
// Matcher matcher = pattern.matcher(sql);
|
||||||
if (matcher.find()) {
|
// if (matcher.find()) {
|
||||||
sql = sql.replaceAll("[:$#]", "@");
|
// sql = sql.replaceAll("[:$#]", "@");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
checkArgument(null != sql, "sql is null");
|
// checkArgument(null != sql, "sql is null");
|
||||||
boolean allowComplexParsing = CCJSqlParserUtil.getNestingDepth(sql) <= CCJSqlParserUtil.ALLOWED_NESTING_DEPTH;
|
// boolean allowComplexParsing = CCJSqlParserUtil.getNestingDepth(sql) <= CCJSqlParserUtil.ALLOWED_NESTING_DEPTH;
|
||||||
|
//
|
||||||
CCJSqlParser parser = CCJSqlParserUtil.newParser(sql).withAllowComplexParsing(allowComplexParsing);
|
// CCJSqlParser parser = CCJSqlParserUtil.newParser(sql).withAllowComplexParsing(allowComplexParsing);
|
||||||
Statement stmt;
|
// Statement stmt;
|
||||||
try {
|
// try {
|
||||||
stmt = parser.Statement();
|
// stmt = parser.Statement();
|
||||||
} catch (Exception ex) {
|
// } catch (Exception ex) {
|
||||||
log.error("请注意,SQL语法可能存在问题---> {}", ex.getMessage());
|
// log.error("请注意,SQL语法可能存在问题---> {}", ex.getMessage());
|
||||||
throw new JeecgSqlInjectionException("请注意,SQL语法可能存在问题:"+sql);
|
// throw new JeecgSqlInjectionException("请注意,SQL语法可能存在问题:"+sql);
|
||||||
}
|
// }
|
||||||
if (null != visitor) {
|
// if (null != visitor) {
|
||||||
parser.getASTRoot().jjtAccept(visitor, null);
|
// parser.getASTRoot().jjtAccept(visitor, null);
|
||||||
}
|
// }
|
||||||
if (null != sqlSyntaxAnalyzer) {
|
// if (null != sqlSyntaxAnalyzer) {
|
||||||
stmt.accept(sqlSyntaxAnalyzer.resetChanged());
|
// stmt.accept(sqlSyntaxAnalyzer.resetChanged());
|
||||||
}
|
// }
|
||||||
return new SqlParserInfo(stmt.toString(), stmt, (SimpleNode) parser.getASTRoot());
|
// return new SqlParserInfo(stmt.toString(), stmt, (SimpleNode) parser.getASTRoot());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 调用{@link CCJSqlParser}解析SQL语句部件返回解析生成的对象,如{@code 'ORDER BY id DESC'}
|
// * 调用{@link CCJSqlParser}解析SQL语句部件返回解析生成的对象,如{@code 'ORDER BY id DESC'}
|
||||||
*
|
// *
|
||||||
* @param <T>
|
// * @param <T>
|
||||||
* @param input
|
// * @param input
|
||||||
* @param method 指定调用的{@link CCJSqlParser}解析方法
|
// * @param method 指定调用的{@link CCJSqlParser}解析方法
|
||||||
* @param targetType 返回的解析对象类型
|
// * @param targetType 返回的解析对象类型
|
||||||
* @return
|
// * @return
|
||||||
* @since 3.18.3
|
// * @since 3.18.3
|
||||||
*/
|
// */
|
||||||
public static <T> T parseComponent(String input, String method, Class<T> targetType) {
|
// public static <T> T parseComponent(String input, String method, Class<T> targetType) {
|
||||||
try {
|
// try {
|
||||||
CCJSqlParser parser = new CCJSqlParser(new StringProvider(input));
|
// CCJSqlParser parser = new CCJSqlParser(new StringProvider(input));
|
||||||
try {
|
// try {
|
||||||
return checkNotNull(targetType, "targetType is null").cast(parser.getClass().getMethod(method).invoke(parser));
|
// return checkNotNull(targetType, "targetType is null").cast(parser.getClass().getMethod(method).invoke(parser));
|
||||||
} catch (InvocationTargetException e) {
|
// } catch (InvocationTargetException e) {
|
||||||
Throwables.throwIfUnchecked(e.getTargetException());
|
// Throwables.throwIfUnchecked(e.getTargetException());
|
||||||
throw new RuntimeException(e.getTargetException());
|
// throw new RuntimeException(e.getTargetException());
|
||||||
}
|
// }
|
||||||
} catch (IllegalAccessException | NoSuchMethodException | SecurityException e) {
|
// } catch (IllegalAccessException | NoSuchMethodException | SecurityException e) {
|
||||||
Throwables.throwIfUnchecked(e);
|
// Throwables.throwIfUnchecked(e);
|
||||||
throw new RuntimeException(e);
|
// throw new RuntimeException(e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 如果{@link Column}没有定义table,且字段名为true/false(不区分大小写)则视为布尔常量
|
// * 如果{@link Column}没有定义table,且字段名为true/false(不区分大小写)则视为布尔常量
|
||||||
*
|
// *
|
||||||
* @param column
|
// * @param column
|
||||||
*/
|
// */
|
||||||
public static boolean isBoolean(Column column) {
|
// public static boolean isBoolean(Column column) {
|
||||||
return null != column && null == column.getTable() &&
|
// return null != column && null == column.getTable() &&
|
||||||
Pattern.compile("(true|false)", Pattern.CASE_INSENSITIVE).matcher(column.getColumnName()).matches();
|
// Pattern.compile("(true|false)", Pattern.CASE_INSENSITIVE).matcher(column.getColumnName()).matches();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static class SqlParserInfo {
|
// public static class SqlParserInfo {
|
||||||
public String nativeSql;
|
// public String nativeSql;
|
||||||
public Statement statement;
|
// public Statement statement;
|
||||||
public SimpleNode simpleNode;
|
// public SimpleNode simpleNode;
|
||||||
|
//
|
||||||
SqlParserInfo(String nativeSql, Statement statement, SimpleNode simpleNode) {
|
// SqlParserInfo(String nativeSql, Statement statement, SimpleNode simpleNode) {
|
||||||
this.nativeSql = nativeSql;
|
// this.nativeSql = nativeSql;
|
||||||
this.statement = statement;
|
// this.statement = statement;
|
||||||
this.simpleNode = simpleNode;
|
// this.simpleNode = simpleNode;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
|
|||||||
@ -1,37 +1,37 @@
|
|||||||
package org.jeecg.common.util.sqlInjection.parse;
|
//package org.jeecg.common.util.sqlInjection.parse;
|
||||||
|
//
|
||||||
import net.sf.jsqlparser.util.TablesNamesFinder;
|
//import net.sf.jsqlparser.util.TablesNamesFinder;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* SQL语句分析转换器基类<br>
|
// * SQL语句分析转换器基类<br>
|
||||||
* 基于SQL语法对象实现对SQL的修改
|
// * 基于SQL语法对象实现对SQL的修改
|
||||||
* (暂时用不到)
|
// * (暂时用不到)
|
||||||
*
|
// *
|
||||||
* @author guyadong
|
// * @author guyadong
|
||||||
* @since 3.17.0
|
// * @since 3.17.0
|
||||||
*/
|
// */
|
||||||
public class SqlSyntaxNormalizer extends TablesNamesFinder {
|
//public class SqlSyntaxNormalizer extends TablesNamesFinder {
|
||||||
protected static final ThreadLocal<Boolean> changed = new ThreadLocal<>();
|
// protected static final ThreadLocal<Boolean> changed = new ThreadLocal<>();
|
||||||
|
//
|
||||||
public SqlSyntaxNormalizer() {
|
// public SqlSyntaxNormalizer() {
|
||||||
super();
|
// super();
|
||||||
init(true);
|
// init(true);
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 语句改变返回{@code true},否则返回{@code false}
|
// * 语句改变返回{@code true},否则返回{@code false}
|
||||||
*/
|
// */
|
||||||
public boolean changed() {
|
// public boolean changed() {
|
||||||
return Boolean.TRUE.equals(changed.get());
|
// return Boolean.TRUE.equals(changed.get());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 复位线程局部变量{@link #changed}状态
|
// * 复位线程局部变量{@link #changed}状态
|
||||||
*/
|
// */
|
||||||
public SqlSyntaxNormalizer resetChanged() {
|
// public SqlSyntaxNormalizer resetChanged() {
|
||||||
changed.remove();
|
// changed.remove();
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
|
|||||||
@ -1,255 +1,255 @@
|
|||||||
package org.jeecg.common.util.sqlparse;
|
//package org.jeecg.common.util.sqlparse;
|
||||||
|
//
|
||||||
import lombok.extern.slf4j.Slf4j;
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
import net.sf.jsqlparser.JSQLParserException;
|
//import net.sf.jsqlparser.JSQLParserException;
|
||||||
import net.sf.jsqlparser.expression.*;
|
//import net.sf.jsqlparser.expression.*;
|
||||||
import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
//import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
||||||
import net.sf.jsqlparser.schema.Column;
|
//import net.sf.jsqlparser.schema.Column;
|
||||||
import net.sf.jsqlparser.schema.Table;
|
//import net.sf.jsqlparser.schema.Table;
|
||||||
import net.sf.jsqlparser.statement.Statement;
|
//import net.sf.jsqlparser.statement.Statement;
|
||||||
import net.sf.jsqlparser.statement.select.*;
|
//import net.sf.jsqlparser.statement.select.*;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
//import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
//import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||||
|
//
|
||||||
import java.io.StringReader;
|
//import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
//import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
//import java.util.HashMap;
|
||||||
import java.util.List;
|
//import java.util.List;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 解析所有表名和字段的类
|
// * 解析所有表名和字段的类
|
||||||
*/
|
// */
|
||||||
@Slf4j
|
//@Slf4j
|
||||||
public class JSqlParserAllTableManager {
|
//public class JSqlParserAllTableManager {
|
||||||
|
//
|
||||||
private final String sql;
|
// private final String sql;
|
||||||
private final Map<String, SelectSqlInfo> allTableMap = new HashMap<>();
|
// private final Map<String, SelectSqlInfo> allTableMap = new HashMap<>();
|
||||||
/**
|
// /**
|
||||||
* 别名对应实际表名
|
// * 别名对应实际表名
|
||||||
*/
|
// */
|
||||||
private final Map<String, String> tableAliasMap = new HashMap<>();
|
// private final Map<String, String> tableAliasMap = new HashMap<>();
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 解析后的sql
|
// * 解析后的sql
|
||||||
*/
|
// */
|
||||||
private String parsedSql = null;
|
// private String parsedSql = null;
|
||||||
|
//
|
||||||
JSqlParserAllTableManager(String selectSql) {
|
// JSqlParserAllTableManager(String selectSql) {
|
||||||
this.sql = selectSql;
|
// this.sql = selectSql;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 开始解析
|
// * 开始解析
|
||||||
*
|
// *
|
||||||
* @return
|
// * @return
|
||||||
* @throws JSQLParserException
|
// * @throws JSQLParserException
|
||||||
*/
|
// */
|
||||||
public Map<String, SelectSqlInfo> parse() throws JSQLParserException {
|
// public Map<String, SelectSqlInfo> parse() throws JSQLParserException {
|
||||||
// 1. 创建解析器
|
// // 1. 创建解析器
|
||||||
CCJSqlParserManager mgr = new CCJSqlParserManager();
|
// CCJSqlParserManager mgr = new CCJSqlParserManager();
|
||||||
// 2. 使用解析器解析sql生成具有层次结构的java类
|
// // 2. 使用解析器解析sql生成具有层次结构的java类
|
||||||
Statement stmt = mgr.parse(new StringReader(this.sql));
|
// Statement stmt = mgr.parse(new StringReader(this.sql));
|
||||||
if (stmt instanceof Select) {
|
// if (stmt instanceof Select) {
|
||||||
Select selectStatement = (Select) stmt;
|
// Select selectStatement = (Select) stmt;
|
||||||
SelectBody selectBody = selectStatement.getSelectBody();
|
// SelectBody selectBody = selectStatement.getSelectBody();
|
||||||
this.parsedSql = selectBody.toString();
|
// this.parsedSql = selectBody.toString();
|
||||||
// 3. 解析select查询sql的信息
|
// // 3. 解析select查询sql的信息
|
||||||
if (selectBody instanceof PlainSelect) {
|
// if (selectBody instanceof PlainSelect) {
|
||||||
PlainSelect plainSelect = (PlainSelect) selectBody;
|
// PlainSelect plainSelect = (PlainSelect) selectBody;
|
||||||
// 4. 合并 fromItems
|
// // 4. 合并 fromItems
|
||||||
List<FromItem> fromItems = new ArrayList<>();
|
// List<FromItem> fromItems = new ArrayList<>();
|
||||||
fromItems.add(plainSelect.getFromItem());
|
// fromItems.add(plainSelect.getFromItem());
|
||||||
// 4.1 处理join的表
|
// // 4.1 处理join的表
|
||||||
List<Join> joins = plainSelect.getJoins();
|
// List<Join> joins = plainSelect.getJoins();
|
||||||
if (joins != null) {
|
// if (joins != null) {
|
||||||
joins.forEach(join -> fromItems.add(join.getRightItem()));
|
// joins.forEach(join -> fromItems.add(join.getRightItem()));
|
||||||
}
|
// }
|
||||||
// 5. 处理 fromItems
|
// // 5. 处理 fromItems
|
||||||
for (FromItem fromItem : fromItems) {
|
// for (FromItem fromItem : fromItems) {
|
||||||
// 5.1 通过表名的方式from
|
// // 5.1 通过表名的方式from
|
||||||
if (fromItem instanceof Table) {
|
// if (fromItem instanceof Table) {
|
||||||
this.addSqlInfoByTable((Table) fromItem);
|
// this.addSqlInfoByTable((Table) fromItem);
|
||||||
}
|
// }
|
||||||
// 5.2 通过子查询的方式from
|
// // 5.2 通过子查询的方式from
|
||||||
else if (fromItem instanceof SubSelect) {
|
// else if (fromItem instanceof SubSelect) {
|
||||||
this.handleSubSelect((SubSelect) fromItem);
|
// this.handleSubSelect((SubSelect) fromItem);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// 6. 解析 selectFields
|
// // 6. 解析 selectFields
|
||||||
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
// List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||||
for (SelectItem selectItem : selectItems) {
|
// for (SelectItem selectItem : selectItems) {
|
||||||
// 6.1 查询的是全部字段
|
// // 6.1 查询的是全部字段
|
||||||
if (selectItem instanceof AllColumns) {
|
// if (selectItem instanceof AllColumns) {
|
||||||
// 当 selectItem 为 AllColumns 时,fromItem 必定为 Table
|
// // 当 selectItem 为 AllColumns 时,fromItem 必定为 Table
|
||||||
String tableName = plainSelect.getFromItem(Table.class).getName();
|
// String tableName = plainSelect.getFromItem(Table.class).getName();
|
||||||
// 此处必定不为空,因为在解析 fromItem 时,已经将表名添加到 allTableMap 中
|
// // 此处必定不为空,因为在解析 fromItem 时,已经将表名添加到 allTableMap 中
|
||||||
SelectSqlInfo sqlInfo = this.allTableMap.get(tableName);
|
// SelectSqlInfo sqlInfo = this.allTableMap.get(tableName);
|
||||||
assert sqlInfo != null;
|
// assert sqlInfo != null;
|
||||||
// 设置为查询全部字段
|
// // 设置为查询全部字段
|
||||||
sqlInfo.setSelectAll(true);
|
// sqlInfo.setSelectAll(true);
|
||||||
sqlInfo.setSelectFields(null);
|
// sqlInfo.setSelectFields(null);
|
||||||
sqlInfo.setRealSelectFields(null);
|
// sqlInfo.setRealSelectFields(null);
|
||||||
}
|
// }
|
||||||
// 6.2 查询的是带表别名( u.* )的全部字段
|
// // 6.2 查询的是带表别名( u.* )的全部字段
|
||||||
else if (selectItem instanceof AllTableColumns) {
|
// else if (selectItem instanceof AllTableColumns) {
|
||||||
AllTableColumns allTableColumns = (AllTableColumns) selectItem;
|
// AllTableColumns allTableColumns = (AllTableColumns) selectItem;
|
||||||
String aliasName = allTableColumns.getTable().getName();
|
// String aliasName = allTableColumns.getTable().getName();
|
||||||
// 通过别名获取表名
|
// // 通过别名获取表名
|
||||||
String tableName = this.tableAliasMap.get(aliasName);
|
// String tableName = this.tableAliasMap.get(aliasName);
|
||||||
if (tableName == null) {
|
// if (tableName == null) {
|
||||||
tableName = aliasName;
|
// tableName = aliasName;
|
||||||
}
|
// }
|
||||||
SelectSqlInfo sqlInfo = this.allTableMap.get(tableName);
|
// SelectSqlInfo sqlInfo = this.allTableMap.get(tableName);
|
||||||
// 如果此处为空,则说明该字段是通过子查询获取的,所以可以不处理,只有实际表才需要处理
|
// // 如果此处为空,则说明该字段是通过子查询获取的,所以可以不处理,只有实际表才需要处理
|
||||||
if (sqlInfo != null) {
|
// if (sqlInfo != null) {
|
||||||
// 设置为查询全部字段
|
// // 设置为查询全部字段
|
||||||
sqlInfo.setSelectAll(true);
|
// sqlInfo.setSelectAll(true);
|
||||||
sqlInfo.setSelectFields(null);
|
// sqlInfo.setSelectFields(null);
|
||||||
sqlInfo.setRealSelectFields(null);
|
// sqlInfo.setRealSelectFields(null);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// 6.3 各种字段表达式处理
|
// // 6.3 各种字段表达式处理
|
||||||
else if (selectItem instanceof SelectExpressionItem) {
|
// else if (selectItem instanceof SelectExpressionItem) {
|
||||||
SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
// SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
||||||
Expression expression = selectExpressionItem.getExpression();
|
// Expression expression = selectExpressionItem.getExpression();
|
||||||
Alias alias = selectExpressionItem.getAlias();
|
// Alias alias = selectExpressionItem.getAlias();
|
||||||
this.handleExpression(expression, alias, plainSelect.getFromItem());
|
// this.handleExpression(expression, alias, plainSelect.getFromItem());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName());
|
// log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName());
|
||||||
throw new JeecgBootException("暂时尚未处理该类型的 SelectBody");
|
// throw new JeecgBootException("暂时尚未处理该类型的 SelectBody");
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
// 非 select 查询sql,不做处理
|
// // 非 select 查询sql,不做处理
|
||||||
throw new JeecgBootException("非 select 查询sql,不做处理");
|
// throw new JeecgBootException("非 select 查询sql,不做处理");
|
||||||
}
|
// }
|
||||||
return this.allTableMap;
|
// return this.allTableMap;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 处理子查询
|
// * 处理子查询
|
||||||
*
|
// *
|
||||||
* @param subSelect
|
// * @param subSelect
|
||||||
*/
|
// */
|
||||||
private void handleSubSelect(SubSelect subSelect) {
|
// private void handleSubSelect(SubSelect subSelect) {
|
||||||
try {
|
// try {
|
||||||
String subSelectSql = subSelect.getSelectBody().toString();
|
// String subSelectSql = subSelect.getSelectBody().toString();
|
||||||
// 递归调用解析
|
// // 递归调用解析
|
||||||
Map<String, SelectSqlInfo> map = JSqlParserUtils.parseAllSelectTable(subSelectSql);
|
// Map<String, SelectSqlInfo> map = JSqlParserUtils.parseAllSelectTable(subSelectSql);
|
||||||
if (map != null) {
|
// if (map != null) {
|
||||||
this.assignMap(map);
|
// this.assignMap(map);
|
||||||
}
|
// }
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("解析子查询出错", e);
|
// log.error("解析子查询出错", e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 处理查询字段表达式
|
// * 处理查询字段表达式
|
||||||
*
|
// *
|
||||||
* @param expression
|
// * @param expression
|
||||||
*/
|
// */
|
||||||
private void handleExpression(Expression expression, Alias alias, FromItem fromItem) {
|
// private void handleExpression(Expression expression, Alias alias, FromItem fromItem) {
|
||||||
// 处理函数式字段 CONCAT(name,'(',age,')')
|
// // 处理函数式字段 CONCAT(name,'(',age,')')
|
||||||
if (expression instanceof Function) {
|
// if (expression instanceof Function) {
|
||||||
Function functionExp = (Function) expression;
|
// Function functionExp = (Function) expression;
|
||||||
List<Expression> expressions = functionExp.getParameters().getExpressions();
|
// List<Expression> expressions = functionExp.getParameters().getExpressions();
|
||||||
for (Expression expItem : expressions) {
|
// for (Expression expItem : expressions) {
|
||||||
this.handleExpression(expItem, null, fromItem);
|
// this.handleExpression(expItem, null, fromItem);
|
||||||
}
|
// }
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
// 处理字段上的子查询
|
// // 处理字段上的子查询
|
||||||
if (expression instanceof SubSelect) {
|
// if (expression instanceof SubSelect) {
|
||||||
this.handleSubSelect((SubSelect) expression);
|
// this.handleSubSelect((SubSelect) expression);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
// 不处理字面量
|
// // 不处理字面量
|
||||||
if (expression instanceof StringValue ||
|
// if (expression instanceof StringValue ||
|
||||||
expression instanceof NullValue ||
|
// expression instanceof NullValue ||
|
||||||
expression instanceof LongValue ||
|
// expression instanceof LongValue ||
|
||||||
expression instanceof DoubleValue ||
|
// expression instanceof DoubleValue ||
|
||||||
expression instanceof HexValue ||
|
// expression instanceof HexValue ||
|
||||||
expression instanceof DateValue ||
|
// expression instanceof DateValue ||
|
||||||
expression instanceof TimestampValue ||
|
// expression instanceof TimestampValue ||
|
||||||
expression instanceof TimeValue
|
// expression instanceof TimeValue
|
||||||
) {
|
// ) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 处理字段
|
// // 处理字段
|
||||||
if (expression instanceof Column) {
|
// if (expression instanceof Column) {
|
||||||
Column column = (Column) expression;
|
// Column column = (Column) expression;
|
||||||
// 查询字段名
|
// // 查询字段名
|
||||||
String fieldName = column.getColumnName();
|
// String fieldName = column.getColumnName();
|
||||||
String aliasName = fieldName;
|
// String aliasName = fieldName;
|
||||||
if (alias != null) {
|
// if (alias != null) {
|
||||||
aliasName = alias.getName();
|
// aliasName = alias.getName();
|
||||||
}
|
// }
|
||||||
String tableName;
|
// String tableName;
|
||||||
if (column.getTable() != null) {
|
// if (column.getTable() != null) {
|
||||||
// 通过列的表名获取 sqlInfo
|
// // 通过列的表名获取 sqlInfo
|
||||||
// 例如 user.name,这里的 tableName 就是 user
|
// // 例如 user.name,这里的 tableName 就是 user
|
||||||
tableName = column.getTable().getName();
|
// tableName = column.getTable().getName();
|
||||||
// 有可能是别名,需要转换为真实表名
|
// // 有可能是别名,需要转换为真实表名
|
||||||
if (this.tableAliasMap.get(tableName) != null) {
|
// if (this.tableAliasMap.get(tableName) != null) {
|
||||||
tableName = this.tableAliasMap.get(tableName);
|
// tableName = this.tableAliasMap.get(tableName);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
// 当column的table为空时,说明是 fromItem 中的字段
|
// // 当column的table为空时,说明是 fromItem 中的字段
|
||||||
tableName = ((Table) fromItem).getName();
|
// tableName = ((Table) fromItem).getName();
|
||||||
}
|
// }
|
||||||
SelectSqlInfo $sqlInfo = this.allTableMap.get(tableName);
|
// SelectSqlInfo $sqlInfo = this.allTableMap.get(tableName);
|
||||||
if ($sqlInfo != null) {
|
// if ($sqlInfo != null) {
|
||||||
$sqlInfo.addSelectField(aliasName, fieldName);
|
// $sqlInfo.addSelectField(aliasName, fieldName);
|
||||||
} else {
|
// } else {
|
||||||
log.warn("发生意外情况,未找到表名为 {} 的 SelectSqlInfo", tableName);
|
// log.warn("发生意外情况,未找到表名为 {} 的 SelectSqlInfo", tableName);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 根据表名添加sqlInfo
|
// * 根据表名添加sqlInfo
|
||||||
*
|
// *
|
||||||
* @param table
|
// * @param table
|
||||||
*/
|
// */
|
||||||
private void addSqlInfoByTable(Table table) {
|
// private void addSqlInfoByTable(Table table) {
|
||||||
String tableName = table.getName();
|
// String tableName = table.getName();
|
||||||
// 解析 aliasName
|
// // 解析 aliasName
|
||||||
if (table.getAlias() != null) {
|
// if (table.getAlias() != null) {
|
||||||
this.tableAliasMap.put(table.getAlias().getName(), tableName);
|
// this.tableAliasMap.put(table.getAlias().getName(), tableName);
|
||||||
}
|
// }
|
||||||
SelectSqlInfo sqlInfo = new SelectSqlInfo(this.parsedSql);
|
// SelectSqlInfo sqlInfo = new SelectSqlInfo(this.parsedSql);
|
||||||
sqlInfo.setFromTableName(table.getName());
|
// sqlInfo.setFromTableName(table.getName());
|
||||||
this.allTableMap.put(sqlInfo.getFromTableName(), sqlInfo);
|
// this.allTableMap.put(sqlInfo.getFromTableName(), sqlInfo);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 合并map
|
// * 合并map
|
||||||
*
|
// *
|
||||||
* @param source
|
// * @param source
|
||||||
*/
|
// */
|
||||||
private void assignMap(Map<String, SelectSqlInfo> source) {
|
// private void assignMap(Map<String, SelectSqlInfo> source) {
|
||||||
for (Map.Entry<String, SelectSqlInfo> entry : source.entrySet()) {
|
// for (Map.Entry<String, SelectSqlInfo> entry : source.entrySet()) {
|
||||||
SelectSqlInfo sqlInfo = this.allTableMap.get(entry.getKey());
|
// SelectSqlInfo sqlInfo = this.allTableMap.get(entry.getKey());
|
||||||
if (sqlInfo == null) {
|
// if (sqlInfo == null) {
|
||||||
this.allTableMap.put(entry.getKey(), entry.getValue());
|
// this.allTableMap.put(entry.getKey(), entry.getValue());
|
||||||
} else {
|
// } else {
|
||||||
// 合并
|
// // 合并
|
||||||
if (sqlInfo.getSelectFields() == null) {
|
// if (sqlInfo.getSelectFields() == null) {
|
||||||
sqlInfo.setSelectFields(entry.getValue().getSelectFields());
|
// sqlInfo.setSelectFields(entry.getValue().getSelectFields());
|
||||||
} else {
|
// } else {
|
||||||
sqlInfo.getSelectFields().addAll(entry.getValue().getSelectFields());
|
// sqlInfo.getSelectFields().addAll(entry.getValue().getSelectFields());
|
||||||
}
|
// }
|
||||||
if (sqlInfo.getRealSelectFields() == null) {
|
// if (sqlInfo.getRealSelectFields() == null) {
|
||||||
sqlInfo.setRealSelectFields(entry.getValue().getRealSelectFields());
|
// sqlInfo.setRealSelectFields(entry.getValue().getRealSelectFields());
|
||||||
} else {
|
// } else {
|
||||||
sqlInfo.getRealSelectFields().addAll(entry.getValue().getRealSelectFields());
|
// sqlInfo.getRealSelectFields().addAll(entry.getValue().getRealSelectFields());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -1,190 +1,190 @@
|
|||||||
package org.jeecg.common.util.sqlparse;
|
//package org.jeecg.common.util.sqlparse;
|
||||||
|
//
|
||||||
import lombok.extern.slf4j.Slf4j;
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
import net.sf.jsqlparser.JSQLParserException;
|
//import net.sf.jsqlparser.JSQLParserException;
|
||||||
import net.sf.jsqlparser.expression.*;
|
//import net.sf.jsqlparser.expression.*;
|
||||||
import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
//import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
||||||
import net.sf.jsqlparser.schema.Column;
|
//import net.sf.jsqlparser.schema.Column;
|
||||||
import net.sf.jsqlparser.schema.Table;
|
//import net.sf.jsqlparser.schema.Table;
|
||||||
import net.sf.jsqlparser.statement.Statement;
|
//import net.sf.jsqlparser.statement.Statement;
|
||||||
import net.sf.jsqlparser.statement.select.*;
|
//import net.sf.jsqlparser.statement.select.*;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
//import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
//import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
//import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||||
|
//
|
||||||
import java.io.StringReader;
|
//import java.io.StringReader;
|
||||||
import java.util.List;
|
//import java.util.List;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
|
//
|
||||||
@Slf4j
|
//@Slf4j
|
||||||
public class JSqlParserUtils {
|
//public class JSqlParserUtils {
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 解析 查询(select)sql的信息,
|
// * 解析 查询(select)sql的信息,
|
||||||
* 此方法会展开所有子查询到一个map里,
|
// * 此方法会展开所有子查询到一个map里,
|
||||||
* key只存真实的表名,如果查询的没有真实的表名,则会被忽略。
|
// * key只存真实的表名,如果查询的没有真实的表名,则会被忽略。
|
||||||
* value只存真实的字段名,如果查询的没有真实的字段名,则会被忽略。
|
// * value只存真实的字段名,如果查询的没有真实的字段名,则会被忽略。
|
||||||
* <p>
|
// * <p>
|
||||||
* 例如:SELECT a.*,d.age,(SELECT count(1) FROM sys_depart) AS count FROM (SELECT username AS foo, realname FROM sys_user) a, demo d
|
// * 例如:SELECT a.*,d.age,(SELECT count(1) FROM sys_depart) AS count FROM (SELECT username AS foo, realname FROM sys_user) a, demo d
|
||||||
* 解析后的结果为:{sys_user=[username, realname], demo=[age], sys_depart=[]}
|
// * 解析后的结果为:{sys_user=[username, realname], demo=[age], sys_depart=[]}
|
||||||
*
|
// *
|
||||||
* @param selectSql
|
// * @param selectSql
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
public static Map<String, SelectSqlInfo> parseAllSelectTable(String selectSql) throws JSQLParserException {
|
// public static Map<String, SelectSqlInfo> parseAllSelectTable(String selectSql) throws JSQLParserException {
|
||||||
if (oConvertUtils.isEmpty(selectSql)) {
|
// if (oConvertUtils.isEmpty(selectSql)) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
// log.info("解析查询Sql:{}", selectSql);
|
// // log.info("解析查询Sql:{}", selectSql);
|
||||||
JSqlParserAllTableManager allTableManager = new JSqlParserAllTableManager(selectSql);
|
// JSqlParserAllTableManager allTableManager = new JSqlParserAllTableManager(selectSql);
|
||||||
return allTableManager.parse();
|
// return allTableManager.parse();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 解析 查询(select)sql的信息,子查询嵌套
|
// * 解析 查询(select)sql的信息,子查询嵌套
|
||||||
*
|
// *
|
||||||
* @param selectSql
|
// * @param selectSql
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
public static SelectSqlInfo parseSelectSqlInfo(String selectSql) throws JSQLParserException {
|
// public static SelectSqlInfo parseSelectSqlInfo(String selectSql) throws JSQLParserException {
|
||||||
if (oConvertUtils.isEmpty(selectSql)) {
|
// if (oConvertUtils.isEmpty(selectSql)) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
// log.info("解析查询Sql:{}", selectSql);
|
// // log.info("解析查询Sql:{}", selectSql);
|
||||||
// 使用 JSqlParer 解析sql
|
// // 使用 JSqlParer 解析sql
|
||||||
// 1、创建解析器
|
// // 1、创建解析器
|
||||||
CCJSqlParserManager mgr = new CCJSqlParserManager();
|
// CCJSqlParserManager mgr = new CCJSqlParserManager();
|
||||||
// 2、使用解析器解析sql生成具有层次结构的java类
|
// // 2、使用解析器解析sql生成具有层次结构的java类
|
||||||
Statement stmt = mgr.parse(new StringReader(selectSql));
|
// Statement stmt = mgr.parse(new StringReader(selectSql));
|
||||||
if (stmt instanceof Select) {
|
// if (stmt instanceof Select) {
|
||||||
Select selectStatement = (Select) stmt;
|
// Select selectStatement = (Select) stmt;
|
||||||
// 3、解析select查询sql的信息
|
// // 3、解析select查询sql的信息
|
||||||
return JSqlParserUtils.parseBySelectBody(selectStatement.getSelectBody());
|
// return JSqlParserUtils.parseBySelectBody(selectStatement.getSelectBody());
|
||||||
} else {
|
// } else {
|
||||||
// 非 select 查询sql,不做处理
|
// // 非 select 查询sql,不做处理
|
||||||
throw new JeecgBootException("非 select 查询sql,不做处理");
|
// throw new JeecgBootException("非 select 查询sql,不做处理");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 解析 select 查询sql的信息
|
// * 解析 select 查询sql的信息
|
||||||
*
|
// *
|
||||||
* @param selectBody
|
// * @param selectBody
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
private static SelectSqlInfo parseBySelectBody(SelectBody selectBody) {
|
// private static SelectSqlInfo parseBySelectBody(SelectBody selectBody) {
|
||||||
// 判断是否使用了union等操作
|
// // 判断是否使用了union等操作
|
||||||
if (selectBody instanceof SetOperationList) {
|
// if (selectBody instanceof SetOperationList) {
|
||||||
// 如果使用了union等操作,则只解析第一个查询
|
// // 如果使用了union等操作,则只解析第一个查询
|
||||||
List<SelectBody> selectBodyList = ((SetOperationList) selectBody).getSelects();
|
// List<SelectBody> selectBodyList = ((SetOperationList) selectBody).getSelects();
|
||||||
return JSqlParserUtils.parseBySelectBody(selectBodyList.get(0));
|
// return JSqlParserUtils.parseBySelectBody(selectBodyList.get(0));
|
||||||
}
|
// }
|
||||||
// 简单的select查询
|
// // 简单的select查询
|
||||||
if (selectBody instanceof PlainSelect) {
|
// if (selectBody instanceof PlainSelect) {
|
||||||
SelectSqlInfo sqlInfo = new SelectSqlInfo(selectBody);
|
// SelectSqlInfo sqlInfo = new SelectSqlInfo(selectBody);
|
||||||
PlainSelect plainSelect = (PlainSelect) selectBody;
|
// PlainSelect plainSelect = (PlainSelect) selectBody;
|
||||||
FromItem fromItem = plainSelect.getFromItem();
|
// FromItem fromItem = plainSelect.getFromItem();
|
||||||
// 解析 aliasName
|
// // 解析 aliasName
|
||||||
if (fromItem.getAlias() != null) {
|
// if (fromItem.getAlias() != null) {
|
||||||
sqlInfo.setFromTableAliasName(fromItem.getAlias().getName());
|
// sqlInfo.setFromTableAliasName(fromItem.getAlias().getName());
|
||||||
}
|
// }
|
||||||
// 解析 表名
|
// // 解析 表名
|
||||||
if (fromItem instanceof Table) {
|
// if (fromItem instanceof Table) {
|
||||||
// 通过表名的方式from
|
// // 通过表名的方式from
|
||||||
Table fromTable = (Table) fromItem;
|
// Table fromTable = (Table) fromItem;
|
||||||
sqlInfo.setFromTableName(fromTable.getName());
|
// sqlInfo.setFromTableName(fromTable.getName());
|
||||||
} else if (fromItem instanceof SubSelect) {
|
// } else if (fromItem instanceof SubSelect) {
|
||||||
// 通过子查询的方式from
|
// // 通过子查询的方式from
|
||||||
SubSelect fromSubSelect = (SubSelect) fromItem;
|
// SubSelect fromSubSelect = (SubSelect) fromItem;
|
||||||
SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(fromSubSelect.getSelectBody());
|
// SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(fromSubSelect.getSelectBody());
|
||||||
sqlInfo.setFromSubSelect(subSqlInfo);
|
// sqlInfo.setFromSubSelect(subSqlInfo);
|
||||||
}
|
// }
|
||||||
// 解析 selectFields
|
// // 解析 selectFields
|
||||||
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
// List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||||
for (SelectItem selectItem : selectItems) {
|
// for (SelectItem selectItem : selectItems) {
|
||||||
if (selectItem instanceof AllColumns || selectItem instanceof AllTableColumns) {
|
// if (selectItem instanceof AllColumns || selectItem instanceof AllTableColumns) {
|
||||||
// 全部字段
|
// // 全部字段
|
||||||
sqlInfo.setSelectAll(true);
|
// sqlInfo.setSelectAll(true);
|
||||||
sqlInfo.setSelectFields(null);
|
// sqlInfo.setSelectFields(null);
|
||||||
sqlInfo.setRealSelectFields(null);
|
// sqlInfo.setRealSelectFields(null);
|
||||||
break;
|
// break;
|
||||||
} else if (selectItem instanceof SelectExpressionItem) {
|
// } else if (selectItem instanceof SelectExpressionItem) {
|
||||||
// 获取单个查询字段名
|
// // 获取单个查询字段名
|
||||||
SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
// SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
||||||
Expression expression = selectExpressionItem.getExpression();
|
// Expression expression = selectExpressionItem.getExpression();
|
||||||
Alias alias = selectExpressionItem.getAlias();
|
// Alias alias = selectExpressionItem.getAlias();
|
||||||
JSqlParserUtils.handleExpression(sqlInfo, expression, alias);
|
// JSqlParserUtils.handleExpression(sqlInfo, expression, alias);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return sqlInfo;
|
// return sqlInfo;
|
||||||
} else {
|
// } else {
|
||||||
log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName());
|
// log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName());
|
||||||
throw new JeecgBootException("暂时尚未处理该类型的 SelectBody");
|
// throw new JeecgBootException("暂时尚未处理该类型的 SelectBody");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 处理查询字段表达式
|
// * 处理查询字段表达式
|
||||||
*
|
// *
|
||||||
* @param sqlInfo
|
// * @param sqlInfo
|
||||||
* @param expression
|
// * @param expression
|
||||||
* @param alias 是否有别名,无传null
|
// * @param alias 是否有别名,无传null
|
||||||
*/
|
// */
|
||||||
private static void handleExpression(SelectSqlInfo sqlInfo, Expression expression, Alias alias) {
|
// private static void handleExpression(SelectSqlInfo sqlInfo, Expression expression, Alias alias) {
|
||||||
// 处理函数式字段 CONCAT(name,'(',age,')')
|
// // 处理函数式字段 CONCAT(name,'(',age,')')
|
||||||
if (expression instanceof Function) {
|
// if (expression instanceof Function) {
|
||||||
JSqlParserUtils.handleFunctionExpression((Function) expression, sqlInfo);
|
// JSqlParserUtils.handleFunctionExpression((Function) expression, sqlInfo);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
// 处理字段上的子查询
|
// // 处理字段上的子查询
|
||||||
if (expression instanceof SubSelect) {
|
// if (expression instanceof SubSelect) {
|
||||||
SubSelect subSelect = (SubSelect) expression;
|
// SubSelect subSelect = (SubSelect) expression;
|
||||||
SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(subSelect.getSelectBody());
|
// SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(subSelect.getSelectBody());
|
||||||
// 注:字段上的子查询,必须只查询一个字段,否则会报错,所以可以放心合并
|
// // 注:字段上的子查询,必须只查询一个字段,否则会报错,所以可以放心合并
|
||||||
sqlInfo.getSelectFields().addAll(subSqlInfo.getSelectFields());
|
// sqlInfo.getSelectFields().addAll(subSqlInfo.getSelectFields());
|
||||||
sqlInfo.getRealSelectFields().addAll(subSqlInfo.getAllRealSelectFields());
|
// sqlInfo.getRealSelectFields().addAll(subSqlInfo.getAllRealSelectFields());
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
// 不处理字面量
|
// // 不处理字面量
|
||||||
if (expression instanceof StringValue ||
|
// if (expression instanceof StringValue ||
|
||||||
expression instanceof NullValue ||
|
// expression instanceof NullValue ||
|
||||||
expression instanceof LongValue ||
|
// expression instanceof LongValue ||
|
||||||
expression instanceof DoubleValue ||
|
// expression instanceof DoubleValue ||
|
||||||
expression instanceof HexValue ||
|
// expression instanceof HexValue ||
|
||||||
expression instanceof DateValue ||
|
// expression instanceof DateValue ||
|
||||||
expression instanceof TimestampValue ||
|
// expression instanceof TimestampValue ||
|
||||||
expression instanceof TimeValue
|
// expression instanceof TimeValue
|
||||||
) {
|
// ) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 查询字段名
|
// // 查询字段名
|
||||||
String selectField = expression.toString();
|
// String selectField = expression.toString();
|
||||||
// 实际查询字段名
|
// // 实际查询字段名
|
||||||
String realSelectField = selectField;
|
// String realSelectField = selectField;
|
||||||
// 判断是否有别名
|
// // 判断是否有别名
|
||||||
if (alias != null) {
|
// if (alias != null) {
|
||||||
selectField = alias.getName();
|
// selectField = alias.getName();
|
||||||
}
|
// }
|
||||||
// 获取真实字段名
|
// // 获取真实字段名
|
||||||
if (expression instanceof Column) {
|
// if (expression instanceof Column) {
|
||||||
Column column = (Column) expression;
|
// Column column = (Column) expression;
|
||||||
realSelectField = column.getColumnName();
|
// realSelectField = column.getColumnName();
|
||||||
}
|
// }
|
||||||
sqlInfo.addSelectField(selectField, realSelectField);
|
// sqlInfo.addSelectField(selectField, realSelectField);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 处理函数式字段
|
// * 处理函数式字段
|
||||||
*
|
// *
|
||||||
* @param functionExp
|
// * @param functionExp
|
||||||
* @param sqlInfo
|
// * @param sqlInfo
|
||||||
*/
|
// */
|
||||||
private static void handleFunctionExpression(Function functionExp, SelectSqlInfo sqlInfo) {
|
// private static void handleFunctionExpression(Function functionExp, SelectSqlInfo sqlInfo) {
|
||||||
List<Expression> expressions = functionExp.getParameters().getExpressions();
|
// List<Expression> expressions = functionExp.getParameters().getExpressions();
|
||||||
for (Expression expression : expressions) {
|
// for (Expression expression : expressions) {
|
||||||
JSqlParserUtils.handleExpression(sqlInfo, expression, null);
|
// JSqlParserUtils.handleExpression(sqlInfo, expression, null);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -1,101 +1,101 @@
|
|||||||
package org.jeecg.common.util.sqlparse.vo;
|
//package org.jeecg.common.util.sqlparse.vo;
|
||||||
|
//
|
||||||
import lombok.Data;
|
//import lombok.Data;
|
||||||
import net.sf.jsqlparser.statement.select.SelectBody;
|
//import net.sf.jsqlparser.statement.select.SelectBody;
|
||||||
|
//
|
||||||
import java.util.HashSet;
|
//import java.util.HashSet;
|
||||||
import java.util.Set;
|
//import java.util.Set;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* select 查询 sql 的信息
|
// * select 查询 sql 的信息
|
||||||
*/
|
// */
|
||||||
@Data
|
//@Data
|
||||||
public class SelectSqlInfo {
|
//public class SelectSqlInfo {
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 查询的表名,如果是子查询,则此处为null
|
// * 查询的表名,如果是子查询,则此处为null
|
||||||
*/
|
// */
|
||||||
private String fromTableName;
|
// private String fromTableName;
|
||||||
/**
|
// /**
|
||||||
* 表别名
|
// * 表别名
|
||||||
*/
|
// */
|
||||||
private String fromTableAliasName;
|
// private String fromTableAliasName;
|
||||||
/**
|
// /**
|
||||||
* 通过子查询获取的表信息,例如:select name from (select * from user) u
|
// * 通过子查询获取的表信息,例如:select name from (select * from user) u
|
||||||
* 如果不是子查询,则为null
|
// * 如果不是子查询,则为null
|
||||||
*/
|
// */
|
||||||
private SelectSqlInfo fromSubSelect;
|
// private SelectSqlInfo fromSubSelect;
|
||||||
/**
|
// /**
|
||||||
* 查询的字段集合,如果是 * 则为null,如果设了别名则为别名
|
// * 查询的字段集合,如果是 * 则为null,如果设了别名则为别名
|
||||||
*/
|
// */
|
||||||
private Set<String> selectFields;
|
// private Set<String> selectFields;
|
||||||
/**
|
// /**
|
||||||
* 真实的查询字段集合,如果是 * 则为null,如果设了别名则为原始字段名
|
// * 真实的查询字段集合,如果是 * 则为null,如果设了别名则为原始字段名
|
||||||
*/
|
// */
|
||||||
private Set<String> realSelectFields;
|
// private Set<String> realSelectFields;
|
||||||
/**
|
// /**
|
||||||
* 是否是查询所有字段
|
// * 是否是查询所有字段
|
||||||
*/
|
// */
|
||||||
private boolean selectAll;
|
// private boolean selectAll;
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 解析之后的 SQL (关键字都是大写)
|
// * 解析之后的 SQL (关键字都是大写)
|
||||||
*/
|
// */
|
||||||
private final String parsedSql;
|
// private final String parsedSql;
|
||||||
|
//
|
||||||
public SelectSqlInfo(String parsedSql) {
|
// public SelectSqlInfo(String parsedSql) {
|
||||||
this.parsedSql = parsedSql;
|
// this.parsedSql = parsedSql;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public SelectSqlInfo(SelectBody selectBody) {
|
// public SelectSqlInfo(SelectBody selectBody) {
|
||||||
this.parsedSql = selectBody.toString();
|
// this.parsedSql = selectBody.toString();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public void addSelectField(String selectField, String realSelectField) {
|
// public void addSelectField(String selectField, String realSelectField) {
|
||||||
if (this.selectFields == null) {
|
// if (this.selectFields == null) {
|
||||||
this.selectFields = new HashSet<>();
|
// this.selectFields = new HashSet<>();
|
||||||
}
|
// }
|
||||||
if (this.realSelectFields == null) {
|
// if (this.realSelectFields == null) {
|
||||||
this.realSelectFields = new HashSet<>();
|
// this.realSelectFields = new HashSet<>();
|
||||||
}
|
// }
|
||||||
this.selectFields.add(selectField);
|
// this.selectFields.add(selectField);
|
||||||
this.realSelectFields.add(realSelectField);
|
// this.realSelectFields.add(realSelectField);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 获取所有字段,包括子查询里的。
|
// * 获取所有字段,包括子查询里的。
|
||||||
*
|
// *
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
public Set<String> getAllRealSelectFields() {
|
// public Set<String> getAllRealSelectFields() {
|
||||||
Set<String> fields = new HashSet<>();
|
// Set<String> fields = new HashSet<>();
|
||||||
// 递归获取所有字段,起个直观的方法名为:
|
// // 递归获取所有字段,起个直观的方法名为:
|
||||||
this.recursiveGetAllFields(this, fields);
|
// this.recursiveGetAllFields(this, fields);
|
||||||
return fields;
|
// return fields;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 递归获取所有字段
|
// * 递归获取所有字段
|
||||||
*/
|
// */
|
||||||
private void recursiveGetAllFields(SelectSqlInfo sqlInfo, Set<String> fields) {
|
// private void recursiveGetAllFields(SelectSqlInfo sqlInfo, Set<String> fields) {
|
||||||
if (!sqlInfo.isSelectAll() && sqlInfo.getRealSelectFields() != null) {
|
// if (!sqlInfo.isSelectAll() && sqlInfo.getRealSelectFields() != null) {
|
||||||
fields.addAll(sqlInfo.getRealSelectFields());
|
// fields.addAll(sqlInfo.getRealSelectFields());
|
||||||
}
|
// }
|
||||||
if (sqlInfo.getFromSubSelect() != null) {
|
// if (sqlInfo.getFromSubSelect() != null) {
|
||||||
recursiveGetAllFields(sqlInfo.getFromSubSelect(), fields);
|
// recursiveGetAllFields(sqlInfo.getFromSubSelect(), fields);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public String toString() {
|
// public String toString() {
|
||||||
return "SelectSqlInfo{" +
|
// return "SelectSqlInfo{" +
|
||||||
"fromTableName='" + fromTableName + '\'' +
|
// "fromTableName='" + fromTableName + '\'' +
|
||||||
", fromSubSelect=" + fromSubSelect +
|
// ", fromSubSelect=" + fromSubSelect +
|
||||||
", aliasName='" + fromTableAliasName + '\'' +
|
// ", aliasName='" + fromTableAliasName + '\'' +
|
||||||
", selectFields=" + selectFields +
|
// ", selectFields=" + selectFields +
|
||||||
", realSelectFields=" + realSelectFields +
|
// ", realSelectFields=" + realSelectFields +
|
||||||
", selectAll=" + selectAll +
|
// ", selectAll=" + selectAll +
|
||||||
"}";
|
// "}";
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
|||||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||||
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
import io.micrometer.prometheusmetrics.PrometheusMeterRegistry;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import java.util.List;
|
|||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.LongValue;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.TenantConstant;
|
import org.jeecg.common.constant.TenantConstant;
|
||||||
@ -21,8 +23,8 @@ import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||||
|
|
||||||
import net.sf.jsqlparser.expression.Expression;
|
//import net.sf.jsqlparser.expression.Expression;
|
||||||
import net.sf.jsqlparser.expression.LongValue;
|
//import net.sf.jsqlparser.expression.LongValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单数据源配置(jeecg.datasource.open = false时生效)
|
* 单数据源配置(jeecg.datasource.open = false时生效)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.jeecg.config.oss;
|
package org.jeecg.config.oss;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
@ -26,7 +27,7 @@ public class MinioConfig {
|
|||||||
@Value(value = "${jeecg.minio.bucketName}")
|
@Value(value = "${jeecg.minio.bucketName}")
|
||||||
private String bucketName;
|
private String bucketName;
|
||||||
|
|
||||||
@Bean
|
@PostConstruct
|
||||||
public void initMinio(){
|
public void initMinio(){
|
||||||
if(!minioUrl.startsWith(CommonConstant.STR_HTTP)){
|
if(!minioUrl.startsWith(CommonConstant.STR_HTTP)){
|
||||||
minioUrl = "http://" + minioUrl;
|
minioUrl = "http://" + minioUrl;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.jeecg.config.oss;
|
package org.jeecg.config.oss;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import org.jeecg.common.util.oss.OssBootUtil;
|
import org.jeecg.common.util.oss.OssBootUtil;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
@ -26,7 +27,7 @@ public class OssConfiguration {
|
|||||||
private String staticDomain;
|
private String staticDomain;
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@PostConstruct
|
||||||
public void initOssBootConfiguration() {
|
public void initOssBootConfiguration() {
|
||||||
OssBootUtil.setEndPoint(endpoint);
|
OssBootUtil.setEndPoint(endpoint);
|
||||||
OssBootUtil.setAccessKeyId(accessKeyId);
|
OssBootUtil.setAccessKeyId(accessKeyId);
|
||||||
|
|||||||
@ -1,109 +1,109 @@
|
|||||||
package org.jeecg.test.sqlparse;
|
//package org.jeecg.test.sqlparse;
|
||||||
|
//
|
||||||
import net.sf.jsqlparser.JSQLParserException;
|
//import net.sf.jsqlparser.JSQLParserException;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
//import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.common.util.sqlparse.JSqlParserUtils;
|
//import org.jeecg.common.util.sqlparse.JSqlParserUtils;
|
||||||
import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
//import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||||
import org.junit.Test;
|
//import org.junit.Test;
|
||||||
|
//
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 针对 JSqlParserUtils 的单元测试
|
// * 针对 JSqlParserUtils 的单元测试
|
||||||
*/
|
// */
|
||||||
public class JSqlParserUtilsTest {
|
//public class JSqlParserUtilsTest {
|
||||||
|
//
|
||||||
private static final String[] sqlList = new String[]{
|
// private static final String[] sqlList = new String[]{
|
||||||
"select * from sys_user",
|
// "select * from sys_user",
|
||||||
"select u.* from sys_user u",
|
// "select u.* from sys_user u",
|
||||||
"select u.*, c.name from sys_user u, demo c",
|
// "select u.*, c.name from sys_user u, demo c",
|
||||||
"select u.age, c.name from sys_user u, demo c",
|
// "select u.age, c.name from sys_user u, demo c",
|
||||||
"select sex, age, c.name from sys_user, demo c",
|
// "select sex, age, c.name from sys_user, demo c",
|
||||||
// 别名测试
|
// // 别名测试
|
||||||
"select username as realname from sys_user",
|
// "select username as realname from sys_user",
|
||||||
"select username as realname, u.realname as aaa, u.id bbb from sys_user u",
|
// "select username as realname, u.realname as aaa, u.id bbb from sys_user u",
|
||||||
// 不存在真实地查询字段
|
// // 不存在真实地查询字段
|
||||||
"select count(1) from sys_user",
|
// "select count(1) from sys_user",
|
||||||
// 函数式字段
|
// // 函数式字段
|
||||||
"select max(sex), id from sys_user",
|
// "select max(sex), id from sys_user",
|
||||||
// 复杂嵌套函数式字段
|
// // 复杂嵌套函数式字段
|
||||||
"select CONCAT(CONCAT(' _ ', sex), ' - ' , birthday) as info, id from sys_user",
|
// "select CONCAT(CONCAT(' _ ', sex), ' - ' , birthday) as info, id from sys_user",
|
||||||
// 更复杂的嵌套函数式字段
|
// // 更复杂的嵌套函数式字段
|
||||||
"select CONCAT(CONCAT(101,'_',NULL, DATE(create_time),'_',sex),' - ',birthday) as info, id from sys_user",
|
// "select CONCAT(CONCAT(101,'_',NULL, DATE(create_time),'_',sex),' - ',birthday) as info, id from sys_user",
|
||||||
// 子查询SQL
|
// // 子查询SQL
|
||||||
"select u.name1 as name2 from (select username as name1 from sys_user) u",
|
// "select u.name1 as name2 from (select username as name1 from sys_user) u",
|
||||||
// 多层嵌套子查询SQL
|
// // 多层嵌套子查询SQL
|
||||||
"select u2.name2 as name3 from (select u1.name1 as name2 from (select username as name1 from sys_user) u1) u2",
|
// "select u2.name2 as name3 from (select u1.name1 as name2 from (select username as name1 from sys_user) u1) u2",
|
||||||
// 字段子查询SQL
|
// // 字段子查询SQL
|
||||||
"select id, (select username as name1 from sys_user u2 where u1.id = u2.id) as name2 from sys_user u1",
|
// "select id, (select username as name1 from sys_user u2 where u1.id = u2.id) as name2 from sys_user u1",
|
||||||
// 带条件的SQL(不解析where条件里的字段,但不影响解析查询字段)
|
// // 带条件的SQL(不解析where条件里的字段,但不影响解析查询字段)
|
||||||
"select username as name1 from sys_user where realname LIKE '%张%'",
|
// "select username as name1 from sys_user where realname LIKE '%张%'",
|
||||||
// 多重复杂关联表查询解析,包含的表为:sys_user, sys_depart, sys_dict_item, demo
|
// // 多重复杂关联表查询解析,包含的表为:sys_user, sys_depart, sys_dict_item, demo
|
||||||
"" +
|
// "" +
|
||||||
"SELECT " +
|
// "SELECT " +
|
||||||
" u.*, d.age, sd.item_text AS sex, (SELECT count(sd.id) FROM sys_depart sd) AS count " +
|
// " u.*, d.age, sd.item_text AS sex, (SELECT count(sd.id) FROM sys_depart sd) AS count " +
|
||||||
"FROM " +
|
// "FROM " +
|
||||||
" (SELECT sd.username AS foo, sd.realname FROM sys_user sd) u, " +
|
// " (SELECT sd.username AS foo, sd.realname FROM sys_user sd) u, " +
|
||||||
" demo d " +
|
// " demo d " +
|
||||||
"LEFT JOIN sys_dict_item AS sd ON d.sex = sd.item_value " +
|
// "LEFT JOIN sys_dict_item AS sd ON d.sex = sd.item_value " +
|
||||||
"WHERE sd.dict_id = '3d9a351be3436fbefb1307d4cfb49bf2'",
|
// "WHERE sd.dict_id = '3d9a351be3436fbefb1307d4cfb49bf2'",
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
public void testParseSelectSql() {
|
// public void testParseSelectSql() {
|
||||||
System.out.println("-----------------------------------------");
|
// System.out.println("-----------------------------------------");
|
||||||
for (String sql : sqlList) {
|
// for (String sql : sqlList) {
|
||||||
System.out.println("待测试的sql:" + sql);
|
// System.out.println("待测试的sql:" + sql);
|
||||||
try {
|
// try {
|
||||||
// 解析所有的表名,key=表名,value=解析后的sql信息
|
// // 解析所有的表名,key=表名,value=解析后的sql信息
|
||||||
Map<String, SelectSqlInfo> parsedMap = JSqlParserUtils.parseAllSelectTable(sql);
|
// Map<String, SelectSqlInfo> parsedMap = JSqlParserUtils.parseAllSelectTable(sql);
|
||||||
assert parsedMap != null;
|
// assert parsedMap != null;
|
||||||
for (Map.Entry<String, SelectSqlInfo> entry : parsedMap.entrySet()) {
|
// for (Map.Entry<String, SelectSqlInfo> entry : parsedMap.entrySet()) {
|
||||||
System.out.println("表名:" + entry.getKey());
|
// System.out.println("表名:" + entry.getKey());
|
||||||
this.printSqlInfo(entry.getValue(), 1);
|
// this.printSqlInfo(entry.getValue(), 1);
|
||||||
}
|
// }
|
||||||
} catch (JSQLParserException e) {
|
// } catch (JSQLParserException e) {
|
||||||
System.out.println("SQL解析出现异常:" + e.getMessage());
|
// System.out.println("SQL解析出现异常:" + e.getMessage());
|
||||||
}
|
// }
|
||||||
System.out.println("-----------------------------------------");
|
// System.out.println("-----------------------------------------");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private void printSqlInfo(SelectSqlInfo sqlInfo, int level) {
|
// private void printSqlInfo(SelectSqlInfo sqlInfo, int level) {
|
||||||
String beforeStr = this.getBeforeStr(level);
|
// String beforeStr = this.getBeforeStr(level);
|
||||||
if (sqlInfo.getFromTableName() == null) {
|
// if (sqlInfo.getFromTableName() == null) {
|
||||||
// 子查询
|
// // 子查询
|
||||||
System.out.println(beforeStr + "子查询:" + sqlInfo.getFromSubSelect().getParsedSql());
|
// System.out.println(beforeStr + "子查询:" + sqlInfo.getFromSubSelect().getParsedSql());
|
||||||
this.printSqlInfo(sqlInfo.getFromSubSelect(), level + 1);
|
// this.printSqlInfo(sqlInfo.getFromSubSelect(), level + 1);
|
||||||
} else {
|
// } else {
|
||||||
// 非子查询
|
// // 非子查询
|
||||||
System.out.println(beforeStr + "查询的表名:" + sqlInfo.getFromTableName());
|
// System.out.println(beforeStr + "查询的表名:" + sqlInfo.getFromTableName());
|
||||||
}
|
// }
|
||||||
if (oConvertUtils.isNotEmpty(sqlInfo.getFromTableAliasName())) {
|
// if (oConvertUtils.isNotEmpty(sqlInfo.getFromTableAliasName())) {
|
||||||
System.out.println(beforeStr + "查询的表别名:" + sqlInfo.getFromTableAliasName());
|
// System.out.println(beforeStr + "查询的表别名:" + sqlInfo.getFromTableAliasName());
|
||||||
}
|
// }
|
||||||
if (sqlInfo.isSelectAll()) {
|
// if (sqlInfo.isSelectAll()) {
|
||||||
System.out.println(beforeStr + "查询的字段:*");
|
// System.out.println(beforeStr + "查询的字段:*");
|
||||||
} else {
|
// } else {
|
||||||
System.out.println(beforeStr + "查询的字段:" + sqlInfo.getSelectFields());
|
// System.out.println(beforeStr + "查询的字段:" + sqlInfo.getSelectFields());
|
||||||
System.out.println(beforeStr + "真实的字段:" + sqlInfo.getRealSelectFields());
|
// System.out.println(beforeStr + "真实的字段:" + sqlInfo.getRealSelectFields());
|
||||||
if (sqlInfo.getFromTableName() == null) {
|
// if (sqlInfo.getFromTableName() == null) {
|
||||||
System.out.println(beforeStr + "所有的字段(包括子查询):" + sqlInfo.getAllRealSelectFields());
|
// System.out.println(beforeStr + "所有的字段(包括子查询):" + sqlInfo.getAllRealSelectFields());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 打印前缀,根据层级来打印
|
// // 打印前缀,根据层级来打印
|
||||||
private String getBeforeStr(int level) {
|
// private String getBeforeStr(int level) {
|
||||||
if (level == 0) {
|
// if (level == 0) {
|
||||||
return "";
|
// return "";
|
||||||
}
|
// }
|
||||||
StringBuilder beforeStr = new StringBuilder();
|
// StringBuilder beforeStr = new StringBuilder();
|
||||||
for (int i = 0; i < level; i++) {
|
// for (int i = 0; i < level; i++) {
|
||||||
beforeStr.append(" ");
|
// beforeStr.append(" ");
|
||||||
}
|
// }
|
||||||
beforeStr.append("- ");
|
// beforeStr.append("- ");
|
||||||
return beforeStr.toString();
|
// return beforeStr.toString();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -19,10 +19,10 @@
|
|||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
<artifactId>hibernate-core</artifactId>
|
<artifactId>hibernate-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<!--<dependency>
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
<groupId>org.jeecgframework.boot3</groupId>
|
||||||
<artifactId>hibernate-re</artifactId>
|
<artifactId>hibernate-re</artifactId>
|
||||||
</dependency>
|
</dependency>-->
|
||||||
|
|
||||||
<!-- 企业微信/钉钉 api -->
|
<!-- 企业微信/钉钉 api -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<artifactId>weixin4j</artifactId>
|
<artifactId>weixin4j</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- 积木报表 -->
|
<!-- 积木报表 -->
|
||||||
<dependency>
|
<!--<dependency>
|
||||||
<groupId>org.jeecgframework.jimureport</groupId>
|
<groupId>org.jeecgframework.jimureport</groupId>
|
||||||
<artifactId>jimureport-spring-boot3-starter-fastjson2</artifactId>
|
<artifactId>jimureport-spring-boot3-starter-fastjson2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
@ -38,11 +38,11 @@
|
|||||||
<groupId>org.jeecgframework.jimureport</groupId>
|
<groupId>org.jeecgframework.jimureport</groupId>
|
||||||
<artifactId>jimureport-nosql-starter</artifactId>
|
<artifactId>jimureport-nosql-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- 积木BI -->
|
<!– 积木BI –>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jeecgframework.jimureport</groupId>
|
<groupId>org.jeecgframework.jimureport</groupId>
|
||||||
<artifactId>jimubi-spring-boot3-starter</artifactId>
|
<artifactId>jimubi-spring-boot3-starter</artifactId>
|
||||||
</dependency>
|
</dependency>-->
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.common.util.sqlparse.JSqlParserUtils;
|
//import org.jeecg.common.util.sqlparse.JSqlParserUtils;
|
||||||
import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
//import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.firewall.SqlInjection.IDictTableWhiteListHandler;
|
import org.jeecg.config.firewall.SqlInjection.IDictTableWhiteListHandler;
|
||||||
import org.jeecg.config.firewall.interceptor.LowCodeModeInterceptor;
|
import org.jeecg.config.firewall.interceptor.LowCodeModeInterceptor;
|
||||||
@ -63,31 +63,31 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPassBySql(String sql) {
|
public boolean isPassBySql(String sql) {
|
||||||
Map<String, SelectSqlInfo> parsedMap = null;
|
// Map<String, SelectSqlInfo> parsedMap = null;
|
||||||
try {
|
// try {
|
||||||
parsedMap = JSqlParserUtils.parseAllSelectTable(sql);
|
// parsedMap = JSqlParserUtils.parseAllSelectTable(sql);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.warn("校验sql语句,解析报错:{}", e.getMessage());
|
// log.warn("校验sql语句,解析报错:{}", e.getMessage());
|
||||||
}
|
// }
|
||||||
// 如果sql有问题,则肯定执行不了,所以直接返回true
|
// // 如果sql有问题,则肯定执行不了,所以直接返回true
|
||||||
if (parsedMap == null) {
|
// if (parsedMap == null) {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
log.info("获取select sql信息 :{} ", parsedMap);
|
// log.info("获取select sql信息 :{} ", parsedMap);
|
||||||
// 遍历当前sql中的所有表名,如果有其中一个表或表的字段不在白名单中,则不通过
|
// // 遍历当前sql中的所有表名,如果有其中一个表或表的字段不在白名单中,则不通过
|
||||||
for (Map.Entry<String, SelectSqlInfo> entry : parsedMap.entrySet()) {
|
// for (Map.Entry<String, SelectSqlInfo> entry : parsedMap.entrySet()) {
|
||||||
SelectSqlInfo sqlInfo = entry.getValue();
|
// SelectSqlInfo sqlInfo = entry.getValue();
|
||||||
if (sqlInfo.isSelectAll()) {
|
// if (sqlInfo.isSelectAll()) {
|
||||||
log.warn("查询语句中包含 * 字段,暂时先通过");
|
// log.warn("查询语句中包含 * 字段,暂时先通过");
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
Set<String> queryFields = sqlInfo.getAllRealSelectFields();
|
// Set<String> queryFields = sqlInfo.getAllRealSelectFields();
|
||||||
// 校验表名和字段是否允许查询
|
// // 校验表名和字段是否允许查询
|
||||||
String tableName = entry.getKey();
|
// String tableName = entry.getKey();
|
||||||
if (!this.checkWhiteList(tableName, queryFields)) {
|
// if (!this.checkWhiteList(tableName, queryFields)) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,20 +120,21 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
|
|||||||
if (oConvertUtils.isEmpty(tableName)) {
|
if (oConvertUtils.isEmpty(tableName)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (fields == null || fields.length == 0) {
|
// if (fields == null || fields.length == 0) {
|
||||||
fields = new String[]{"*"};
|
// fields = new String[]{"*"};
|
||||||
}
|
// }
|
||||||
String sql = "select " + String.join(",", fields) + " from " + tableName;
|
// String sql = "select " + String.join(",", fields) + " from " + tableName;
|
||||||
log.info("字典拼接的查询SQL:{}", sql);
|
// log.info("字典拼接的查询SQL:{}", sql);
|
||||||
try {
|
// try {
|
||||||
// 进行SQL解析
|
// // 进行SQL解析
|
||||||
JSqlParserUtils.parseSelectSqlInfo(sql);
|
// JSqlParserUtils.parseSelectSqlInfo(sql);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
// 如果SQL解析失败,则通过字段名和表名进行校验
|
// // 如果SQL解析失败,则通过字段名和表名进行校验
|
||||||
return checkWhiteList(tableName, new HashSet<>(Arrays.asList(fields)));
|
// return checkWhiteList(tableName, new HashSet<>(Arrays.asList(fields)));
|
||||||
}
|
// }
|
||||||
// 通过SQL解析进行校验,可防止SQL注入
|
// // 通过SQL解析进行校验,可防止SQL注入
|
||||||
return this.isPassBySql(sql);
|
// return this.isPassBySql(sql);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,124 +1,124 @@
|
|||||||
package org.jeecg.config.jimureport;
|
//package org.jeecg.config.jimureport;
|
||||||
|
//
|
||||||
import com.alibaba.fastjson.JSONObject;
|
//import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.dto.LogDTO;
|
//import org.jeecg.common.api.dto.LogDTO;
|
||||||
import org.jeecg.common.system.api.ISysBaseAPI;
|
//import org.jeecg.common.system.api.ISysBaseAPI;
|
||||||
import org.jeecg.common.system.vo.DictModel;
|
//import org.jeecg.common.system.vo.DictModel;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
//import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
//import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.modules.drag.service.IOnlDragExternalService;
|
//import org.jeecg.modules.drag.service.IOnlDragExternalService;
|
||||||
import org.jeecg.modules.drag.vo.DragDictModel;
|
//import org.jeecg.modules.drag.vo.DragDictModel;
|
||||||
import org.jeecg.modules.drag.vo.DragLogDTO;
|
//import org.jeecg.modules.drag.vo.DragLogDTO;
|
||||||
import org.springframework.beans.BeanUtils;
|
//import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Lazy;
|
//import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
//import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
//import org.springframework.util.CollectionUtils;
|
||||||
|
//
|
||||||
import java.util.ArrayList;
|
//import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
//import java.util.HashMap;
|
||||||
import java.util.List;
|
//import java.util.List;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* @Description: 字典处理
|
// * @Description: 字典处理
|
||||||
* @Author: lsq
|
// * @Author: lsq
|
||||||
* @Date:2023-01-09
|
// * @Date:2023-01-09
|
||||||
* @Version:V1.0
|
// * @Version:V1.0
|
||||||
*/
|
// */
|
||||||
@Slf4j
|
//@Slf4j
|
||||||
@Service("onlDragExternalServiceImpl")
|
//@Service("onlDragExternalServiceImpl")
|
||||||
public class JimuDragExternalServiceImpl implements IOnlDragExternalService {
|
//public class JimuDragExternalServiceImpl implements IOnlDragExternalService {
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
@Lazy
|
// @Lazy
|
||||||
private BaseCommonService baseCommonService;
|
// private BaseCommonService baseCommonService;
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
@Lazy
|
// @Lazy
|
||||||
private ISysBaseAPI sysBaseApi;
|
// private ISysBaseAPI sysBaseApi;
|
||||||
/**
|
// /**
|
||||||
* 根据多个字典code查询多个字典项
|
// * 根据多个字典code查询多个字典项
|
||||||
* @param codeList
|
// * @param codeList
|
||||||
* @return key = dictCode ; value=对应的字典项
|
// * @return key = dictCode ; value=对应的字典项
|
||||||
*/
|
// */
|
||||||
@Override
|
// @Override
|
||||||
public Map<String, List<DragDictModel>> getManyDictItems(List<String> codeList, List<JSONObject> tableDictList) {
|
// public Map<String, List<DragDictModel>> getManyDictItems(List<String> codeList, List<JSONObject> tableDictList) {
|
||||||
Map<String, List<DragDictModel>> manyDragDictItems = new HashMap<>();
|
// Map<String, List<DragDictModel>> manyDragDictItems = new HashMap<>();
|
||||||
if(!CollectionUtils.isEmpty(codeList)){
|
// if(!CollectionUtils.isEmpty(codeList)){
|
||||||
Map<String, List<DictModel>> dictItemsMap = sysBaseApi.getManyDictItems(codeList);
|
// Map<String, List<DictModel>> dictItemsMap = sysBaseApi.getManyDictItems(codeList);
|
||||||
dictItemsMap.forEach((k,v)->{
|
// dictItemsMap.forEach((k,v)->{
|
||||||
List<DragDictModel> dictItems = new ArrayList<>();
|
// List<DragDictModel> dictItems = new ArrayList<>();
|
||||||
v.forEach(dictItem->{
|
// v.forEach(dictItem->{
|
||||||
DragDictModel dictModel = new DragDictModel();
|
// DragDictModel dictModel = new DragDictModel();
|
||||||
BeanUtils.copyProperties(dictItem,dictModel);
|
// BeanUtils.copyProperties(dictItem,dictModel);
|
||||||
dictItems.add(dictModel);
|
// dictItems.add(dictModel);
|
||||||
});
|
// });
|
||||||
manyDragDictItems.put(k,dictItems);
|
// manyDragDictItems.put(k,dictItems);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if(!CollectionUtils.isEmpty(tableDictList)){
|
// if(!CollectionUtils.isEmpty(tableDictList)){
|
||||||
tableDictList.forEach(item->{
|
// tableDictList.forEach(item->{
|
||||||
List<DragDictModel> dictItems = new ArrayList<>();
|
// List<DragDictModel> dictItems = new ArrayList<>();
|
||||||
JSONObject object = JSONObject.parseObject(item.toString());
|
// JSONObject object = JSONObject.parseObject(item.toString());
|
||||||
String dictField = object.getString("dictField");
|
// String dictField = object.getString("dictField");
|
||||||
String dictTable = object.getString("dictTable");
|
// String dictTable = object.getString("dictTable");
|
||||||
String dictText = object.getString("dictText");
|
// String dictText = object.getString("dictText");
|
||||||
String fieldName = object.getString("fieldName");
|
// String fieldName = object.getString("fieldName");
|
||||||
List<DictModel> dictItemsList = sysBaseApi.queryTableDictItemsByCode(dictTable,dictText,dictField);
|
// List<DictModel> dictItemsList = sysBaseApi.queryTableDictItemsByCode(dictTable,dictText,dictField);
|
||||||
dictItemsList.forEach(dictItem->{
|
// dictItemsList.forEach(dictItem->{
|
||||||
DragDictModel dictModel = new DragDictModel();
|
// DragDictModel dictModel = new DragDictModel();
|
||||||
BeanUtils.copyProperties(dictItem,dictModel);
|
// BeanUtils.copyProperties(dictItem,dictModel);
|
||||||
dictItems.add(dictModel);
|
// dictItems.add(dictModel);
|
||||||
});
|
// });
|
||||||
manyDragDictItems.put(fieldName,dictItems);
|
// manyDragDictItems.put(fieldName,dictItems);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
return manyDragDictItems;
|
// return manyDragDictItems;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
*
|
// *
|
||||||
* @param dictCode
|
// * @param dictCode
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
@Override
|
// @Override
|
||||||
public List<DragDictModel> getDictItems(String dictCode) {
|
// public List<DragDictModel> getDictItems(String dictCode) {
|
||||||
List<DragDictModel> dictItems = new ArrayList<>();
|
// List<DragDictModel> dictItems = new ArrayList<>();
|
||||||
if(oConvertUtils.isNotEmpty(dictCode)){
|
// if(oConvertUtils.isNotEmpty(dictCode)){
|
||||||
List<DictModel> dictItemsList = sysBaseApi.getDictItems(dictCode);
|
// List<DictModel> dictItemsList = sysBaseApi.getDictItems(dictCode);
|
||||||
dictItemsList.forEach(dictItem->{
|
// dictItemsList.forEach(dictItem->{
|
||||||
DragDictModel dictModel = new DragDictModel();
|
// DragDictModel dictModel = new DragDictModel();
|
||||||
BeanUtils.copyProperties(dictItem,dictModel);
|
// BeanUtils.copyProperties(dictItem,dictModel);
|
||||||
dictItems.add(dictModel);
|
// dictItems.add(dictModel);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
return dictItems;
|
// return dictItems;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 添加日志
|
// * 添加日志
|
||||||
* @param dragLogDTO
|
// * @param dragLogDTO
|
||||||
*/
|
// */
|
||||||
@Override
|
// @Override
|
||||||
public void addLog(DragLogDTO dragLogDTO) {
|
// public void addLog(DragLogDTO dragLogDTO) {
|
||||||
if(oConvertUtils.isNotEmpty(dragLogDTO)){
|
// if(oConvertUtils.isNotEmpty(dragLogDTO)){
|
||||||
LogDTO dto = new LogDTO();
|
// LogDTO dto = new LogDTO();
|
||||||
BeanUtils.copyProperties(dragLogDTO,dto);
|
// BeanUtils.copyProperties(dragLogDTO,dto);
|
||||||
baseCommonService.addLog(dto);
|
// baseCommonService.addLog(dto);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 保存日志
|
// * 保存日志
|
||||||
* @param logMsg
|
// * @param logMsg
|
||||||
* @param logType
|
// * @param logType
|
||||||
* @param operateType
|
// * @param operateType
|
||||||
*/
|
// */
|
||||||
@Override
|
// @Override
|
||||||
public void addLog(String logMsg, int logType, int operateType) {
|
// public void addLog(String logMsg, int logType, int operateType) {
|
||||||
baseCommonService.addLog(logMsg,logType,operateType);
|
// baseCommonService.addLog(logMsg,logType,operateType);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
@ -1,107 +1,107 @@
|
|||||||
package org.jeecg.config.jimureport;
|
//package org.jeecg.config.jimureport;
|
||||||
|
//
|
||||||
import lombok.extern.slf4j.Slf4j;
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.system.util.JwtUtil;
|
//import org.jeecg.common.system.util.JwtUtil;
|
||||||
import org.jeecg.common.system.vo.SysUserCacheInfo;
|
//import org.jeecg.common.system.vo.SysUserCacheInfo;
|
||||||
import org.jeecg.common.util.RedisUtil;
|
//import org.jeecg.common.util.RedisUtil;
|
||||||
import org.jeecg.common.util.TokenUtils;
|
//import org.jeecg.common.util.TokenUtils;
|
||||||
import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
|
//import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
|
||||||
import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
|
//import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Lazy;
|
//import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
//import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.CollectionUtils;
|
//import org.springframework.util.CollectionUtils;
|
||||||
|
//
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
//import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.HashMap;
|
//import java.util.HashMap;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
import java.util.Set;
|
//import java.util.Set;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 自定义积木报表鉴权(如果不进行自定义,则所有请求不做权限控制)
|
// * 自定义积木报表鉴权(如果不进行自定义,则所有请求不做权限控制)
|
||||||
* * 1.自定义获取登录token
|
// * * 1.自定义获取登录token
|
||||||
* * 2.自定义获取登录用户
|
// * * 2.自定义获取登录用户
|
||||||
* @author: jeecg-boot
|
// * @author: jeecg-boot
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
|
//
|
||||||
@Slf4j
|
//@Slf4j
|
||||||
@Component
|
//@Component
|
||||||
public class JimuReportTokenService implements JmReportTokenServiceI {
|
//public class JimuReportTokenService implements JmReportTokenServiceI {
|
||||||
@Autowired
|
// @Autowired
|
||||||
private SysBaseApiImpl sysBaseApi;
|
// private SysBaseApiImpl sysBaseApi;
|
||||||
@Autowired
|
// @Autowired
|
||||||
@Lazy
|
// @Lazy
|
||||||
private RedisUtil redisUtil;
|
// private RedisUtil redisUtil;
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public String getToken(HttpServletRequest request) {
|
// public String getToken(HttpServletRequest request) {
|
||||||
return TokenUtils.getTokenByRequest(request);
|
// return TokenUtils.getTokenByRequest(request);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public String getUsername(String token) {
|
// public String getUsername(String token) {
|
||||||
return JwtUtil.getUsername(token);
|
// return JwtUtil.getUsername(token);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public String[] getRoles(String token) {
|
// public String[] getRoles(String token) {
|
||||||
String username = JwtUtil.getUsername(token);
|
// String username = JwtUtil.getUsername(token);
|
||||||
Set roles = sysBaseApi.getUserRoleSet(username);
|
// Set roles = sysBaseApi.getUserRoleSet(username);
|
||||||
if(CollectionUtils.isEmpty(roles)){
|
// if(CollectionUtils.isEmpty(roles)){
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
return (String[]) roles.toArray(new String[roles.size()]);
|
// return (String[]) roles.toArray(new String[roles.size()]);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public Boolean verifyToken(String token) {
|
// public Boolean verifyToken(String token) {
|
||||||
return TokenUtils.verifyToken(token, sysBaseApi, redisUtil);
|
// return TokenUtils.verifyToken(token, sysBaseApi, redisUtil);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public Map<String, Object> getUserInfo(String token) {
|
// public Map<String, Object> getUserInfo(String token) {
|
||||||
Map<String, Object> map = new HashMap(5);
|
// Map<String, Object> map = new HashMap(5);
|
||||||
String username = JwtUtil.getUsername(token);
|
// String username = JwtUtil.getUsername(token);
|
||||||
//此处通过token只能拿到一个信息 用户账号 后面的就是根据账号获取其他信息 查询数据或是走redis 用户根据自身业务可自定义
|
// //此处通过token只能拿到一个信息 用户账号 后面的就是根据账号获取其他信息 查询数据或是走redis 用户根据自身业务可自定义
|
||||||
SysUserCacheInfo userInfo = null;
|
// SysUserCacheInfo userInfo = null;
|
||||||
try {
|
// try {
|
||||||
userInfo = sysBaseApi.getCacheUser(username);
|
// userInfo = sysBaseApi.getCacheUser(username);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("获取用户信息异常:"+ e.getMessage());
|
// log.error("获取用户信息异常:"+ e.getMessage());
|
||||||
return map;
|
// return map;
|
||||||
}
|
// }
|
||||||
//设置账号名
|
// //设置账号名
|
||||||
map.put(SYS_USER_CODE, userInfo.getSysUserCode());
|
// map.put(SYS_USER_CODE, userInfo.getSysUserCode());
|
||||||
//设置部门编码
|
// //设置部门编码
|
||||||
map.put(SYS_ORG_CODE, userInfo.getSysOrgCode());
|
// map.put(SYS_ORG_CODE, userInfo.getSysOrgCode());
|
||||||
// 将所有信息存放至map 解析sql/api会根据map的键值解析
|
// // 将所有信息存放至map 解析sql/api会根据map的键值解析
|
||||||
return map;
|
// return map;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 将jeecgboot平台的权限传递给积木报表
|
// * 将jeecgboot平台的权限传递给积木报表
|
||||||
* @param token
|
// * @param token
|
||||||
* @return
|
// * @return
|
||||||
*/
|
// */
|
||||||
@Override
|
// @Override
|
||||||
public String[] getPermissions(String token) {
|
// public String[] getPermissions(String token) {
|
||||||
// 获取用户信息
|
// // 获取用户信息
|
||||||
String username = JwtUtil.getUsername(token);
|
// String username = JwtUtil.getUsername(token);
|
||||||
SysUserCacheInfo userInfo = null;
|
// SysUserCacheInfo userInfo = null;
|
||||||
try {
|
// try {
|
||||||
userInfo = sysBaseApi.getCacheUser(username);
|
// userInfo = sysBaseApi.getCacheUser(username);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("获取用户信息异常:"+ e.getMessage());
|
// log.error("获取用户信息异常:"+ e.getMessage());
|
||||||
}
|
// }
|
||||||
if(userInfo == null){
|
// if(userInfo == null){
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
// 查询权限
|
// // 查询权限
|
||||||
Set<String> userPermissions = sysBaseApi.getUserPermissionSet(userInfo.getSysUserId());
|
// Set<String> userPermissions = sysBaseApi.getUserPermissionSet(userInfo.getSysUserId());
|
||||||
if(CollectionUtils.isEmpty(userPermissions)){
|
// if(CollectionUtils.isEmpty(userPermissions)){
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
return userPermissions.toArray(new String[0]);
|
// return userPermissions.toArray(new String[0]);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -1,64 +1,56 @@
|
|||||||
|
////
|
||||||
|
//// Source code recreated from a .class file by IntelliJ IDEA
|
||||||
|
//// (powered by Fernflower decompiler)
|
||||||
|
////
|
||||||
//
|
//
|
||||||
// Source code recreated from a .class file by IntelliJ IDEA
|
//package org.springframework.boot.autoconfigure.mongo;
|
||||||
// (powered by Fernflower decompiler)
|
|
||||||
//
|
//
|
||||||
|
//import com.mongodb.MongoClientSettings;
|
||||||
package org.springframework.boot.autoconfigure.mongo;
|
//import com.mongodb.client.MongoClient;
|
||||||
|
//import org.springframework.beans.factory.ObjectProvider;
|
||||||
import com.mongodb.MongoClientSettings;
|
//import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import com.mongodb.client.MongoClient;
|
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
//import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
//import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
//import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
//import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
//import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.boot.autoconfigure.mongo.MongoClientFactory;
|
//import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCustomizer;
|
//import org.springframework.core.env.Environment;
|
||||||
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
|
//
|
||||||
import org.springframework.boot.autoconfigure.mongo.MongoPropertiesClientSettingsBuilderCustomizer;
|
//import java.util.List;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
//import java.util.stream.Collectors;
|
||||||
import org.springframework.context.annotation.Bean;
|
//
|
||||||
import org.springframework.context.annotation.Configuration;
|
//@Primary
|
||||||
import org.springframework.context.annotation.Primary;
|
//@AutoConfiguration
|
||||||
import org.springframework.core.env.Environment;
|
//@ConditionalOnClass({MongoClient.class})
|
||||||
|
//@ConditionalOnProperty(name = "spring.data.mongodb.uri", havingValue = "", matchIfMissing = false)
|
||||||
import java.util.List;
|
//@EnableConfigurationProperties({MongoProperties.class})
|
||||||
import java.util.stream.Collectors;
|
//@ConditionalOnMissingBean(
|
||||||
|
// type = {"org.springframework.data.mongodb.MongoDatabaseFactory"}
|
||||||
@Primary
|
//)
|
||||||
@AutoConfiguration
|
//public class MongoAutoConfiguration {
|
||||||
@ConditionalOnClass({MongoClient.class})
|
// public MongoAutoConfiguration() {
|
||||||
@ConditionalOnProperty(name = "spring.data.mongodb.uri", havingValue = "", matchIfMissing = false)
|
// }
|
||||||
@EnableConfigurationProperties({MongoProperties.class})
|
//
|
||||||
@ConditionalOnMissingBean(
|
// @Bean
|
||||||
type = {"org.springframework.data.mongodb.MongoDatabaseFactory"}
|
// @ConditionalOnMissingBean({MongoClient.class})
|
||||||
)
|
// public MongoClient mongo(ObjectProvider<MongoClientSettingsBuilderCustomizer> builderCustomizers, MongoClientSettings settings) {
|
||||||
public class MongoAutoConfiguration {
|
// return (MongoClient)(new MongoClientFactory((List)builderCustomizers.orderedStream().collect(Collectors.toList()))).createMongoClient(settings);
|
||||||
public MongoAutoConfiguration() {
|
// }
|
||||||
}
|
//
|
||||||
|
// @Configuration(
|
||||||
@Bean
|
// proxyBeanMethods = false
|
||||||
@ConditionalOnMissingBean({MongoClient.class})
|
// )
|
||||||
public MongoClient mongo(ObjectProvider<MongoClientSettingsBuilderCustomizer> builderCustomizers, MongoClientSettings settings) {
|
// @ConditionalOnMissingBean({MongoClientSettings.class})
|
||||||
return (MongoClient)(new MongoClientFactory((List)builderCustomizers.orderedStream().collect(Collectors.toList()))).createMongoClient(settings);
|
// static class MongoClientSettingsConfiguration {
|
||||||
}
|
// MongoClientSettingsConfiguration() {
|
||||||
|
// }
|
||||||
@Configuration(
|
//
|
||||||
proxyBeanMethods = false
|
// @Bean
|
||||||
)
|
// MongoClientSettings mongoClientSettings() {
|
||||||
@ConditionalOnMissingBean({MongoClientSettings.class})
|
// return MongoClientSettings.builder().build();
|
||||||
static class MongoClientSettingsConfiguration {
|
// }
|
||||||
MongoClientSettingsConfiguration() {
|
//
|
||||||
}
|
// }
|
||||||
|
//}
|
||||||
@Bean
|
|
||||||
MongoClientSettings mongoClientSettings() {
|
|
||||||
return MongoClientSettings.builder().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
MongoPropertiesClientSettingsBuilderCustomizer mongoPropertiesCustomizer(MongoProperties properties, Environment environment) {
|
|
||||||
return new MongoPropertiesClientSettingsBuilderCustomizer(properties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>3.1.5</version>
|
<version>3.4.4</version>
|
||||||
<relativePath/>
|
<relativePath/>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@ -33,8 +33,8 @@
|
|||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
|
||||||
<!-- 微服务 -->
|
<!-- 微服务 -->
|
||||||
<spring-cloud.version>2022.0.4</spring-cloud.version>
|
<spring-cloud.version>2024.0.1</spring-cloud.version>
|
||||||
<spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
|
<spring-cloud-alibaba.version>2023.0.3.2</spring-cloud-alibaba.version>
|
||||||
<alibaba.nacos.version>2.0.4</alibaba.nacos.version>
|
<alibaba.nacos.version>2.0.4</alibaba.nacos.version>
|
||||||
|
|
||||||
<xxl-job-core.version>2.4.1</xxl-job-core.version>
|
<xxl-job-core.version>2.4.1</xxl-job-core.version>
|
||||||
@ -56,7 +56,7 @@
|
|||||||
<!-- 积木报表-->
|
<!-- 积木报表-->
|
||||||
<jimureport-spring-boot-starter.version>1.9.4</jimureport-spring-boot-starter.version>
|
<jimureport-spring-boot-starter.version>1.9.4</jimureport-spring-boot-starter.version>
|
||||||
<!-- 持久层 -->
|
<!-- 持久层 -->
|
||||||
<mybatis-plus.version>3.5.3.2</mybatis-plus.version>
|
<mybatis-plus.version>3.5.11</mybatis-plus.version>
|
||||||
<dynamic-datasource-spring-boot-starter.version>4.1.3</dynamic-datasource-spring-boot-starter.version>
|
<dynamic-datasource-spring-boot-starter.version>4.1.3</dynamic-datasource-spring-boot-starter.version>
|
||||||
<druid.version>1.2.24</druid.version>
|
<druid.version>1.2.24</druid.version>
|
||||||
|
|
||||||
@ -79,7 +79,7 @@
|
|||||||
<!-- Log4j2爆雷漏洞 -->
|
<!-- Log4j2爆雷漏洞 -->
|
||||||
<!-- spring boot 3 不支持下列两个版本-->
|
<!-- spring boot 3 不支持下列两个版本-->
|
||||||
<!--<log4j2.version>2.17.0</log4j2.version>-->
|
<!--<log4j2.version>2.17.0</log4j2.version>-->
|
||||||
<logback.version>1.4.12</logback.version>
|
<!--<logback.version>1.4.12</logback.version>-->
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
|
|||||||
Reference in New Issue
Block a user