sql解析和执行

This commit is contained in:
蓝白 committed 2023-03-16 21:38:27 +08:00
1 parent dc1a49d72d
commit 8ad7079b6a
34 files changed
+478 -358

No files matched your search

-5
View File
@@ -46,11 +46,6 @@
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>${jsqlparser.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
@@ -3,13 +3,11 @@ package cn.crabc.core.admin.api;
import cn.crabc.core.admin.entity.dto.ApiInfoDTO;
import cn.crabc.core.admin.service.core.IBaseDataService;
import cn.crabc.core.admin.util.ApiThreadLocal;
import cn.crabc.core.admin.util.RequestUtils;
import cn.crabc.core.admin.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -26,26 +24,60 @@ public class ApiServiceController {
private IBaseDataService baseDataService;
/**
* API请求方法
* API GET请求方法
*
* @param request
* @return
*/
@RequestMapping("/**")
public Result service(HttpServletRequest request) {
ApiInfoDTO apiInfo = ApiThreadLocal.get();
if (apiInfo == null) {
@RequestMapping(value = "/**", method = {RequestMethod.GET, RequestMethod.DELETE, RequestMethod.PATCH})
public Result getService(@RequestParam Map<String, Object> paramMap) {
ApiInfoDTO api = ApiThreadLocal.get();
if (api == null) {
return Result.error(5001, "请求地址不存在!");
}
Map<String, Object> params = RequestUtils.getParameters(request);
// post请求才解析body
if ("POST".equals(request.getMethod().toUpperCase())) {
Map<String, Object> bodyMap = RequestUtils.getBodyMap(request);
if (bodyMap != null && !bodyMap.isEmpty()) {
params.putAll(bodyMap);
List<Object> params = new ArrayList<>();
if (paramMap != null && paramMap.size() > 0) {
params.add(paramMap);
}
Object query = null;
if (api.getSqlScript().trim().startsWith("select") || api.getSqlScript().trim().startsWith("SELECT")) {
query = baseDataService.query(api.getDatasourceId(), api.getSchemaName(), api.getSqlScript(), params);
} else {
query = baseDataService.execute(api.getDatasourceId(), api.getSchemaName(), api.getSqlScript(), params);
}
return Result.success(query);
}
/**
* API post请求
*
* @param paramMap
* @param body
* @return
*/
@RequestMapping(value = "/**", method = {RequestMethod.POST, RequestMethod.PUT})
public Result postService(@RequestParam Map<String, Object> paramMap, @RequestBody Object body) {
ApiInfoDTO api = ApiThreadLocal.get();
if (api == null) {
return Result.error(5001, "请求地址不存在!");
}
List<Object> params = new ArrayList<>();
if (paramMap != null && paramMap.size() > 0) {
params.add(paramMap);
}
if (body instanceof Map) {
Map<String, Object> map = (Map<String, Object>) body;
params.add(map);
} else if (body instanceof List) {
List<Object> list = (List<Object>) body;
params.addAll(list);
}
Object query = null;
if (api.getSqlScript().trim().startsWith("select") || api.getSqlScript().trim().startsWith("SELECT")) {
query = baseDataService.query(api.getDatasourceId(), api.getSchemaName(), api.getSqlScript(), params);
} else {
query = baseDataService.execute(api.getDatasourceId(), api.getSchemaName(), api.getSqlScript(), params);
}
List<Map<String, Object>> query = baseDataService.query(apiInfo.getDatasourceId(), apiInfo.getSchemaName(), apiInfo.getSqlScript(), params);
return Result.success(query);
}
}
@@ -1,10 +1,10 @@
package cn.crabc.core.admin.component;
import cn.crabc.core.app.driver.DataSourceManager;
import cn.crabc.core.spi.bean.BaseDataSource;
import cn.crabc.core.admin.service.system.IBaseApiInfoService;
import cn.crabc.core.admin.service.system.IBaseDataSourceService;
import cn.crabc.core.admin.util.RSAUtils;
import cn.crabc.core.app.driver.DataSourceManager;
import cn.crabc.core.spi.bean.BaseDataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -10,7 +10,8 @@ import cn.crabc.core.admin.entity.vo.SqlParseVO;
import cn.crabc.core.admin.service.system.IBaseApiInfoService;
import cn.crabc.core.admin.util.PageInfo;
import cn.crabc.core.admin.util.Result;
import cn.crabc.core.admin.util.SQLUtils;
import cn.crabc.core.admin.util.SQLUtil;
import cn.crabc.core.admin.util.UserThreadLocal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -111,6 +112,17 @@ public class ApiInfoController {
return Result.success();
}
/**
* 删除API
*
* @param apiId
* @return
*/
@DeleteMapping("/{apiId}")
public Result deleteApi(@PathVariable Long apiId) {
return Result.success(apiInfoService.deleteApi(apiId, UserThreadLocal.getUserId()));
}
/**
* SQL解析
*
@@ -120,12 +132,12 @@ public class ApiInfoController {
@PostMapping("/sqlParse")
public Result sqlParse(@RequestBody SqlParseVO sqlParse) {
SqlParseVO sqlParseVO = new SqlParseVO();
// 返回字段
Set<String> paramNames = SQLUtils.parseParams(sqlParse.getSqlScript());
sqlParseVO.setReqColumns(paramNames);
// 条件字段
Set<String> paramNames = SQLUtil.parseParams(sqlParse.getSqlScript());
sqlParseVO.setReqColumns(paramNames);
// 返回字段
Set<ColumnParseVo> resColumns = new HashSet<>();
Set<String> resNames = SQLUtils.parseColumns(sqlParse.getSqlScript());
Set<String> resNames = SQLUtil.analyzeSQL(sqlParse.getSqlScript(), sqlParse.getDatasourceType());
for (String name : resNames) {
ColumnParseVo resColumn = new ColumnParseVo();
resColumn.setColName(name);
@@ -140,12 +152,12 @@ public class ApiInfoController {
/**
* 校验接口url
*
* @param baseApiInfo
* @param api
* @return
*/
@PostMapping("/check")
public Result checkPath(@RequestBody BaseApiInfo baseApiInfo) {
Boolean result = apiInfoService.checkApiPath(baseApiInfo.getApiPath(), baseApiInfo.getApiMethod());
public Result checkPath(@RequestBody BaseApiInfo api) {
Boolean result = apiInfoService.checkApiPath(api.getApiId(),api.getApiPath(), api.getApiMethod());
if (result) {
return Result.error("50011", "该接口地址已存在");
}
@@ -1,9 +1,7 @@
package cn.crabc.core.admin.controller;
import cn.crabc.core.admin.entity.BaseApiSql;
import cn.crabc.core.admin.entity.param.ApiTestParam;
import cn.crabc.core.admin.entity.vo.PreviewVO;
import cn.crabc.core.admin.service.system.IBaseApiSqlService;
import cn.crabc.core.admin.service.system.IBaseApiTestService;
import cn.crabc.core.admin.util.Result;
import com.alibaba.fastjson2.JSON;
@@ -24,8 +22,6 @@ public class ApiTestController {
@Autowired
private IBaseApiTestService baseapitestService;
@Autowired
private IBaseApiSqlService baseApiSqlService;
/**
@@ -46,10 +42,6 @@ public class ApiTestController {
*/
@PostMapping("/verify/{apiId}")
public Result testApiSql(@PathVariable Long apiId, @RequestBody ApiTestParam params) {
// BaseApiSql apiSql = baseApiSqlService.getApiSql(apiId);
// if (apiSql == null){
// return Result.error(52002,"API不存在");
// }
if (params.getDatasourceType() == null){
params.setDatasourceType("mysql");
}
@@ -43,13 +43,23 @@ public class BaseGroupController {
return Result.success();
}
/**
* 编辑分组
* @param baseGroup
* @return
*/
@PutMapping
public Result updateGroup(@RequestBody BaseGroup baseGroup){
iBaseGroupService.updateGroup(baseGroup,UserThreadLocal.getUserId());
return Result.success();
}
@DeleteMapping
/**
* 删除分组
* @param groupId
* @return
*/
@DeleteMapping("/{groupId}")
public Result deleteGroup(@PathVariable Integer groupId){
iBaseGroupService.delteGroup(groupId, UserThreadLocal.getUserId());
return Result.success();
@@ -1,13 +1,13 @@
package cn.crabc.core.admin.controller;
import cn.crabc.core.admin.entity.BaseDatasource;
import cn.crabc.core.admin.service.system.IBaseDataSourceService;
import cn.crabc.core.admin.util.Result;
import cn.crabc.core.app.driver.DataSourceManager;
import cn.crabc.core.spi.DataSourceDriver;
import cn.crabc.core.spi.bean.Column;
import cn.crabc.core.spi.bean.Schema;
import cn.crabc.core.spi.bean.Table;
import cn.crabc.core.admin.entity.BaseDatasource;
import cn.crabc.core.admin.service.system.IBaseDataSourceService;
import cn.crabc.core.admin.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
@@ -61,11 +61,32 @@ public class BaseApiInfo extends BaseEntity {
*/
private String version;
/**
* 分页设置,不分页:0、只分页:1、分页并统计:2
* sql语句脚本
*/
private String sqlScript;
/**
* 分页设置,不分页:0、只分页:page、分页并统计:pageCount
*/
private Integer pageSetup;
/**
* 数据源Id
*/
private String datasourceId;
/**
* schema
*/
private String schemaName;
/**
* 数据源类型
*/
private String datasourceType;
/**
* 发布时间
*/
@@ -195,4 +216,36 @@ public class BaseApiInfo extends BaseEntity {
public void setPageSetup(Integer pageSetup) {
this.pageSetup = pageSetup;
}
public String getSqlScript() {
return sqlScript;
}
public void setSqlScript(String sqlScript) {
this.sqlScript = sqlScript;
}
public String getDatasourceId() {
return datasourceId;
}
public void setDatasourceId(String datasourceId) {
this.datasourceId = datasourceId;
}
public String getSchemaName() {
return schemaName;
}
public void setSchemaName(String schemaName) {
this.schemaName = schemaName;
}
public String getDatasourceType() {
return datasourceType;
}
public void setDatasourceType(String datasourceType) {
this.datasourceType = datasourceType;
}
}
@@ -8,6 +8,8 @@ public class ApiComboBoxVO {
private String apiType;
private String apiStatus;
public Long getApiId() {
return apiId;
}
@@ -31,4 +33,12 @@ public class ApiComboBoxVO {
public void setApiType(String apiType) {
this.apiType = apiType;
}
public String getApiStatus() {
return apiStatus;
}
public void setApiStatus(String apiStatus) {
this.apiStatus = apiStatus;
}
}
@@ -11,6 +11,8 @@ public class SqlParseVO {
private String sqlScript;
private String datasourceType;
public Set<String> getReqColumns() {
return reqColumns;
}
@@ -34,4 +36,12 @@ public class SqlParseVO {
public void setSqlScript(String sqlScript) {
this.sqlScript = sqlScript;
}
public String getDatasourceType() {
return datasourceType;
}
public void setDatasourceType(String datasourceType) {
this.datasourceType = datasourceType;
}
}
@@ -1,6 +1,5 @@
package cn.crabc.core.admin.filter;
import cn.crabc.core.app.exception.CustomException;
import cn.crabc.core.admin.entity.BaseApiLog;
import cn.crabc.core.admin.entity.BaseApp;
import cn.crabc.core.admin.entity.dto.ApiInfoDTO;
@@ -8,6 +7,7 @@ import cn.crabc.core.admin.enums.ApiAuthEnum;
import cn.crabc.core.admin.service.system.IBaseApiLogService;
import cn.crabc.core.admin.util.ApiThreadLocal;
import cn.crabc.core.admin.util.RequestUtils;
import cn.crabc.core.app.exception.CustomException;
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -1,8 +1,8 @@
package cn.crabc.core.admin.filter;
import cn.crabc.core.app.exception.CustomException;
import cn.crabc.core.admin.util.JwtUtil;
import cn.crabc.core.admin.util.UserThreadLocal;
import cn.crabc.core.app.exception.CustomException;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.lang.Nullable;
@@ -47,13 +47,13 @@ public interface BaseApiInfoMapper {
BaseApiInfo selectApiById(Long apiId);
/**
* 根据API地址查询详情
* 校验api地址是否已经存在
*
* @param apiPath
* @param method
* @return
*/
BaseApiInfo selectApiInfo(@Param("apiPath") String apiPath, @Param("method") String method);
Integer checkApiPath(@Param("apiId") Long apiId, @Param("apiPath") String apiPath, @Param("method") String method);
List<ApiInfoDTO> selectApiDetail(Long apiId);
@@ -82,6 +82,13 @@ public interface BaseApiInfoMapper {
*/
Integer updateApiState(BaseApiInfo apiInfo);
/**
* 删除API
* @param apiId
* @return
*/
Integer deleteApiInfo(@Param("apiId") Long apiId,@Param("userId") String userId);
/**
* API校验统计
*
@@ -1,6 +1,7 @@
package cn.crabc.core.admin.mapper;
import cn.crabc.core.admin.entity.BaseApiSql;
import org.apache.ibatis.annotations.Param;
/**
* API SQL配置 Mapper接口
@@ -35,5 +36,5 @@ public interface BaseApiSqlMapper{
* @param apiId
* @return
*/
Integer deleteApiSql(Integer apiId);
Integer deleteApiSql(@Param("apiId") Long apiId, @Param("userId") String userId);
}
@@ -1,8 +1,8 @@
package cn.crabc.core.admin.mapper;
import cn.crabc.core.spi.bean.BaseDataSource;
import cn.crabc.core.admin.entity.BaseDatasource;
import cn.crabc.core.spi.bean.BaseDataSource;
import java.util.List;
@@ -37,7 +37,7 @@ public interface IBaseDataService {
* @param params
* @return
*/
List<Map<String, Object>> query(String datasourceId, String schema, String sql, Map<String, Object> params);
List<Map<String, Object>> query(String datasourceId, String schema, String sql, List<Object> params);
/**
* 通用操作方法
@@ -47,5 +47,5 @@ public interface IBaseDataService {
* @param params
* @return
*/
Integer update(String datasourceId, String schema, String sql, Map<String, Object> params);
Integer execute(String datasourceId, String schema, String sql, List<Object> params);
}
@@ -1,13 +1,12 @@
package cn.crabc.core.admin.service.core.impl;
import cn.crabc.core.app.constant.BaseConstant;
import cn.crabc.core.admin.service.core.IBaseDataService;
import cn.crabc.core.app.driver.DataSourceManager;
import cn.crabc.core.spi.DataSourceDriver;
import cn.crabc.core.spi.bean.BaseDataSource;
import cn.crabc.core.spi.bean.Column;
import cn.crabc.core.spi.bean.Table;
import cn.crabc.core.admin.service.core.IBaseDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -47,15 +46,17 @@ public class BaseDataServiceImpl implements IBaseDataService {
}
@Override
public List<Map<String, Object>> query(String datasourceId, String schema, String sql, Map<String, Object> params) {
public List<Map<String, Object>> query(String datasourceId, String schema, String sql, List<Object> params) {
DataSourceDriver dataSourceDriver = dataSourceManager.getDataSource(datasourceId);
return dataSourceDriver.selectList(datasourceId, schema, sql, params);
return dataSourceDriver.selectList(datasourceId, schema, sql, params.get(0));
}
@Override
public Integer update(String datasourceId, String schema, String sql, Map<String, Object> params) {
public Integer execute(String datasourceId, String schema, String sql, List<Object> params) {
DataSourceDriver dataSourceDriver = dataSourceManager.getDataSource(datasourceId);
params.put(BaseConstant.DATA_SOURCE_ID, datasourceId);
return dataSourceDriver.update(sql, params);
for(Object param : params) {
dataSourceDriver.execute(datasourceId, schema, sql, param);
}
return 1;
}
}
@@ -59,7 +59,7 @@ public interface IBaseApiInfoService {
* @param method
* @return
*/
Boolean checkApiPath(String apiPath, String method);
Boolean checkApiPath(Long apiId, String apiPath, String method);
/**
* apiId获取详情
@@ -103,6 +103,14 @@ public interface IBaseApiInfoService {
*/
Integer updateApiState(Long apiId, String status, Integer enabled);
/**
* 删除API
* @param apiId
* @param userId
* @return
*/
Integer deleteApi(Long apiId, String userId);
/**
* API发布
*
@@ -36,5 +36,5 @@ public interface IBaseApiSqlService {
* @param apiId
* @return
*/
Integer deleteApiSql(Integer apiId);
Integer deleteApiSql(Long apiId, String userId);
}
@@ -1,8 +1,8 @@
package cn.crabc.core.admin.service.system;
import cn.crabc.core.spi.bean.BaseDataSource;
import cn.crabc.core.admin.entity.BaseDatasource;
import cn.crabc.core.admin.util.PageInfo;
import cn.crabc.core.spi.bean.BaseDataSource;
import java.util.List;
@@ -1,6 +1,5 @@
package cn.crabc.core.admin.service.system.impl;
import cn.crabc.core.app.exception.CustomException;
import cn.crabc.core.admin.entity.BaseApiInfo;
import cn.crabc.core.admin.entity.BaseApiSql;
import cn.crabc.core.admin.entity.BaseApp;
@@ -11,14 +10,15 @@ import cn.crabc.core.admin.entity.vo.ApiComboBoxVO;
import cn.crabc.core.admin.entity.vo.ApiInfoVO;
import cn.crabc.core.admin.enums.ApiStateEnum;
import cn.crabc.core.admin.mapper.BaseApiInfoMapper;
import cn.crabc.core.admin.mapper.BaseApiSqlMapper;
import cn.crabc.core.admin.mapper.BaseAppApiMapper;
import cn.crabc.core.admin.mapper.BaseAppMapper;
import cn.crabc.core.admin.service.system.IBaseApiInfoService;
import cn.crabc.core.admin.util.PageInfo;
import cn.crabc.core.admin.util.UserThreadLocal;
import cn.crabc.core.app.exception.CustomException;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
@@ -42,8 +42,6 @@ public class BaseApiInfoServiceImpl implements IBaseApiInfoService {
@Autowired
private BaseApiInfoMapper apiInfoMapper;
@Autowired
private BaseApiSqlMapper apiSqlMapper;
@Autowired
private BaseAppMapper baseAppMapper;
@Autowired
private BaseAppApiMapper baseAppApiMapper;
@@ -102,9 +100,9 @@ public class BaseApiInfoServiceImpl implements IBaseApiInfoService {
}
@Override
public Boolean checkApiPath(String apiPath, String method) {
BaseApiInfo baseApiInfo = apiInfoMapper.selectApiInfo(apiPath, method);
return baseApiInfo != null ? true : false;
public Boolean checkApiPath(Long apiId, String apiPath, String method) {
Integer count = apiInfoMapper.checkApiPath(apiId, apiPath, method);
return count > 0 ? true : false;
}
@Override
@@ -116,7 +114,8 @@ public class BaseApiInfoServiceImpl implements IBaseApiInfoService {
public ApiInfoVO getApiDetail(Long apiId) {
ApiInfoVO result = new ApiInfoVO();
BaseApiInfo baseApiInfo = apiInfoMapper.selectApiById(apiId);
BaseApiSql baseApiSql = apiSqlMapper.selectApiSql(apiId);
BaseApiSql baseApiSql = new BaseApiSql();
BeanUtils.copyProperties(baseApiInfo, baseApiSql);
result.setSqlInfo(baseApiSql);
baseApiInfo.setPageSetup(baseApiSql.getPageSetup());
result.setBaseInfo(baseApiInfo);
@@ -128,24 +127,22 @@ public class BaseApiInfoServiceImpl implements IBaseApiInfoService {
@Transactional(rollbackFor = Exception.class)
public Long addApiInfo(ApiInfoParam apiInfo) {
Date date = new Date();
BaseApiInfo baseApiInfo = apiInfo.getBaseInfo();
baseApiInfo.setApiStatus(ApiStateEnum.EDIT.getName());
baseApiInfo.setEnabled(0);
baseApiInfo.setApiType("SQL");
baseApiInfo.setCreateTime(date);
baseApiInfo.setUpdateBy(UserThreadLocal.getUserId());
apiInfoMapper.insertApiInfo(baseApiInfo);
BaseApiSql baseApiSql = apiInfo.getSqlInfo();
if (baseApiSql.getDatasourceId() == null && baseApiSql.getSqlScript() == null){
return 1L;
BaseApiInfo api = apiInfo.getBaseInfo();
BaseApiSql sql = apiInfo.getSqlInfo();
api.setApiStatus(ApiStateEnum.EDIT.getName());
api.setEnabled(0);
api.setApiType("SQL");
api.setDatasourceId(sql.getDatasourceId());
api.setSchemaName(sql.getSchemaName());
api.setDatasourceType(sql.getDatasourceType());
api.setSqlScript(sql.getSqlScript());
api.setCreateTime(date);
api.setCreateBy(UserThreadLocal.getUserId());
if (api.getGroupId() == null) {
api.setGroupId(1);
}
baseApiSql.setApiId(baseApiInfo.getApiId());
baseApiSql.setPageSetup(baseApiInfo.getPageSetup());
baseApiSql.setUpdateTime(date);
baseApiSql.setUpdateBy(UserThreadLocal.getUserId());
apiSqlMapper.insertApiSql(baseApiSql);
return baseApiInfo.getApiId();
apiInfoMapper.insertApiInfo(api);
return api.getApiId();
}
@Override
@@ -155,28 +152,23 @@ public class BaseApiInfoServiceImpl implements IBaseApiInfoService {
if (count == 0) {
throw new CustomException(52002, "API不存在");
}
BaseApiInfo baseApiInfo = apiInfo.getBaseInfo();
BaseApiInfo api = apiInfo.getBaseInfo();
BaseApiSql sql = apiInfo.getSqlInfo();
Date updateTime = new Date();
baseApiInfo.setUpdateTime(updateTime);
baseApiInfo.setApiStatus(ApiStateEnum.EDIT.getName());
baseApiInfo.setEnabled(0);
baseApiInfo.setApiType("SQL");
baseApiInfo.setUpdateBy(UserThreadLocal.getUserId());
apiInfoMapper.updateApiInfo(baseApiInfo);
BaseApiSql baseApiSql = apiInfo.getSqlInfo();
baseApiSql.setUpdateTime(updateTime);
baseApiSql.setUpdateBy(UserThreadLocal.getUserId());
baseApiSql.setPageSetup(baseApiInfo.getPageSetup());
BaseApiSql apiSql = apiSqlMapper.selectApiSql(baseApiInfo.getApiId());
if (apiSql == null) {
baseApiSql.setApiId(baseApiInfo.getApiId());
apiSqlMapper.insertApiSql(baseApiSql);
}else{
apiSqlMapper.updateApiSql(baseApiSql);
api.setApiStatus(ApiStateEnum.EDIT.getName());
api.setEnabled(0);
api.setApiType("SQL");
api.setDatasourceId(sql.getDatasourceId());
api.setSchemaName(sql.getSchemaName());
api.setDatasourceType(sql.getDatasourceType());
api.setSqlScript(sql.getSqlScript());
api.setUpdateTime(updateTime);
api.setUpdateBy(UserThreadLocal.getUserId());
if (api.getGroupId() == null) {
api.setGroupId(1);
}
return apiInfo.getSqlInfo().getApiId();
apiInfoMapper.updateApiInfo(api);
return apiInfo.getBaseInfo().getApiId();
}
@Override
@@ -199,6 +191,13 @@ public class BaseApiInfoServiceImpl implements IBaseApiInfoService {
return 1;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Integer deleteApi(Long apiId, String userId) {
Integer result = apiInfoMapper.deleteApiInfo(apiId, userId);
return result;
}
@Override
public Long apiPublish(ApiInfoParam apiInfoParam) {
Long apiId = apiInfoParam.getBaseInfo().getApiId();
@@ -222,11 +221,6 @@ public class BaseApiInfoServiceImpl implements IBaseApiInfoService {
baseApiInfo.setUpdateBy(UserThreadLocal.getUserId());
baseApiInfo.setApiStatus(ApiStateEnum.RELEASE.getName());
apiInfoMapper.updateApiInfo(baseApiInfo);
BaseApiSql baseApiSql = apiInfoParam.getSqlInfo();
baseApiSql.setUpdateTime(updateTime);
baseApiSql.setUpdateBy(UserThreadLocal.getUserId());
apiSqlMapper.updateApiSql(baseApiSql);
// 更新缓存
this.getApiCache(baseApiInfo.getApiId());
return apiId;
@@ -284,11 +278,5 @@ public class BaseApiInfoServiceImpl implements IBaseApiInfoService {
apiInfo.setUpdateTime(updateTime);
apiInfo.setApiId(null);
apiInfoMapper.insertApiInfo(apiInfo);
BaseApiSql oldApiSql = apiSqlMapper.selectApiSql(apiId);
oldApiSql.setSqlId(null);
oldApiSql.setUpdateTime(updateTime);
oldApiSql.setApiId(apiInfo.getApiId());
apiSqlMapper.insertApiSql(oldApiSql);
}
}
@@ -33,7 +33,7 @@ public class BaseApiSqlServiceImpl implements IBaseApiSqlService {
}
@Override
public Integer deleteApiSql(Integer apiId) {
return apiSqlMapper.deleteApiSql(apiId);
public Integer deleteApiSql(Long apiId, String userId) {
return apiSqlMapper.deleteApiSql(apiId, userId);
}
}
@@ -1,10 +1,10 @@
package cn.crabc.core.admin.service.system.impl;
import cn.crabc.core.admin.entity.vo.PreviewVO;
import cn.crabc.core.admin.service.system.IBaseApiTestService;
import cn.crabc.core.app.constant.BaseConstant;
import cn.crabc.core.app.driver.DataSourceManager;
import cn.crabc.core.spi.DataSourceDriver;
import cn.crabc.core.admin.entity.vo.PreviewVO;
import cn.crabc.core.admin.service.system.IBaseApiTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -1,11 +1,11 @@
package cn.crabc.core.admin.service.system.impl;
import cn.crabc.core.app.exception.CustomException;
import cn.crabc.core.admin.entity.BaseApp;
import cn.crabc.core.admin.mapper.BaseAppMapper;
import cn.crabc.core.admin.service.system.IBaseAppService;
import cn.crabc.core.admin.util.PageInfo;
import cn.crabc.core.admin.util.UserThreadLocal;
import cn.crabc.core.app.exception.CustomException;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -1,7 +1,5 @@
package cn.crabc.core.admin.service.system.impl;
import cn.crabc.core.app.driver.DataSourceManager;
import cn.crabc.core.spi.bean.BaseDataSource;
import cn.crabc.core.admin.entity.BaseDatasource;
import cn.crabc.core.admin.mapper.BaseDataSourceMapper;
import cn.crabc.core.admin.service.core.IBaseDataService;
@@ -9,6 +7,8 @@ import cn.crabc.core.admin.service.system.IBaseDataSourceService;
import cn.crabc.core.admin.util.PageInfo;
import cn.crabc.core.admin.util.RSAUtils;
import cn.crabc.core.admin.util.UserThreadLocal;
import cn.crabc.core.app.driver.DataSourceManager;
import cn.crabc.core.spi.bean.BaseDataSource;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
@@ -0,0 +1,154 @@
package cn.crabc.core.admin.util;
import com.alibaba.druid.DbType;
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.SQLAllColumnExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import io.micrometer.core.instrument.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* SQL解析工具类
*
* @author yuqf
*/
public class SQLUtil {
private final static Logger log = LoggerFactory.getLogger(SQLUtil.class);
public final static String PARAM_PATTERN = "(?<=\\#\\{)(.+?)(?=\\})";
/**
* 过滤SQL中的注释
*
* @param sql
* @return
*/
public static String sqlCommentReplace(String sql) {
String SQL_COMMENT = "(?ms)('(?:''|[^'])*')|--.*?$|///*.*?//*/|\\/\\/[^\\n]*|\\/\\*([^\\*^\\/]*|[\\*^\\/*]*|[^\\**\\/]*)*\\*+\\/";
Pattern p = Pattern.compile(SQL_COMMENT);
return p.matcher(sql).replaceAll("#1");
}
/**
* 解析查询字段
* @param sql
* @param dbType
* @return
*/
public static Set<String> analyzeSQL(String sql, String dbType){
Set<String> aliasList = new HashSet<>();
try {
List<SQLStatement> sqlStatementList = SQLUtils.parseStatements(sql,DbType.valueOf(dbType),false);
if(sqlStatementList == null || sqlStatementList.isEmpty()){
//throw new IllegalArgumentException("不是有效语句");
return aliasList;
}else if(sqlStatementList.size() > 1){
//throw new IllegalArgumentException("检测到多条语句,请不用使用;分号");
return aliasList;
}
if(!(sqlStatementList.get(0) instanceof SQLSelectStatement)){
return aliasList;
}
SQLSelectStatement selectStatement = (SQLSelectStatement) sqlStatementList.get(0);
SQLSelect sqlSelect = selectStatement.getSelect();
SQLSelectQueryBlock firstQueryBlock = sqlSelect.getFirstQueryBlock();
//normalized
for (int i = 0; i < firstQueryBlock.getSelectList().size(); i++) {
SQLSelectItem item = firstQueryBlock.getSelectList().get(i);
SQLExpr expr = item.getExpr();
String normalizedName = null;
if (expr instanceof SQLAllColumnExpr) {
normalizedName = "*";
} else if (expr instanceof SQLPropertyExpr && ((SQLPropertyExpr) expr).getName().equals("*")) {
normalizedName = "*";
} else if (expr instanceof SQLIdentifierExpr) {
//标识
normalizedName = ((SQLIdentifierExpr) expr).normalizedName();//normalizedName能够去掉引号关键字
} else if (expr instanceof SQLPropertyExpr) {
//带owner的标识
normalizedName = SQLUtils.normalize(((SQLPropertyExpr) expr).getName(), DbType.valueOf(dbType));//normalizedName能够去掉引号关键字,去掉owner
}else {
//自动生成虚拟别名
normalizedName = "_col"+i;
}
String alias = item.computeAlias();
if(alias == null){
aliasList.add(normalizedName + "," + normalizedName);
}else {
aliasList.add(normalizedName + ',' + alias);
}
}
return aliasList;
}catch (Exception e){
log.info("SQL解析失败:{}",e.getMessage());
return aliasList;
}
}
public List<String> parseOperation(String sql, String dbType){
List<String> tableNameList = new ArrayList<>();
//格式化输出
String sqlResult = SQLUtils.format(sql, dbType);
List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);
for (SQLStatement sqlStatement : stmtList) {
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
sqlStatement.accept(visitor);
Map<TableStat.Name, TableStat> tables = visitor.getTables();
Set<TableStat.Name> tableNameSet = tables.keySet();
for (TableStat.Name name : tableNameSet) {
String tableName = name.getName();
if (StringUtils.isNotBlank(tableName)) {
tableNameList.add(tableName);
}
}
}
return null;
}
/**
* 正则解析请求参数
* @param sql
* @return
*/
public static Set<String> parseParams(String sql) {
Set<String> columns = new HashSet<>();
try{
sql = sqlCommentReplace(sql);
Pattern pattern = Pattern.compile(PARAM_PATTERN);
Matcher m = pattern.matcher(sql);
while (m.find()) {
columns.add(m.group(0));
}
}catch (Exception e){
e.printStackTrace();
}
return columns;
}
}
@@ -1,173 +0,0 @@
package cn.crabc.core.admin.util;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.parser.SimpleNode;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.*;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* SQL解析工具类
*
* @author yuqf
*/
public class SQLUtils {
private final static String PATTERN = "\\#\\{\\s*(\\w+|[\\w-]+)\\s*\\}";
public final static String PARAM_PATTERN = "(?<=\\#\\{)(.+?)(?=\\})";
/**
* 过滤SQL中的注释
*
* @param sql
* @return
*/
public static String sqlCommentReplace(String sql) {
String SQL_COMMENT = "(?ms)('(?:''|[^'])*')|--.*?$|///*.*?//*/|\\/\\/[^\\n]*|\\/\\*([^\\*^\\/]*|[\\*^\\/*]*|[^\\**\\/]*)*\\*+\\/";
Pattern p = Pattern.compile(SQL_COMMENT);
return p.matcher(sql).replaceAll("#1");
}
/**
* 临时转换sql供sql编译通过
*
* @param sql sql
* @return sql
*/
public static String sqlParamReplaceTemp(String sql) {
sql = sqlCommentReplace(sql);
Pattern r = Pattern.compile(PATTERN);
Matcher m = r.matcher(sql);
while (m.find()) {
sql = sql.replace(m.group(), "1");
}
return sql;
}
/**
* 正则解析请求参数
* @param sql
* @return
*/
public static Set<String> parseParams(String sql) {
Set<String> columns = new HashSet<>();
try{
sql = sqlCommentReplace(sql);
Pattern pattern = Pattern.compile(PARAM_PATTERN);
Matcher m = pattern.matcher(sql);
while (m.find()) {
columns.add(m.group(0));
}
}catch (Exception e){
e.printStackTrace();
}
return columns;
}
/**
* 解析sql的查询列
*
* @param sql
* @return
*/
public static Set<String> parseColumns(String sql) {
sql = sqlCommentReplace(sql);
if (sql.contains("#{")) {
sql = sqlParamReplaceTemp(sql);
}
Set<String> result = new HashSet<>();
try {
CCJSqlParserManager pm = new CCJSqlParserManager();
Statement statement = pm.parse(new StringReader(sql));
if (statement instanceof Select) {
Select selectStatement = (Select) statement;
SelectBody selectBody = selectStatement.getSelectBody();
List<PlainSelect> plainSelects = new ArrayList<>();
if (selectBody instanceof SetOperationList){
SetOperationList list = (SetOperationList) selectBody;
for(SelectBody sb : list.getSelects()){
PlainSelect plainSelect = (PlainSelect) sb;
plainSelects.add(plainSelect);
}
}else if(selectBody instanceof PlainSelect){
PlainSelect plainSelect = (PlainSelect) selectBody;
plainSelects.add(plainSelect);
}
for(PlainSelect plainSelect : plainSelects){
List<SelectItem> selectItemlist = plainSelect.getSelectItems();
SelectItem selectItem = null;
SelectExpressionItem selectExpressionItem = null;
AllTableColumns allTableColumns = null;
Alias alias = null;
SimpleNode node = null;
if (selectItemlist != null) {
for (int i = 0; i < selectItemlist.size(); i++) {
selectItem = selectItemlist.get(i);
if (selectItem instanceof SelectExpressionItem) {
String columnName = "";
selectExpressionItem = (SelectExpressionItem) selectItemlist.get(i);
alias = selectExpressionItem.getAlias();
node = selectExpressionItem.getExpression().getASTNode();
// 针对复杂函数解析不到node,直接使用别名作为返回参数
if (node == null && alias != null) {
columnName = "_col" + i + "," + alias.getName();
} else if (node == null) {
columnName = "_col" + i;
} else {
Object value = node.jjtGetValue();
if (value instanceof Column) {
columnName = ((Column) value).getColumnName();
} else if (value instanceof Function) {
//columnName = ((Function) value).toString();
columnName = "_col" + i;
} else {
// 增加对select 'aaa' from table; 的支持
columnName = value.toString();
columnName = columnName.replace("'", "");
columnName = columnName.replace("\"", "");
}
columnName = columnName + "," + (alias == null ? columnName : alias.getName());
}
//为重复字段添加尾缀
// int suffix = 1;
// String columnNameDuplicRm = columnName;
// while (result.contains(columnNameDuplicRm)){
// columnNameDuplicRm = columnName + suffix;
// suffix++;
// }
// result.add(columnNameDuplicRm);
result.add(columnName);
} else if (selectItem instanceof AllTableColumns) {
allTableColumns = (AllTableColumns) selectItemlist.get(i);
result.add(allTableColumns.toString());
} else {
result.add(selectItem.toString());
}
}
}
}
}
} catch (JSQLParserException e) {
e.printStackTrace();
}
return result;
}
}
@@ -39,7 +39,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SELECT
api_id,
api_name,
api_type
api_type,
api_status
FROM
base_api_info where group_id = #{groupId} and api_status !='history'
</select>
@@ -64,27 +65,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectApiDetail" resultType="cn.crabc.core.admin.entity.dto.ApiInfoDTO">
SELECT
i.api_id,
i.api_name,
i.api_path,
i.api_type,
i.api_method,
i.auth_type,
i.api_status,
i.enabled,
i.group_id,
i.tenant_id,
s.sql_script,
s.datasource_id,
s.datasource_type,
s.schema_name
api_id,
api_name,
api_path,
api_type,
api_method,
auth_type,
api_status,
enabled,
group_id,
tenant_id,
remarks,
version,
datasource_id,
datasource_type,
schema_name,
sql_script
FROM
base_api_info i
LEFT JOIN base_api_sql s ON i.api_id = s.api_id
base_api_info
WHERE
i.api_id = s.api_id AND i.enabled='1' AND i.parent_id = 0 AND i.api_status ='release'
enabled='1' AND parent_id = 0 AND api_status ='release'
<if test="apiId != null">
and i.api_id =#{apiId}
and api_id =#{apiId}
</if>
</select>
@@ -105,28 +107,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
create_time,
update_by,
update_time,
version
version,
datasource_id,
datasource_type,
schema_name,
sql_script,
page_setup
FROM
base_api_info
WHERE
api_id =#{apiId}
</select>
<select id="selectApiInfo" resultType="cn.crabc.core.admin.entity.BaseApiInfo">
<select id="checkApiPath">
SELECT
api_id,
api_name,
api_path,
api_type,
api_method,
auth_type,
api_status,
enabled,
group_id,
tenant_id,
version
count(1)
FROM
base_api_info where api_path =#{apiPath} and api_method =#{method}
base_api_info where api_path =#{apiPath} and api_method =#{method} and api_id !=#{apiId}
</select>
<insert id="insertApiInfo" useGeneratedKeys="true" keyProperty="apiId" parameterType="cn.crabc.core.admin.entity.BaseApiInfo">
@@ -142,6 +139,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="version != null and version != ''">version,</if>
<if test="parentId != null">parent_id,</if>
<if test="remarks != null and remarks != ''">remarks,</if>
<if test="sqlScript != null and sqlScript !=''">sql_script,</if>
<if test="datasourceId != null and datasourceId != ''">datasource_id,</if>
<if test="datasourceType != null and datasourceType != ''">datasource_type,</if>
<if test="schemaName != null and schemaName != ''">schema_name,</if>
<if test="pageSetup != null">page_setup,</if>
enabled,
create_by,
create_time
@@ -157,6 +159,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="version != null and version != ''">#{version},</if>
<if test="parentId != null and parentId != ''">#{parentId},</if>
<if test="remarks != null and remarks != ''">#{remarks},</if>
<if test="sqlScript != null and sqlScript !=''">#{sqlScript},</if>
<if test="datasourceId != null and datasourceId != ''">#{datasourceId},</if>
<if test="datasourceType != null and datasourceType != ''">#{datasourceType},</if>
<if test="schemaName != null and schemaName != ''">#{schemaName},</if>
<if test="pageSetup != null">#{pageSetup},</if>
#{enabled},
#{createBy},
#{createTime}
@@ -179,6 +186,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="parentId != null">parent_id = #{parentId},</if>
<if test="tenantId != null">tenant_id = #{tenantId},</if>
<if test="remarks != null and remarks != ''">remarks = #{remarks},</if>
<if test="sqlScript != null and sqlScript !=''">sql_script = #{sqlScript},</if>
<if test="datasourceId != null and datasourceId != ''">datasource_id =#{datasourceId},</if>
<if test="datasourceType != null and datasourceType != ''">datasource_type =#{datasourceType},</if>
<if test="schemaName != null and schemaName != ''">schema_name =#{schemaName},</if>
<if test="pageSetup != null">page_setup =#{pageSetup},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
update_time = #{updateTime}
</set>
@@ -197,6 +209,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
WHERE api_id =#{apiId}
</update>
<delete id="deleteApiInfo">
DELETE FROM base_api_info where api_status ='edit' and api_id =#{apiId} and create_by =#{userId}
</delete>
<select id="countApi" resultType="java.lang.Integer">
select count(1) from base_api_info
<where>
@@ -27,8 +27,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="datasourceType != null and datasourceType != ''">datasource_type,</if>
<if test="schemaName != null and schemaName != ''">schema_name,</if>
<if test="pageSetup != null">page_setup,</if>
<if test="updateBy != null and updateBy != ''">update_by,</if>
update_time
<if test="createBy != null and createBy != ''">create_by,</if>
create_time
)values(
<if test="apiId != null and apiId !=''">#{apiId},</if>
<if test="sqlScript != null and sqlScript !=''">#{sqlScript},</if>
@@ -36,8 +36,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="datasourceType != null and datasourceType != ''">#{datasourceType},</if>
<if test="schemaName != null and schemaName != ''">#{schemaName},</if>
<if test="pageSetup != null">#{pageSetup},</if>
<if test="updateBy != null and updateBy != ''">#{updateBy},</if>
#{updateTime}
<if test="createBy != null and createBy != ''">#{createBy},</if>
#{createTime}
)
</insert>
@@ -56,6 +56,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</update>
<delete id="deleteApiSql">
DELETE FROM base_api_sql where api_id =#{apiId}
DELETE FROM base_api_sql where api_id =#{apiId} and create_by =#{userId}
</delete>
</mapper>
@@ -96,8 +96,25 @@ public class JdbcDataSourceDriver extends DefaultDataSourceDriver {
}
@Override
public Long execute(String dataSourceId, String schema, String sql) {
return null;
public Long execute(String dataSourceId, String schema, String sql, Object params) {
JdbcDataSourceRouter.setDataSourceKey(dataSourceId);
Object result = null;
try {
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put(BaseConstant.BASE_SQL, sql);
if (params != null && params instanceof Map) {
Map<String, Object> map = (Map<String, Object>) params;
paramsMap.putAll(map);
}
result = baseDataHandleMapper.executeUpdate(paramsMap);
} catch (Exception e) {
log.error("--SQL执行失败,请检查SQL是否正常", e);
throw new CustomException(51000, "SQL执行失败,请检查SQL是否正常");
} finally {
// 移除线程
JdbcDataSourceRouter.remove();
}
return 1L;
}
@Override
@@ -112,18 +129,6 @@ public class JdbcDataSourceDriver extends DefaultDataSourceDriver {
@Override
public int update(String sql, Map<String, Object> entity) {
JdbcDataSourceRouter.setDataSourceKey(entity.get(BaseConstant.DATA_SOURCE_ID).toString());
Integer result = 0;
try {
entity.remove(BaseConstant.DATA_SOURCE_ID);
result = baseDataHandleMapper.executeUpdate(entity);
} catch (Exception e) {
log.error("--SQL执行失败,请检查SQL是否正常", e);
throw new CustomException(51000, "SQL执行失败,请检查SQL是否正常");
} finally {
// 移除线程
JdbcDataSourceRouter.remove();
}
return result;
return 0;
}
}
@@ -26,6 +26,6 @@ public interface BaseDataHandleMapper {
* @return
*/
@SelectProvider(type = BaseSelectProvider.class, method = "executeUpdate")
Integer executeUpdate(Map<String, Object> params);
Object executeUpdate(Map<String, Object> params);
}
@@ -97,7 +97,7 @@ public class EsDataSourceDriver implements DataSourceDriver {
}
@Override
public Object execute(String dataSourceId, String schema, String sql) {
public Object execute(String dataSourceId, String schema, String sql, Object params) {
return null;
}
@@ -15,7 +15,7 @@ public interface BaseDataHandle<T> {
Object selectPage(String dataSourceId, String schema, String sql, Object params, int pageNum, int pageSize);
Object execute(String dataSourceId, String schema, String sql);
Object execute(String dataSourceId, String schema, String sql, Object params);
int insert(String sql, T entity);
+2 -3
View File
@@ -20,11 +20,10 @@
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>2.7.9</spring-boot.version>
<spring-boot.mybatis.version>2.2.2</spring-boot.mybatis.version>
<spring-boot.mybatis.version>2.3.0</spring-boot.mybatis.version>
<pagehelper.boot.version>1.4.6</pagehelper.boot.version>
<spring-boot.druid.version>1.2.16</spring-boot.druid.version>
<jsqlparser.version>4.5</jsqlparser.version>
<fastjson.version>2.0.24</fastjson.version>
<fastjson.version>2.0.25</fastjson.version>
<jwt.version>0.9.1</jwt.version>
<commons-pool2.version>2.11.1</commons-pool2.version>
</properties>