以下是使用Java和druid解析sql,并通过feign接口查询到的表元数据,替换包含left join的insert into table select sql语句中的*的代码示例:
时间: 2023-11-22 07:53:22 浏览: 101
以下是使用Java和druid解析sql,并通过feign接口查询到的表元数据,替换包含left join的insert into table select sql语句中的*的代码示例:
```java
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import feign.Feign;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.okhttp.OkHttpClient;
import feign.slf4j.Slf4jLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class SqlParserUtils {
/**
* 解析insert into table select语句中的表名
*/
public static String parseTableName(String sql) {
List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
SQLInsertStatement insertStmt = (SQLInsertStatement) stmtList.get(0);
SQLSelectStatement selectStmt = (SQLSelectStatement) insertStmt.getQuery().getQuery();
SQLSelect sqlSelect = selectStmt.getSelect();
SQLSelectQueryBlock sqlSelectQuery = (SQLSelectQueryBlock) sqlSelect.getQuery();
SQLTableSource tableSource = sqlSelectQuery.getFrom();
if (tableSource instanceof SQLExprTableSource) {
return ((SQLExprTableSource) tableSource).getName().getSimpleName();
} else if (tableSource instanceof SQLJoinTableSource) {
SQLJoinTableSource joinSource = (SQLJoinTableSource) tableSource;
SQLTableSource left = joinSource.getLeft();
if (left instanceof SQLExprTableSource) {
return ((SQLExprTableSource) left).getName().getSimpleName();
}
}
throw new IllegalArgumentException("无法解析的SQL语句");
}
/**
* 解析insert into table select语句中的列名
*/
public static List<String> parseColumnNames(String sql) {
List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
SQLInsertStatement insertStmt = (SQLInsertStatement) stmtList.get(0);
SQLSelectStatement selectStmt = (SQLSelectStatement) insertStmt.getQuery().getQuery();
SQLSelect sqlSelect = selectStmt.getSelect();
SQLSelectQueryBlock sqlSelectQuery = (SQLSelectQueryBlock) sqlSelect.getQuery();
List<SQLSelectItem> selectList = sqlSelectQuery.getSelectList();
List<String> columnNames = new ArrayList<>();
for (SQLSelectItem selectItem : selectList) {
SQLExpr expr = selectItem.getExpr();
if (expr instanceof SQLIdentifierExpr) {
columnNames.add(((SQLIdentifierExpr) expr).getName());
}
}
return columnNames;
}
/**
* 替换insert into table select语句中的*为实际列名
*/
public static String replaceAsterisk(String sql, List<String> columnNames) {
SQLSelectParser parser = new MySqlSelectParser(sql);
SQLSelect select = parser.select();
SQLSelectQueryBlock query = (SQLSelectQueryBlock) select.getQuery();
List<SQLSelectItem> selectList = query.getSelectList();
if (!CollectionUtils.isEmpty(selectList)) {
for (int i = 0; i < selectList.size(); i++) {
SQLSelectItem selectItem = selectList.get(i);
SQLExpr expr = selectItem.getExpr();
if (expr instanceof SQLAllColumnExpr) {
selectList.remove(i);
for (String columnName : columnNames) {
SQLSelectItem newSelectItem = new SQLSelectItem(new SQLIdentifierExpr(columnName));
selectList.add(i, newSelectItem);
i++;
}
break;
}
}
}
return SQLUtils.toMySqlString(select);
}
/**
* 查询表元数据
*/
public static JSONObject getTableMetadata(String tableName, String metadataServiceUrl) {
Feign.Builder builder = Feign.builder()
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.logger(new Slf4jLogger(SqlParserUtils.class))
.client(new OkHttpClient());
MetadataServiceClient client = builder.target(MetadataServiceClient.class, metadataServiceUrl);
Map<String, Object> result = client.getTableMetadata(tableName);
return JSON.parseObject(JSON.toJSONString(result));
}
/**
* 替换insert into table select语句中的*为实际列名,并获取列的类型信息
*/
public static String replaceAsteriskAndGetType(String sql, String metadataServiceUrl) {
String tableName = parseTableName(sql);
List<String> columnNames = parseColumnNames(sql);
JSONObject tableMetadata = getTableMetadata(tableName, metadataServiceUrl);
List<JSONObject> columns = tableMetadata.getJSONArray("columns").toJavaList(JSONObject.class);
List<String> columnTypes = columns.stream().filter(column -> columnNames.contains(column.getString("name")))
.map(column -> column.getString("type")).collect(Collectors.toList());
String replacedSql = replaceAsterisk(sql, columnNames);
String columnTypesStr = Joiner.on(",").join(columnTypes);
return String.format("%s/*{%s}*/", replacedSql, columnTypesStr);
}
}
```
其中,MetadataServiceClient为通过Feign实现的调用元数据服务接口的客户端,代码示例如下:
```java
import feign.RequestLine;
import java.util.Map;
public interface MetadataServiceClient {
@RequestLine("GET /metadata/tables/{tableName}")
Map<String, Object> getTableMetadata(String tableName);
}
```
阅读全文