From 4fefe37cfe570b68b14c25aa9a2668b84ca6de63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E6=97=B6=E4=BB=A3=E7=9A=84=E5=B0=8F=E9=9D=92?= =?UTF-8?q?=E5=B9=B4=E5=91=80?= <497157812@qq.com> Date: Tue, 22 Jun 2021 14:12:45 +0800 Subject: [PATCH] data --- .../dataSet/controller/DataSetController.java | 149 ++++++ .../dataSet/controller/dto/DataSetDto.java | 58 +++ .../controller/dto/OriginalDataDto.java | 32 ++ .../controller/param/DataSetParam.java | 30 ++ .../param/DataSetTestTransformParam.java | 34 ++ .../data/dataSet/dao/DataSetMapper.java | 16 + .../data/dataSet/dao/entity/DataSet.java | 45 ++ .../data/dataSet/service/DataSetService.java | 70 +++ .../service/impl/DataSetServiceImpl.java | 343 +++++++++++++ .../dataSource/config/HttpClientConfig.java | 214 ++++++++ .../config/HttpClientPoolConfig.java | 53 ++ .../controller/DataSourceController.java | 67 +++ .../controller/dto/DataSourceDto.java | 74 +++ .../controller/param/ConnectionParam.java | 21 + .../controller/param/DataSourceParam.java | 31 ++ .../data/dataSource/dao/DataSourceMapper.java | 16 + .../dataSource/dao/entity/DataSource.java | 42 ++ .../data/dataSource/pool/api/IConfig.java | 39 ++ .../pool/api/IDataSourceConfig.java | 13 + .../data/dataSource/pool/api/ILifeCycle.java | 21 + .../pool/api/IPooledDataSourceConfig.java | 93 ++++ .../pool/connection/IPooledConnection.java | 56 +++ .../pool/connection/PooledConnection.java | 457 ++++++++++++++++++ .../pool/constant/JdbcConstants.java | 71 +++ .../dataSource/pool/constant/PooledConst.java | 71 +++ .../datasource/AbstractDataSourceConfig.java | 68 +++ .../AbstractPooledDataSourceConfig.java | 159 ++++++ .../datasource/DataSourceConfigAdaptor.java | 82 ++++ .../pool/datasource/PooledDataSource.java | 240 +++++++++ .../pool/datasource/UnPooledDataSource.java | 26 + .../pool/exception/JdbcPoolException.java | 28 ++ .../pool/util/DataSourceHandleUtil.java | 13 + .../dataSource/pool/util/DriverClassUtil.java | 89 ++++ .../data/dataSource/pool/util/JdbcUtil.java | 100 ++++ .../dataSource/service/DataSourceService.java | 48 ++ .../service/impl/DataSourceServiceImpl.java | 384 +++++++++++++++ 36 files changed, 3353 insertions(+) create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/DataSetController.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/DataSetDto.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/OriginalDataDto.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetParam.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetTestTransformParam.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/DataSetMapper.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/entity/DataSet.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/DataSetService.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/impl/DataSetServiceImpl.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientConfig.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientPoolConfig.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/DataSourceController.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/dto/DataSourceDto.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/ConnectionParam.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/DataSourceParam.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/DataSourceMapper.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/entity/DataSource.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IConfig.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IDataSourceConfig.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/ILifeCycle.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IPooledDataSourceConfig.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/IPooledConnection.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/PooledConnection.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/JdbcConstants.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/PooledConst.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractDataSourceConfig.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractPooledDataSourceConfig.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/DataSourceConfigAdaptor.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/PooledDataSource.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/UnPooledDataSource.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/exception/JdbcPoolException.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DataSourceHandleUtil.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DriverClassUtil.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/JdbcUtil.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/DataSourceService.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/impl/DataSourceServiceImpl.java diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/DataSetController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/DataSetController.java new file mode 100644 index 00000000..e5a0e58a --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/DataSetController.java @@ -0,0 +1,149 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.controller; + +import com.anji.plus.gaea.annotation.AccessKey; +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.annotation.log.GaeaAuditLog; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anji.plus.gaea.holder.UserContentHolder; +import com.anji.plus.gaea.utils.GaeaUtils; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param.DataSetParam; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param.DataSetTestTransformParam; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity.DataSet; +import com.anjiplus.template.gaea.business.modules.data.dataSet.service.DataSetService; +import io.swagger.annotations.Api; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** +* @desc 数据集 controller +* @website https://gitee.com/anji-plus/gaea +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@RestController +@Api(tags = "数据集管理") +@RequestMapping("/dataSet") +public class DataSetController extends GaeaBaseController { + + @Autowired + private DataSetService dataSetService; + + @Override + public GaeaBaseService getService() { + return dataSetService; + } + + @Override + public DataSet getEntity() { + return new DataSet(); + } + + @Override + public DataSetDto getDTO() { + return new DataSetDto(); + } + + @GetMapping("/detailBysetId/{id}") + @Permission( + code = "DETAIL", + name = "明细" + ) + public ResponseBean detailBysetId(@PathVariable("id") Long id) { + this.logger.info("{}根据ID查询服务开始,id为:{}", this.getClass().getSimpleName(), id); + ResponseBean responseBean = this.responseSuccessWithData(dataSetService.detailSet(id)); + this.logger.info("{}根据ID查询结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean)); + return responseBean; + } + + @GetMapping({"/detailBysetCode/{setCode}"}) + @Permission( + code = "DETAIL", + name = "明细" + ) + @AccessKey + public ResponseBean detailBysetCode(@PathVariable("setCode") String setCode) { + this.logger.info("{}根据setCode查询服务开始,setCode为:{}", this.getClass().getSimpleName(), setCode); + ResponseBean responseBean = this.responseSuccessWithData(dataSetService.detailSet(setCode)); + this.logger.info("{}根据setCode查询结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean)); + return responseBean; + } + + @PostMapping + @Permission( + code = "INSERT", + name = "新增" + ) + @GaeaAuditLog( + pageTitle = "新增" + ) + @Override + public ResponseBean insert(@RequestBody DataSetDto dto) { + this.logger.info("{}新增服务开始,参数:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(dto)); + DataSetDto dataSetDto = dataSetService.insertSet(dto); + this.logger.info("{}新增服务结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(dataSetDto)); + return ResponseBean.builder().data(dataSetDto).build(); + } + + @PutMapping + @Permission( + code = "UPDATE", + name = "更新" + ) + @GaeaAuditLog( + pageTitle = "修改" + ) + @Override + public ResponseBean update(@RequestBody DataSetDto dto) { + String username = UserContentHolder.getContext().getUsername(); + this.logger.info("{}更新服务开始,更新人:{},参数:{}", this.getClass().getSimpleName(), username, GaeaUtils.toJSONString(dto)); + ResponseBean responseBean = this.responseSuccess(); + dataSetService.updateSet(dto); + this.logger.info("{}更新服务结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean)); + return this.responseSuccess(); + } + + @DeleteMapping({"/{id}"}) + @Permission( + code = "DELETE", + name = "删除" + ) + @GaeaAuditLog( + pageTitle = "删除" + ) + @Override + public ResponseBean deleteById(@PathVariable("id") Long id) { + this.logger.info("{}删除服务开始,参数ID:{}", this.getClass().getSimpleName(), id); + dataSetService.deleteSet(id); + this.logger.info("{}删除服务结束", this.getClass().getSimpleName()); + return this.responseSuccess(); + } + + /** + * 测试 数据转换是否正确 + * @param param + * @return + */ + @PostMapping("/testTransform") + public ResponseBean testTransform(@Validated @RequestBody DataSetTestTransformParam param) { + DataSetDto dto = new DataSetDto(); + BeanUtils.copyProperties(param, dto); + return responseSuccessWithData(dataSetService.testTransform(dto)); + } + + /** + * 获取所有数据集 + * @return + */ + @GetMapping("/queryAllDataSet") + public ResponseBean queryAllDataSet() { + return responseSuccessWithData(dataSetService.queryAllDataSet()); + } + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/DataSetDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/DataSetDto.java new file mode 100644 index 00000000..acef9c28 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/DataSetDto.java @@ -0,0 +1,58 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.dto.DataSetTransformDto; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** +* +* @description 数据集 dto +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Data +public class DataSetDto extends GaeaBaseDTO implements Serializable { + /** 数据集编码 */ + private String setCode; + + /** 数据集名称 */ + private String setName; + + /** 数据集描述 */ + private String setDesc; + + /** 数据源编码 */ + private String sourceCode; + + /** 动态查询sql或者接口中的请求体 */ + private String dynSentence; + + /** 结果案例 */ + private String caseResult; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + private Integer deleteFlag; + + /** 请求参数集合 */ + private List dataSetParamDtoList; + + /** 数据转换集合 */ + private List dataSetTransformDtoList; + + /** 传入的自定义参数*/ + private Map contextData; + + private Set setParamList; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/OriginalDataDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/OriginalDataDto.java new file mode 100644 index 00000000..12b4aad0 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/OriginalDataDto.java @@ -0,0 +1,32 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * Created by raodeming on 2021/3/26. + */ +@Data +public class OriginalDataDto implements Serializable { + + /**总数*/ + private long total; + + /**获取的数据详情*/ + private List data; + + public OriginalDataDto(List data) { + this.data = data; + } + + public OriginalDataDto(long total, List data) { + this.total = total; + this.data = data; + } + + public OriginalDataDto() { + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetParam.java new file mode 100644 index 00000000..f96ecf93 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetParam.java @@ -0,0 +1,30 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param; + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + + +/** +* @desc DataSet 数据集查询输入类 +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Data +public class DataSetParam extends PageParam implements Serializable{ + /** 数据集编码 */ + @Query(QueryEnum.LIKE) + private String setCode; + + /** 数据集名称 */ + @Query(QueryEnum.LIKE) + private String setName; + + /** 数据源编码 */ + @Query(QueryEnum.EQ) + private String sourceCode; +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetTestTransformParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetTestTransformParam.java new file mode 100644 index 00000000..33739099 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetTestTransformParam.java @@ -0,0 +1,34 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param; + +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.dto.DataSetTransformDto; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.List; + + +/** +* @desc DataSet 数据集查询输入类 +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Data +public class DataSetTestTransformParam implements Serializable{ + + /** 数据源编码 */ + @NotBlank(message = "sourceCode not empty") + private String sourceCode; + + /** 动态查询sql或者接口中的请求体 */ + private String dynSentence; + + /** 请求参数集合 */ + private List dataSetParamDtoList; + + /** 数据转换集合 */ + private List dataSetTransformDtoList; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/DataSetMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/DataSetMapper.java new file mode 100644 index 00000000..fe6a9ab9 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/DataSetMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSet.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity.DataSet; + +/** +* DataSet Mapper +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Mapper +public interface DataSetMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/entity/DataSet.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/entity/DataSet.java new file mode 100644 index 00000000..05da2eb0 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/entity/DataSet.java @@ -0,0 +1,45 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.common.RespCommonCode; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +* @description 数据集 entity +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@TableName(value="gaea_report_data_set") +@Data +public class DataSet extends GaeaBaseEntity { + @ApiModelProperty(value = "数据集编码") + @Unique(code = RespCommonCode.SET_CODE_ISEXIST) + private String setCode; + + @ApiModelProperty(value = "数据集名称") + private String setName; + + @ApiModelProperty(value = "数据集描述") + private String setDesc; + + @ApiModelProperty(value = "数据源编码") + private String sourceCode; + + @ApiModelProperty(value = "动态查询sql或者接口中的请求体") + private String dynSentence; + + @ApiModelProperty(value = "结果案例") + private String caseResult; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/DataSetService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/DataSetService.java new file mode 100644 index 00000000..b9dd4dd3 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/DataSetService.java @@ -0,0 +1,70 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param.DataSetParam; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity.DataSet; + +import java.util.List; + +/** +* @desc DataSet 数据集服务接口 +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +public interface DataSetService extends GaeaBaseService { + + /** + * 单条详情 + * @param id + * @return + */ + DataSetDto detailSet(Long id); + + /** + * 单条详情 + * @param setCode + * @return + */ + DataSetDto detailSet(String setCode); + + /** + * 新增数据集、添加查询参数、数据转换 + * @param dto + */ + DataSetDto insertSet(DataSetDto dto); + + /** + * 更新数据集、添加查询参数、数据转换 + * @param dto + */ + void updateSet(DataSetDto dto); + + /** + * 删除数据集、添加查询参数、数据转换 + * @param id + */ + void deleteSet(Long id); + + /** + * 获取数据 + * @param dto + * @return + */ + OriginalDataDto getData(DataSetDto dto); + + /** + * + * @param dto + * @return + */ + OriginalDataDto testTransform(DataSetDto dto); + + /** + * 获取所有数据集 + * @return + */ + List queryAllDataSet(); +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/impl/DataSetServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/impl/DataSetServiceImpl.java new file mode 100644 index 00000000..3b536c51 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/impl/DataSetServiceImpl.java @@ -0,0 +1,343 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.constant.Enabled; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.utils.GaeaBeanUtils; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.DataSetMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity.DataSet; +import com.anjiplus.template.gaea.business.modules.data.dataSet.service.DataSetService; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.dao.entity.DataSetParam; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.dao.entity.DataSetTransform; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service.DataSetTransformService; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.data.dataSource.service.DataSourceService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** +* @desc DataSet 数据集服务实现 +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Service +//@RequiredArgsConstructor +public class DataSetServiceImpl implements DataSetService { + + @Autowired + private DataSetMapper dataSetMapper; + + @Autowired + private DataSetParamService dataSetParamService; + + @Autowired + private DataSetTransformService dataSetTransformService; + + @Autowired + private DataSourceService dataSourceService; + + @Override + public GaeaBaseMapper getMapper() { + return dataSetMapper; + } + + /** + * 单条详情 + * + * @param id + * @return + */ + @Override + public DataSetDto detailSet(Long id) { + DataSetDto dto = new DataSetDto(); + DataSet result = selectOne(id); + String setCode = result.getSetCode(); + GaeaBeanUtils.copyAndFormatter(result, dto); + return getDetailSet(dto, setCode); + } + + /** + * 单条详情 + * + * @param setCode + * @return + */ + @Override + public DataSetDto detailSet(String setCode) { + DataSetDto dto = new DataSetDto(); + DataSet result = selectOne("set_code", setCode); + GaeaBeanUtils.copyAndFormatter(result, dto); + return getDetailSet(dto, setCode); + } + + public DataSetDto getDetailSet(DataSetDto dto, String setCode) { + //查询参数 + List dataSetParamList = dataSetParamService.list( + new QueryWrapper() + .lambda() + .eq(DataSetParam::getSetCode, setCode) + ); + List dataSetParamDtoList = new ArrayList<>(); + dataSetParamList.forEach(dataSetParam -> { + DataSetParamDto dataSetParamDto = new DataSetParamDto(); + GaeaBeanUtils.copyAndFormatter(dataSetParam, dataSetParamDto); + dataSetParamDtoList.add(dataSetParamDto); + }); + dto.setDataSetParamDtoList(dataSetParamDtoList); + + //数据转换 + + List dataSetTransformList = dataSetTransformService.list( + new QueryWrapper() + .lambda() + .eq(DataSetTransform::getSetCode, setCode) + .orderByAsc(DataSetTransform::getOrderNum) + ); + List dataSetTransformDtoList = new ArrayList<>(); + dataSetTransformList.forEach(dataSetTransform -> { + DataSetTransformDto dataSetTransformDto = new DataSetTransformDto(); + GaeaBeanUtils.copyAndFormatter(dataSetTransform, dataSetTransformDto); + dataSetTransformDtoList.add(dataSetTransformDto); + }); + dto.setDataSetTransformDtoList(dataSetTransformDtoList); + + if (StringUtils.isNotBlank(dto.getCaseResult())) { + try { + JSONArray jsonArray = JSONArray.parseArray(dto.getCaseResult()); + JSONObject jsonObject = jsonArray.getJSONObject(0); + dto.setSetParamList(jsonObject.keySet()); + } catch (Exception e) { + } + } + return dto; + } + + + /** + * 新增数据集、添加查询参数、数据转换 + * + * @param dto + */ + @Override + @Transactional + public DataSetDto insertSet(DataSetDto dto) { + List dataSetParamDtoList = dto.getDataSetParamDtoList(); + List dataSetTransformDtoList = dto.getDataSetTransformDtoList(); + + //1.新增数据集 + DataSet dataSet = new DataSet(); + BeanUtils.copyProperties(dto, dataSet); + insert(dataSet); + //2.更新查询参数 + dataSetParamBatch(dataSetParamDtoList, dto.getSetCode()); + + //3.更新数据转换 + dataSetTransformBatch(dataSetTransformDtoList, dto.getSetCode()); + return dto; + } + + /** + * 更新数据集、添加查询参数、数据转换 + * + * @param dto + */ + @Override + @Transactional + public void updateSet(DataSetDto dto) { + List dataSetParamDtoList = dto.getDataSetParamDtoList(); + List dataSetTransformDtoList = dto.getDataSetTransformDtoList(); + //1.更新数据集 + DataSet dataSet = new DataSet(); + BeanUtils.copyProperties(dto, dataSet); + update(dataSet); + + //2.更新查询参数 + dataSetParamBatch(dataSetParamDtoList, dto.getSetCode()); + + //3.更新数据转换 + dataSetTransformBatch(dataSetTransformDtoList, dto.getSetCode()); + } + + + /** + * 删除数据集、添加查询参数、数据转换 + * + * @param id + */ + @Override + public void deleteSet(Long id) { + DataSet dataSet = selectOne(id); + String setCode = dataSet.getSetCode(); + //1.删除数据集 + deleteById(id); + + //2.删除查询参数 + dataSetParamService.delete( + new QueryWrapper() + .lambda() + .eq(DataSetParam::getSetCode, setCode) + ); + + //3.删除数据转换 + dataSetTransformService.delete( + new QueryWrapper() + .lambda() + .eq(DataSetTransform::getSetCode, setCode) + ); + } + + /** + * 获取数据 + * + * @param dto + * @return + */ + @Override + public OriginalDataDto getData(DataSetDto dto) { + OriginalDataDto originalDataDto = new OriginalDataDto(); + String setCode = dto.getSetCode(); + //1.获取数据集、参数替换、数据转换 + DataSetDto dataSetDto = detailSet(setCode); + //2.获取数据源 + DataSource dataSource = dataSourceService.selectOne("source_code", dataSetDto.getSourceCode()); + //3.参数替换 + //3.1参数校验 + boolean verification = dataSetParamService.verification(dataSetDto.getDataSetParamDtoList(), dto.getContextData()); + if (!verification) { + throw BusinessExceptionBuilder.build(ResponseCode.RULE_FIELDS_CHECK_ERROR); + } + String dynSentence = dataSetParamService.transform(dto.getContextData(), dataSetDto.getDynSentence()); + //4.获取数据 + DataSourceDto dataSourceDto = new DataSourceDto(); + BeanUtils.copyProperties(dataSource, dataSourceDto); + dataSourceDto.setDynSentence(dynSentence); + dataSourceDto.setContextData(dto.getContextData()); + //获取total,判断contextData中是否传入分页参数 + if (null != dto.getContextData() + && dto.getContextData().containsKey("pageNumber") + && dto.getContextData().containsKey("pageSize")) { + long total = dataSourceService.total(dataSourceDto, dto); + originalDataDto.setTotal(total); + } + List data = dataSourceService.execute(dataSourceDto); + //5.数据转换 + List transform = dataSetTransformService.transform(dataSetDto.getDataSetTransformDtoList(), data); + originalDataDto.setData(transform); + return originalDataDto; + } + + /** + * @param dto + * @return + */ + @Override + public OriginalDataDto testTransform(DataSetDto dto) { + OriginalDataDto originalDataDto = new OriginalDataDto(); + String sourceCode = dto.getSourceCode(); + //1.获取数据源 + DataSource dataSource = dataSourceService.selectOne("source_code", sourceCode); + //3.参数替换 + //3.1参数校验 + boolean verification = dataSetParamService.verification(dto.getDataSetParamDtoList(), null); + if (!verification) { + throw BusinessExceptionBuilder.build(ResponseCode.RULE_FIELDS_CHECK_ERROR); + } + + String dynSentence = dataSetParamService.transform(dto.getDataSetParamDtoList(), dto.getDynSentence()); + //4.获取数据 + DataSourceDto dataSourceDto = new DataSourceDto(); + BeanUtils.copyProperties(dataSource, dataSourceDto); + dataSourceDto.setDynSentence(dynSentence); + dataSourceDto.setContextData(dto.getContextData()); + + //获取total,判断DataSetParamDtoList中是否传入分页参数 + Map collect = dto.getDataSetParamDtoList().stream().collect(Collectors.toMap(DataSetParamDto::getParamName, DataSetParamDto::getSampleItem)); + if (collect.containsKey("pageNumber") && collect.containsKey("pageSize")) { + dto.setContextData(collect); + long total = dataSourceService.total(dataSourceDto, dto); + originalDataDto.setTotal(total); + } + + List data = dataSourceService.execute(dataSourceDto); + //5.数据转换 + List transform = dataSetTransformService.transform(dto.getDataSetTransformDtoList(), data); + originalDataDto.setData(transform); + return originalDataDto; + } + + + /** + * 获取所有数据集 + * + * @return + */ + @Override + public List queryAllDataSet() { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.select(DataSet::getSetCode, DataSet::getSetName, DataSet::getSetDesc, DataSet::getId) + .eq(DataSet::getEnableFlag, Enabled.YES.getValue()); + return dataSetMapper.selectList(wrapper); + } + + public void dataSetParamBatch(List dataSetParamDtoList,String setCode){ + dataSetParamService.delete( + new QueryWrapper() + .lambda() + .eq(DataSetParam::getSetCode, setCode) + ); + if (null == dataSetParamDtoList || dataSetParamDtoList.size() <= 0) { + return; + } + List dataSetParamList = new ArrayList<>(); + dataSetParamDtoList.forEach(dataSetParamDto -> { + DataSetParam dataSetParam = new DataSetParam(); + BeanUtils.copyProperties(dataSetParamDto, dataSetParam); + dataSetParam.setSetCode(setCode); + dataSetParamList.add(dataSetParam); + }); + dataSetParamService.insertBatch(dataSetParamList); + + } + + public void dataSetTransformBatch(List dataSetTransformDtoList,String setCode){ + dataSetTransformService.delete( + new QueryWrapper() + .lambda() + .eq(DataSetTransform::getSetCode, setCode) + ); + if (null == dataSetTransformDtoList || dataSetTransformDtoList.size() <= 0) { + return; + } + List dataSetTransformList = new ArrayList<>(); + for (int i = 0; i < dataSetTransformDtoList.size(); i++) { + DataSetTransform dataSetTransform = new DataSetTransform(); + BeanUtils.copyProperties(dataSetTransformDtoList.get(i), dataSetTransform); + dataSetTransform.setOrderNum(i + 1); + dataSetTransform.setSetCode(setCode); + dataSetTransformList.add(dataSetTransform); + } + dataSetTransformService.insertBatch(dataSetTransformList); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientConfig.java new file mode 100644 index 00000000..01e1dcf3 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientConfig.java @@ -0,0 +1,214 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.config; + +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.Header; +import org.apache.http.HeaderElement; +import org.apache.http.HeaderElementIterator; +import org.apache.http.HttpHost; +import org.apache.http.client.HttpClient; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicHeaderElementIterator; +import org.apache.http.protocol.HTTP; +import org.apache.http.ssl.SSLContextBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestTemplate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import java.nio.charset.Charset; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +/** + * Created by raodeming on 2021/3/24. + */ +@Configuration +@Slf4j +public class HttpClientConfig { + @Autowired + private HttpClientPoolConfig httpClientPoolConfig; + + /** + * 创建HTTP客户端工厂 + */ + @Bean(name = "clientHttpRequestFactory") + public ClientHttpRequestFactory clientHttpRequestFactory() { + /** + * maxTotalConnection 和 maxConnectionPerRoute 必须要配 + */ + if (httpClientPoolConfig.getMaxTotalConnect() <= 0) { + throw new IllegalArgumentException("invalid maxTotalConnection: " + httpClientPoolConfig.getMaxTotalConnect()); + } + if (httpClientPoolConfig.getMaxConnectPerRoute() <= 0) { + throw new IllegalArgumentException("invalid maxConnectionPerRoute: " + httpClientPoolConfig.getMaxConnectPerRoute()); + } + HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient()); + // 连接超时 + clientHttpRequestFactory.setConnectTimeout(httpClientPoolConfig.getConnectTimeout()); + // 数据读取超时时间,即SocketTimeout + clientHttpRequestFactory.setReadTimeout(httpClientPoolConfig.getReadTimeout()); + // 从连接池获取请求连接的超时时间,不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的 + clientHttpRequestFactory.setConnectionRequestTimeout(httpClientPoolConfig.getConnectionRequestTimout()); + return clientHttpRequestFactory; + } + + /** + * 初始化RestTemplate,并加入spring的Bean工厂,由spring统一管理 + */ + @Bean(name = "dataSourceRestTemplate") + public RestTemplate restTemplate(@Qualifier("clientHttpRequestFactory") ClientHttpRequestFactory factory) { + return createRestTemplate(factory); + } + + /** + * 配置httpClient + * + * @return + */ + @Bean + public HttpClient httpClient() { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); + try { + //设置信任ssl访问 + SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build(); + + httpClientBuilder.setSSLContext(sslContext); + HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; + SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); + Registry socketFactoryRegistry = RegistryBuilder.create() + // 注册http和https请求 + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslConnectionSocketFactory).build(); + + //使用Httpclient连接池的方式配置(推荐),同时支持netty,okHttp以及其他http框架 + PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + // 最大连接数 + poolingHttpClientConnectionManager.setMaxTotal(httpClientPoolConfig.getMaxTotalConnect()); + // 同路由并发数 + poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientPoolConfig.getMaxConnectPerRoute()); + //配置连接池 + httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); + // 重试次数 + httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpClientPoolConfig.getRetryTimes(), true)); + + //设置默认请求头 + List
headers = getDefaultHeaders(); + httpClientBuilder.setDefaultHeaders(headers); + //设置长连接保持策略 + httpClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy()); + return httpClientBuilder.build(); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + log.error("初始化HTTP连接池出错", e); + } + return null; + } + + + /** + * 配置长连接保持策略 + * + * @return + */ + public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() { + return (response, context) -> { + // Honor 'keep-alive' header + HeaderElementIterator it = new BasicHeaderElementIterator( + response.headerIterator(HTTP.CONN_KEEP_ALIVE)); + while (it.hasNext()) { + HeaderElement he = it.nextElement(); + log.info("HeaderElement:{}", JSON.toJSONString(he)); + String param = he.getName(); + String value = he.getValue(); + if (value != null && "timeout".equalsIgnoreCase(param)) { + try { + return Long.parseLong(value) * 1000; + } catch (NumberFormatException ignore) { + log.error("解析长连接过期时间异常", ignore); + } + } + } + HttpHost target = (HttpHost) context.getAttribute( + HttpClientContext.HTTP_TARGET_HOST); + //如果请求目标地址,单独配置了长连接保持时间,使用该配置 + Optional> any = Optional.ofNullable(httpClientPoolConfig.getKeepAliveTargetHost()).orElseGet(HashMap::new) + .entrySet().stream().filter( + e -> e.getKey().equalsIgnoreCase(target.getHostName())).findAny(); + //否则使用默认长连接保持时间 + return any.map(en -> en.getValue() * 1000L).orElse(httpClientPoolConfig.getKeepAliveTime() * 1000L); + }; + } + + + /** + * 设置请求头 + * + * @return + */ + private List
getDefaultHeaders() { + List
headers = new ArrayList<>(); + headers.add(new BasicHeader("User-Agent", + "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36")); + headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate")); + headers.add(new BasicHeader("Accept-Language", "zh-CN")); + headers.add(new BasicHeader("Connection", "Keep-Alive")); + return headers; + } + + + private RestTemplate createRestTemplate(ClientHttpRequestFactory factory) { + RestTemplate restTemplate = new RestTemplate(factory); + + //我们采用RestTemplate内部的MessageConverter + //重新设置StringHttpMessageConverter字符集,解决中文乱码问题 + modifyDefaultCharset(restTemplate); + + //设置错误处理器 + restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); + + return restTemplate; + } + + /** + * 修改默认的字符集类型为utf-8 + * + * @param restTemplate + */ + private void modifyDefaultCharset(RestTemplate restTemplate) { + List> converterList = restTemplate.getMessageConverters(); + HttpMessageConverter converterTarget = null; + for (HttpMessageConverter item : converterList) { + if (StringHttpMessageConverter.class == item.getClass()) { + converterTarget = item; + break; + } + } + if (null != converterTarget) { + converterList.remove(converterTarget); + } + Charset defaultCharset = Charset.forName(httpClientPoolConfig.getCharset()); + converterList.add(1, new StringHttpMessageConverter(defaultCharset)); + } +} + diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientPoolConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientPoolConfig.java new file mode 100644 index 00000000..a8b91faa --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientPoolConfig.java @@ -0,0 +1,53 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * Created by raodeming on 2021/3/24. + */ +@Component +@ConfigurationProperties(prefix = "spring.http-client.pool") +@Data +public class HttpClientPoolConfig { + /** + * java配置的优先级低于yml配置;如果yml配置不存在,会采用java配置 + */ + /** + * 连接池的最大连接数 + */ + private int maxTotalConnect = 1000; + /** + * 同路由的并发数 + */ + private int maxConnectPerRoute = 200; + /** + * 客户端和服务器建立连接超时,默认2s + */ + private int connectTimeout = 2 * 1000; + /** + * 指客户端从服务器读取数据包的间隔超时时间,不是总读取时间,默认30s + */ + private int readTimeout = 30 * 1000; + + private String charset = "UTF-8"; + /** + * 重试次数,默认2次 + */ + private int retryTimes = 2; + /** + * 从连接池获取连接的超时时间,不宜过长,单位ms + */ + private int connectionRequestTimout = 200; + /** + * 针对不同的地址,特别设置不同的长连接保持时间 + */ + private Map keepAliveTargetHost; + /** + * 针对不同的地址,特别设置不同的长连接保持时间,单位 s + */ + private int keepAliveTime = 60; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/DataSourceController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/DataSourceController.java new file mode 100644 index 00000000..8e569e9e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/DataSourceController.java @@ -0,0 +1,67 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.controller; + +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.DataSourceParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.data.dataSource.service.DataSourceService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** +* @desc 数据源 controller +* @website https://gitee.com/anji-plus/gaea +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@RestController +@Api(tags = "数据源管理") +@RequestMapping("/dataSource") +public class DataSourceController extends GaeaBaseController { + + @Autowired + private DataSourceService dataSourceService; + + @Override + public GaeaBaseService getService() { + return dataSourceService; + } + + @Override + public DataSource getEntity() { + return new DataSource(); + } + + @Override + public DataSourceDto getDTO() { + return new DataSourceDto(); + } + + /** + * 获取所有数据源 + * @return + */ + @GetMapping("/queryAllDataSource") + public ResponseBean queryAllDataSource() { + return responseSuccessWithData(dataSourceService.queryAllDataSource()); + } + + /** + * 测试 连接 + * @param connectionParam + * @return + */ + @PostMapping("/testConnection") + public ResponseBean testConnection(@Validated @RequestBody ConnectionParam connectionParam) { + return responseSuccessWithData(dataSourceService.testConnection(connectionParam)); + } + + + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/dto/DataSourceDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/dto/DataSourceDto.java new file mode 100644 index 00000000..0ed5a42e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/dto/DataSourceDto.java @@ -0,0 +1,74 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; +import java.util.Map; + + +/** +* +* @description 数据源 dto +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@Data +public class DataSourceDto extends GaeaBaseDTO implements Serializable { + /** 数据源编码 */ + private String sourceCode; + + /** 数据源名称 */ + private String sourceName; + + /** 数据源描述 */ + private String sourceDesc; + + /** 数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单 */ + private String sourceType; + + /** 数据源连接配置json:关系库{ jdbcUrl:'', username:'', password:'','driverName':''}ES-sql{ apiUrl:'http://127.0.0.1:9092/_xpack/sql?format=json','method':'POST','body':'{"query":"select 1"}' } 接口{ apiUrl:'http://ip:port/url', method:'' } javaBean{ beanNamw:'xxx' } */ + private String sourceConfig; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + private Integer deleteFlag; + + /**************************************************************/ + /**关系型数据库jdbcUrl */ + private String jdbcUrl; + + /** 关系型数据库用户名 */ + private String username; + + /** 关系型数据库密码 */ + private String password; + + /** 关系型数据库驱动类 */ + private String driverName; + + /** 关系型数据库sql */ + private String sql; + + /** http requestUrl */ + private String apiUrl; + + /** http method */ + private String method; + + /** http header */ + private String header; + + /** http 请求体 */ + private String body; + + /** 动态查询sql或者接口中的请求体 */ + private String dynSentence; + + /** 传入的自定义参数,解决url中存在的动态参数*/ + private Map contextData; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/ConnectionParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/ConnectionParam.java new file mode 100644 index 00000000..0ccb40cf --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/ConnectionParam.java @@ -0,0 +1,21 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * Created by raodeming on 2021/3/19. + */ +@Data +public class ConnectionParam implements Serializable { + + /** 数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单 */ + @NotBlank(message = "sourceType not empty") + private String sourceType; + + /** 数据源连接配置json:关系库{ jdbcUrl:'', username:'', password:'','driverName':''}ES-sql{ apiUrl:'http://127.0.0.1:9092/_xpack/sql?format=json','method':'POST','body':'{"query":"select 1"}' } 接口{ apiUrl:'http://ip:port/url', method:'' } javaBean{ beanNamw:'xxx' } */ + @NotBlank(message = "sourceConfig not empty") + private String sourceConfig; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/DataSourceParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/DataSourceParam.java new file mode 100644 index 00000000..1804b03d --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/DataSourceParam.java @@ -0,0 +1,31 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param; + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + + +/** +* @desc DataSource 数据集查询输入类 +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@Data +public class DataSourceParam extends PageParam implements Serializable{ + + /** 数据源名称 */ + @Query(QueryEnum.LIKE) + private String sourceName; + + /** 数据源编码 */ + @Query(QueryEnum.LIKE) + private String sourceCode; + + /** 数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单 */ + @Query(QueryEnum.EQ) + private String sourceType; +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/DataSourceMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/DataSourceMapper.java new file mode 100644 index 00000000..dcf1e224 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/DataSourceMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; + +/** +* DataSource Mapper +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@Mapper +public interface DataSourceMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/entity/DataSource.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/entity/DataSource.java new file mode 100644 index 00000000..4999ab5a --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/entity/DataSource.java @@ -0,0 +1,42 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.common.RespCommonCode; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +* @description 数据源 entity +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@TableName(value="gaea_report_data_source") +@Data +public class DataSource extends GaeaBaseEntity { + @ApiModelProperty(value = "数据源编码") + @Unique(code = RespCommonCode.SOURCE_CODE_ISEXIST) + private String sourceCode; + + @ApiModelProperty(value = "数据源名称") + private String sourceName; + + @ApiModelProperty(value = "数据源描述") + private String sourceDesc; + + @ApiModelProperty(value = "数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单") + private String sourceType; + + @ApiModelProperty(value = "数据源连接配置json:关系库{ jdbcUrl:'', username:'', password:'','driverName':''}ES-sql{ apiUrl:'http://127.0.0.1:9092/_xpack/sql?format=json','method':'POST','body':'{\"query\":\"select 1\"}' } 接口{ apiUrl:'http://ip:port/url', method:'' } javaBean{ beanNamw:'xxx' }") + private String sourceConfig; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IConfig.java new file mode 100644 index 00000000..f7354808 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IConfig.java @@ -0,0 +1,39 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api; + +/** + * 配置接口 + * @author binbin.hou + * @since 1.0.0 + */ +public interface IConfig { + + /** + * 设置驱动类 + * + * @param driverClass 驱动类 + * @since 1.0.0 + */ + void setDriverClass(final String driverClass); + + /** + * jdbc url + * @param jdbcUrl url + * @since 1.0.0 + */ + void setJdbcUrl(final String jdbcUrl); + + /** + * 设置用户信息 + * @param user 用户信息 + * @since 1.0.0 + */ + void setUser(final String user); + + /** + * 设置密码 + * @param password 密码 + * @since 1.0.0 + */ + void setPassword(final String password); + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IDataSourceConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IDataSourceConfig.java new file mode 100644 index 00000000..fb90392c --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IDataSourceConfig.java @@ -0,0 +1,13 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api; + +import javax.sql.DataSource; + +/** + * 配置接口 + * @author binbin.hou + * @since 1.0.0 + */ +public interface IDataSourceConfig extends IConfig, DataSource { + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/ILifeCycle.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/ILifeCycle.java new file mode 100644 index 00000000..5f0089df --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/ILifeCycle.java @@ -0,0 +1,21 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api; + +/** + * 生命周期管理 + * @since 1.1.0 + */ +public interface ILifeCycle { + + /** + * 生命的初始化 + * @since 1.1.0 + */ + void init(); + + /** + * 生命的销毁 + * @since 1.1.0 + */ + void destroy(); + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IPooledDataSourceConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IPooledDataSourceConfig.java new file mode 100644 index 00000000..f542c7de --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IPooledDataSourceConfig.java @@ -0,0 +1,93 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection.IPooledConnection; + +/** + * 池化的接口 + * @author binbin.hou + * @since 1.0.0 + */ +public interface IPooledDataSourceConfig extends IDataSourceConfig { + + /** + * 归还连接 + * @param pooledConnection 连接池信息 + * @since 1.5.0 + */ + void returnConnection(IPooledConnection pooledConnection); + + /** + * 设置最小尺寸 + * + * @param minSize 大小 + * @since 1.1.0 + */ + void setMinSize(final int minSize); + + /** + * 设置最大的大小 + * + * @param maxSize 最大的大小 + * @since 1.1.0 + */ + void setMaxSize(final int maxSize); + + /** + * 设置最大的等待时间 + * @param maxWaitMills 最大的等待时间 + * @since 1.1.0 + */ + void setMaxWaitMills(final long maxWaitMills); + + /** + * 设置验证查询的语句 + * + * 如果这个值为空,那么 {@link #setTestOnBorrow(boolean)} + * {@link #setTestOnIdle(boolean)}} + * {@link #setTestOnReturn(boolean)} + * 都将无效 + * @param validQuery 验证查询的语句 + * @since 1.5.0 + */ + void setValidQuery(final String validQuery); + + /** + * 验证的超时秒数 + * @param validTimeOutSeconds 验证的超时秒数 + * @since 1.5.0 + */ + void setValidTimeOutSeconds(final int validTimeOutSeconds); + + /** + * 获取连接时进行校验 + * + * 备注:影响性能 + * @param testOnBorrow 是否 + * @since 1.5.0 + */ + void setTestOnBorrow(final boolean testOnBorrow); + + /** + * 归还连接时进行校验 + * + * 备注:影响性能 + * @param testOnReturn 归还连接时进行校验 + * @since 1.5.0 + */ + void setTestOnReturn(final boolean testOnReturn); + + /** + * 闲暇的时候进行校验 + * @param testOnIdle 闲暇的时候进行校验 + * @since 1.5.0 + */ + void setTestOnIdle(final boolean testOnIdle); + + /** + * 闲暇时进行校验的时间间隔 + * @param testOnIdleIntervalSeconds 时间间隔 + * @since 1.5.0 + */ + void setTestOnIdleIntervalSeconds(final long testOnIdleIntervalSeconds); + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/IPooledConnection.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/IPooledConnection.java new file mode 100644 index 00000000..f0365db0 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/IPooledConnection.java @@ -0,0 +1,56 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.IPooledDataSourceConfig; + +import java.sql.Connection; + +/** + * 池化的连接池 + * @since 1.1.0 + */ +public interface IPooledConnection extends Connection { + + + /** + * 是否繁忙 + * @since 1.1.0 + * @return 状态 + */ + boolean isBusy(); + + /** + * 设置状态 + * @param busy 状态 + * @since 1.1.0 + */ + void setBusy(boolean busy); + + /** + * 获取真正的连接 + * @return 连接 + * @since 1.1.0 + */ + Connection getConnection(); + + /** + * 设置连接信息 + * @param connection 连接信息 + * @since 1.1.0 + */ + void setConnection(Connection connection); + + /** + * 设置对应的数据源 + * @param dataSource 数据源 + * @since 1.5.0 + */ + void setDataSource(final IPooledDataSourceConfig dataSource); + + /** + * 获取对应的数据源信息 + * @return 数据源 + * @since 1.5.0 + */ + IPooledDataSourceConfig getDataSource(); + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/PooledConnection.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/PooledConnection.java new file mode 100644 index 00000000..8d5f03df --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/PooledConnection.java @@ -0,0 +1,457 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.IPooledDataSourceConfig; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.exception.JdbcPoolException; +import lombok.extern.slf4j.Slf4j; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * 池化的连接 + * + * @since 1.1.0 + */ +@Slf4j +public class PooledConnection implements IPooledConnection { + + /** + * 是否繁忙 + * @since 1.1.0 + */ + private volatile boolean isBusy; + + /** + * 数据库链接信息 + * @since 1.1.0 + */ + private Connection connection; + + /** + * 对应的数据源信息 + * + * @since 1.1.0 + */ + private IPooledDataSourceConfig dataSource; + + @Override + public Statement createStatement() throws SQLException { + checkStatus(); + + return connection.createStatement(); + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql); + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + checkStatus(); + + return connection.prepareCall(sql); + } + + @Override + public String nativeSQL(String sql) throws SQLException { + checkStatus(); + + return connection.nativeSQL(sql); + } + + @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + checkStatus(); + + connection.setAutoCommit(autoCommit); + } + + @Override + public boolean getAutoCommit() throws SQLException { + checkStatus(); + + return connection.getAutoCommit(); + } + + @Override + public void commit() throws SQLException { + checkStatus(); + + connection.commit(); + } + + @Override + public void rollback() throws SQLException { + checkStatus(); + + connection.rollback(); + } + + @Override + public void close() throws SQLException { + checkStatus(); + + this.dataSource.returnConnection(this); + } + + @Override + public boolean isClosed() throws SQLException { + checkStatus(); + + return connection.isClosed(); + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + checkStatus(); + + return connection.getMetaData(); + } + + @Override + public void setReadOnly(boolean readOnly) throws SQLException { + checkStatus(); + + connection.setReadOnly(readOnly); + } + + @Override + public boolean isReadOnly() throws SQLException { + checkStatus(); + + return connection.isReadOnly(); + } + + @Override + public void setCatalog(String catalog) throws SQLException { + checkStatus(); + + connection.setCatalog(catalog); + } + + @Override + public String getCatalog() throws SQLException { + checkStatus(); + + return connection.getCatalog(); + } + + @Override + public void setTransactionIsolation(int level) throws SQLException { + checkStatus(); + + connection.setTransactionIsolation(level); + } + + @Override + public int getTransactionIsolation() throws SQLException { + checkStatus(); + + return connection.getTransactionIsolation(); + } + + @Override + public SQLWarning getWarnings() throws SQLException { + checkStatus(); + + return connection.getWarnings(); + } + + @Override + public void clearWarnings() throws SQLException { + checkStatus(); + + connection.clearWarnings(); + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + checkStatus(); + + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + checkStatus(); + + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + @Override + public Map> getTypeMap() throws SQLException { + checkStatus(); + + return connection.getTypeMap(); + } + + @Override + public void setTypeMap(Map> map) throws SQLException { + checkStatus(); + + connection.setTypeMap(map); + } + + @Override + public void setHoldability(int holdability) throws SQLException { + checkStatus(); + + connection.setHoldability(holdability); + } + + @Override + public int getHoldability() throws SQLException { + checkStatus(); + + return connection.getHoldability(); + } + + @Override + public Savepoint setSavepoint() throws SQLException { + checkStatus(); + + return connection.setSavepoint(); + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + checkStatus(); + + return connection.setSavepoint(name); + } + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + checkStatus(); + + connection.rollback(savepoint); + } + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + checkStatus(); + + connection.releaseSavepoint(savepoint); + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + checkStatus(); + + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + checkStatus(); + + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, autoGeneratedKeys); + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, columnIndexes); + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, columnNames); + } + + @Override + public Clob createClob() throws SQLException { + checkStatus(); + + return connection.createClob(); + } + + @Override + public Blob createBlob() throws SQLException { + checkStatus(); + + return connection.createBlob(); + } + + @Override + public NClob createNClob() throws SQLException { + checkStatus(); + + return connection.createNClob(); + } + + @Override + public SQLXML createSQLXML() throws SQLException { + checkStatus(); + + return connection.createSQLXML(); + } + + @Override + public boolean isValid(int timeout) throws SQLException { + checkStatus(); + + return connection.isValid(timeout); + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + checkStatus(); + + connection.setClientInfo(name, value); + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + checkStatus(); + + connection.setClientInfo(properties); + } + + @Override + public String getClientInfo(String name) throws SQLException { + checkStatus(); + + return connection.getClientInfo(name); + } + + @Override + public Properties getClientInfo() throws SQLException { + checkStatus(); + + return connection.getClientInfo(); + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + checkStatus(); + + return connection.createArrayOf(typeName, elements); + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + checkStatus(); + + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + checkStatus(); + + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + checkStatus(); + + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + checkStatus(); + + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + checkStatus(); + + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + checkStatus(); + + return connection.getNetworkTimeout(); + } + + @Override + public T unwrap(Class iface) throws SQLException { + checkStatus(); + + return connection.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + checkStatus(); + + return connection.isWrapperFor(iface); + } + + @Override + public boolean isBusy() { + return isBusy; + } + + @Override + public void setBusy(boolean busy) { + isBusy = busy; + } + + @Override + public Connection getConnection() { + return connection; + } + + @Override + public void setConnection(Connection connection) { + this.connection = connection; + } + + @Override + public IPooledDataSourceConfig getDataSource() { + return dataSource; + } + + @Override + public void setDataSource(IPooledDataSourceConfig dataSource) { + this.dataSource = dataSource; + } + + /** + * 对于设置为繁忙的连接,等价于关闭 + * @since 1.4.0 + */ + private void checkStatus() { + if(!isBusy) { + throw new JdbcPoolException("Connection has been closed"); + } + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/JdbcConstants.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/JdbcConstants.java new file mode 100644 index 00000000..419b72cf --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/JdbcConstants.java @@ -0,0 +1,71 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.constant; + +/** + * Created by raodeming on 2021/3/19. + */ +public class JdbcConstants { + public final static String JTDS = "jtds"; + public final static String MOCK = "mock"; + public final static String HSQL = "hsql"; + public final static String DB2 = "db2"; + public final static String DB2_DRIVER = "COM.ibm.db2.jdbc.app.DB2Driver"; + public final static String POSTGRESQL = "postgresql"; + public final static String POSTGRESQL_DRIVER = "org.postgresql.Driver"; + public final static String SYBASE = "sybase"; + public final static String SQL_SERVER = "sqlserver"; + public final static String SQL_SERVER_DRIVER = "com.microsoft.jdbc.sqlserver.SQLServerDriver"; + public final static String SQL_SERVER_DRIVER_SQLJDBC4 = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; + public final static String SQL_SERVER_DRIVER_JTDS = "net.sourceforge.jtds.jdbc.Driver"; + public final static String ORACLE = "oracle"; + public final static String ORACLE_DRIVER = "oracle.jdbc.OracleDriver"; + public final static String ORACLE_DRIVER2 = "oracle.jdbc.driver.OracleDriver"; + public final static String ALI_ORACLE = "AliOracle"; + public final static String ALI_ORACLE_DRIVER = "com.alibaba.jdbc.AlibabaDriver"; + public final static String MYSQL = "mysql"; + public final static String MYSQL_DRIVER = "com.mysql.jdbc.Driver"; + public final static String MYSQL_DRIVER_6 = "com.mysql.cj.jdbc.Driver"; + public final static String MYSQL_DRIVER_REPLICATE = "com.mysql.jdbc."; + public final static String MARIADB = "mariadb"; + public final static String MARIADB_DRIVER = "org.mariadb.jdbc.Driver"; + public final static String DERBY = "derby"; + public final static String HBASE = "hbase"; + public final static String HIVE = "hive"; + public final static String HIVE_DRIVER = "org.apache.hive.jdbc.HiveDriver"; + public final static String H2 = "h2"; + public final static String H2_DRIVER = "org.h2.Driver"; + public final static String DM = "dm"; + public final static String DM_DRIVER = "dm.jdbc.driver.DmDriver"; + public final static String KINGBASE = "kingbase"; + public final static String KINGBASE_DRIVER = "com.kingbase.Driver"; + public final static String GBASE = "gbase"; + public final static String GBASE_DRIVER = "com.gbase.jdbc.Driver"; + public final static String XUGU = "xugu"; + public final static String XUGU_DRIVER = "com.xugu.cloudjdbc.Driver"; + public final static String OCEANBASE = "oceanbase"; + public final static String OCEANBASE_DRIVER = "com.mysql.jdbc.Driver"; + public final static String INFORMIX = "informix"; + public final static String ODPS = "odps"; + public final static String ODPS_DRIVER = "com.aliyun.odps.jdbc.OdpsDriver"; + public final static String TERADATA = "teradata"; + public final static String TERADATA_DRIVER = "com.teradata.jdbc.TeraDriver"; + public final static String LOG4JDBC = "log4jdbc"; + public final static String LOG4JDBC_DRIVER = "net.sf.log4jdbc.DriverSpy"; + public final static String PHOENIX = "phoenix"; + public final static String PHOENIX_DRIVER = "org.apache.phoenix.jdbc.PhoenixDriver"; + public final static String ENTERPRISEDB = "edb"; + public final static String ENTERPRISEDB_DRIVER = "com.edb.Driver"; + public final static String KYLIN = "kylin"; + public final static String KYLIN_DRIVER = "org.apache.kylin.jdbc.Driver"; + public final static String SQLITE = "sqlite"; + public final static String SQLITE_DRIVER = "org.sqlite.JDBC"; + public final static String ALIYUN_ADS = "aliyun_ads"; + public final static String ALIYUN_DRDS = "aliyun_drds"; + public final static String PRESTO = "presto"; + public final static String ELASTIC_SEARCH = "elasticsearch"; + public final static String ELASTIC_SEARCH_SQL = "elasticsearch_sql"; + public final static String ELASTIC_SEARCH_DRIVER = "com.alibaba.xdriver.elastic.jdbc.ElasticDriver"; + public final static String CLICKHOUSE = "clickhouse"; + public final static String CLICKHOUSE_DRIVER = "ru.yandex.clickhouse.ClickHouseDriver"; + public final static String KUDU_IMAPLA = "kudu_impala"; + public final static String HTTP = "http"; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/PooledConst.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/PooledConst.java new file mode 100644 index 00000000..b584060d --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/PooledConst.java @@ -0,0 +1,71 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.constant; + +/** + * 线程池常量 + * @since 1.1.0 + */ +public final class PooledConst { + + private PooledConst(){} + + /** + * 默认的最小连接数 + * @since 1.1.0 + */ + public static final int DEFAULT_MIN_SIZE = 10; + + /** + * 默认最大的连接数 + * @since 1.1.0 + */ + public static final int DEFAULT_MAX_SIZE = 300; + + /** + * 默认最大的等待毫秒数 + * + * 默认:1 min + * + * @since 1.3.0 + */ + public static final int DEFAULT_MAX_WAIT_MILLS = 60 * 1000; + + /** + * 默认验证查询的语句 + * @since 1.5.0 + */ + public static final String DEFAULT_VALID_QUERY = "select 1 from dual"; + + /** + * 默认的验证的超时时间 + * @since 1.5.0 + */ + public static final int DEFAULT_VALID_TIME_OUT_SECONDS = 5; + + /** + * 获取连接时,默认不校验 + * @since 1.5.0 + */ + public static final boolean DEFAULT_TEST_ON_BORROW = false; + + + /** + * 归还连接时,默认不校验 + * @since 1.5.0 + */ + public static final boolean DEFAULT_TEST_ON_RETURN = false; + + /** + * 默认闲暇的时候,进行校验 + * + * @since 1.5.0 + */ + public static final boolean DEFAULT_TEST_ON_IDLE = true; + + /** + * 1min 自动校验一次 + * + * @since 1.5.0 + */ + public static final long DEFAULT_TEST_ON_IDLE_INTERVAL_SECONDS = 60; + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractDataSourceConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractDataSourceConfig.java new file mode 100644 index 00000000..786bc5f7 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractDataSourceConfig.java @@ -0,0 +1,68 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class AbstractDataSourceConfig extends DataSourceConfigAdaptor { + + /** + * 驱动类 + * @since 1.0.0 + */ + protected String driverClass; + + /** + * jdbc url + * @since 1.0.0 + */ + protected String jdbcUrl; + + /** + * 用户 + * @since 1.0.0 + */ + protected String user; + + /** + * 密码 + * @since 1.0.0 + */ + protected String password; + + public String getDriverClass() { + return driverClass; + } + + @Override + public void setDriverClass(String driverClass) { + this.driverClass = driverClass; + } + + public String getJdbcUrl() { + return jdbcUrl; + } + + @Override + public void setJdbcUrl(String jdbcUrl) { + this.jdbcUrl = jdbcUrl; + } + + public String getUser() { + return user; + } + + @Override + public void setUser(String user) { + this.user = user; + } + + public String getPassword() { + return password; + } + + @Override + public void setPassword(String password) { + this.password = password; + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractPooledDataSourceConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractPooledDataSourceConfig.java new file mode 100644 index 00000000..786fb5ec --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractPooledDataSourceConfig.java @@ -0,0 +1,159 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.ILifeCycle; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.IPooledDataSourceConfig; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.constant.PooledConst; + +/** + * @author binbin.hou + * @since 1.1.0 + */ +public abstract class AbstractPooledDataSourceConfig extends AbstractDataSourceConfig + implements IPooledDataSourceConfig, ILifeCycle { + + /** + * 最小尺寸 + * @since 1.1.0 + */ + protected int minSize = PooledConst.DEFAULT_MIN_SIZE; + + /** + * 最大尺寸 + * @since 1.1.0 + */ + protected int maxSize = PooledConst.DEFAULT_MAX_SIZE; + + /** + * 最大的等待时间 + * @since 1.3.0 + */ + protected long maxWaitMills = PooledConst.DEFAULT_MAX_WAIT_MILLS; + + /** + * 验证查询 + * @since 1.5.0 + */ + protected String validQuery = PooledConst.DEFAULT_VALID_QUERY; + + /** + * 验证的超时时间 + * @since 1.5.0 + */ + protected int validTimeOutSeconds = PooledConst.DEFAULT_VALID_TIME_OUT_SECONDS; + + /** + * 获取时验证 + * @since 1.5.0 + */ + protected boolean testOnBorrow = PooledConst.DEFAULT_TEST_ON_BORROW; + + /** + * 归还时验证 + * @since 1.5.0 + */ + protected boolean testOnReturn = PooledConst.DEFAULT_TEST_ON_RETURN; + + /** + * 闲暇时验证 + * @since 1.5.0 + */ + protected boolean testOnIdle = PooledConst.DEFAULT_TEST_ON_IDLE; + + /** + * 闲暇时验证的时间间隔 + * @since 1.5.0 + */ + protected long testOnIdleIntervalSeconds = PooledConst.DEFAULT_TEST_ON_IDLE_INTERVAL_SECONDS; + + public int getMinSize() { + return minSize; + } + + @Override + public void setMinSize(int minSize) { + this.minSize = minSize; + } + + public int getMaxSize() { + return maxSize; + } + + @Override + public void setMaxSize(int maxSize) { + this.maxSize = maxSize; + } + + public long getMaxWaitMills() { + return maxWaitMills; + } + + @Override + public void setMaxWaitMills(long maxWaitMills) { + this.maxWaitMills = maxWaitMills; + } + + public String getValidQuery() { + return validQuery; + } + + @Override + public void setValidQuery(String validQuery) { + this.validQuery = validQuery; + } + + public int getValidTimeOutSeconds() { + return validTimeOutSeconds; + } + + @Override + public void setValidTimeOutSeconds(int validTimeOutSeconds) { + this.validTimeOutSeconds = validTimeOutSeconds; + } + + public boolean isTestOnBorrow() { + return testOnBorrow; + } + + @Override + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public boolean isTestOnReturn() { + return testOnReturn; + } + + @Override + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + public boolean isTestOnIdle() { + return testOnIdle; + } + + @Override + public void setTestOnIdle(boolean testOnIdle) { + this.testOnIdle = testOnIdle; + } + + public long getTestOnIdleIntervalSeconds() { + return testOnIdleIntervalSeconds; + } + + @Override + public void setTestOnIdleIntervalSeconds(long testOnIdleIntervalSeconds) { + this.testOnIdleIntervalSeconds = testOnIdleIntervalSeconds; + } + + @Override + public void init() { + + } + + @Override + public void destroy() { + + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/DataSourceConfigAdaptor.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/DataSourceConfigAdaptor.java new file mode 100644 index 00000000..dcab7f88 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/DataSourceConfigAdaptor.java @@ -0,0 +1,82 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.IDataSourceConfig; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class DataSourceConfigAdaptor implements IDataSourceConfig { + + @Override + public Connection getConnection() throws SQLException { + return null; + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + return null; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return null; + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + + } + + @Override + public int getLoginTimeout() throws SQLException { + return 0; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + + @Override + public void setDriverClass(String driverClass) { + + } + + @Override + public void setJdbcUrl(String jdbcUrl) { + + } + + @Override + public void setUser(String user) { + + } + + @Override + public void setPassword(String password) { + + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/PooledDataSource.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/PooledDataSource.java new file mode 100644 index 00000000..24b7def2 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/PooledDataSource.java @@ -0,0 +1,240 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection.IPooledConnection; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection.PooledConnection; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.exception.JdbcPoolException; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util.DriverClassUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 池化的数据源 + * + * @author binbin.hou + * @since 1.1.0 + */ +@Slf4j +public class PooledDataSource extends AbstractPooledDataSourceConfig { + + /** + * 内置的队列 + * + * @since 1.1.0 + */ + private List pool = new ArrayList<>(); + + @Override + public synchronized void init() { + DriverClassUtil.loadDriverClass(super.driverClass, super.jdbcUrl); + + this.initJdbcPool(); + + // 初始化 idle check + this.initTestOnIdle(); + } + + @Override + public synchronized Connection getConnection() throws SQLException { + //1. 获取第一个不是 busy 的连接 + Optional connectionOptional = getFreeConnectionFromPool(); + if (connectionOptional.isPresent()) { + return connectionOptional.get(); + } + + //2. 考虑是否可以扩容 + if (pool.size() >= maxSize) { + //2.1 立刻返回 + if (maxWaitMills <= 0) { + throw new JdbcPoolException("Can't get connection from pool!"); + } + + + //2.2 循环等待 + final long startWaitMills = System.currentTimeMillis(); + final long endWaitMills = startWaitMills + maxWaitMills; + while (System.currentTimeMillis() < endWaitMills) { + Optional optional = getFreeConnectionFromPool(); + if (optional.isPresent()) { + return optional.get(); + } + + try { + TimeUnit.MILLISECONDS.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + log.debug("等待连接池归还,wait for 1 mills"); + } + + //2.3 等待超时 + throw new JdbcPoolException("Can't get connection from pool, wait time out for mills: " + maxWaitMills); + } + + //3. 扩容(暂时只扩容一个) + log.debug("开始扩容连接池大小,step: 1"); + IPooledConnection pooledConnection = createPooledConnection(); + pooledConnection.setBusy(true); + this.pool.add(pooledConnection); + log.debug("从扩容后的连接池中获取连接"); + return pooledConnection; + } + + @Override + public void returnConnection(IPooledConnection pooledConnection) { + // 验证状态 + if (testOnReturn) { + checkValid(pooledConnection); + } + + // 设置为不繁忙 + pooledConnection.setBusy(false); + log.debug("归还连接,状态设置为不繁忙"); + } + + /** + * 获取空闲的连接 + * + * @return 连接 + * @since 1.3.0 + */ + private Optional getFreeConnectionFromPool() { + for (IPooledConnection pc : pool) { + if (!pc.isBusy()) { + pc.setBusy(true); + log.debug("从连接池中获取连接"); + + // 验证有效性 + if (testOnBorrow) { + log.debug("Test on borrow start"); + checkValid(pc); + log.debug("Test on borrow finish"); + } + + return Optional.of(pc); + } + } + // 空 + return Optional.empty(); + } + + + /** + * https://stackoverflow.com/questions/3668506/efficient-sql-test-query-or-validation-query-that-will-work-across-all-or-most + *

+ * 真正支持标准的,直接使用 {@link Connection#isValid(int)} 验证比较合适 + * + * @param pooledConnection 连接池信息 + * @since 1.5.0 + */ + private void checkValid(final IPooledConnection pooledConnection) { + if (StringUtils.isNotEmpty(super.validQuery)) { + Connection connection = pooledConnection.getConnection(); + try { + // 如果连接无效,重新申请一个新的替代 + if (!connection.isValid(super.validTimeOutSeconds)) { + log.debug("Old connection is inValid, start create one for it."); + + Connection newConnection = createConnection(); + pooledConnection.setConnection(newConnection); + log.debug("Old connection is inValid, finish create one for it."); + } + } catch (SQLException throwables) { + throw new JdbcPoolException(throwables); + } + } else { + log.debug("valid query is empty, ignore valid."); + } + } + + /** + * 初始化连接池 + * + * @since 1.1.0 + */ + private void initJdbcPool() { + final int minSize = super.minSize; + pool = new ArrayList<>(minSize); + + for (int i = 0; i < minSize; i++) { + IPooledConnection pooledConnection = createPooledConnection(); + + pool.add(pooledConnection); + } + } + + /** + * 创建一个池化的连接 + * + * @return 连接 + * @since 1.1.0 + */ + private IPooledConnection createPooledConnection() { + Connection connection = createConnection(); + + IPooledConnection pooledConnection = new PooledConnection(); + pooledConnection.setBusy(false); + pooledConnection.setConnection(connection); + pooledConnection.setDataSource(this); + + return pooledConnection; + } + + /** + * 创建新连接 + * + * @return 连接 + * @since 1.1.0 + */ + private Connection createConnection() { + try { + if (StringUtils.isBlank(super.getUser()) && StringUtils.isBlank(super.getPassword())) { + return DriverManager.getConnection(super.getJdbcUrl()); + } + return DriverManager.getConnection(super.getJdbcUrl(), + super.getUser(), super.getPassword()); + } catch (SQLException e) { + throw new JdbcPoolException(e); + } + } + + + /** + * 初始化空闲时检验 + * + * @since 1.5.0 + */ + private void initTestOnIdle() { + if (StringUtils.isNotEmpty(validQuery)) { + ScheduledExecutorService idleExecutor = Executors.newSingleThreadScheduledExecutor(); + + idleExecutor.scheduleAtFixedRate(this::testOnIdleCheck, super.testOnIdleIntervalSeconds, testOnIdleIntervalSeconds, TimeUnit.SECONDS); + log.debug("Test on idle config with interval seonds: " + testOnIdleIntervalSeconds); + } + } + + /** + * 验证所有的空闲连接是否有效 + * + * @since 1.5.0 + */ + private void testOnIdleCheck() { + log.debug("start check test on idle"); + for (IPooledConnection pc : this.pool) { + if (!pc.isBusy()) { + checkValid(pc); + } + } + log.debug("finish check test on idle"); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/UnPooledDataSource.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/UnPooledDataSource.java new file mode 100644 index 00000000..e45010c9 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/UnPooledDataSource.java @@ -0,0 +1,26 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util.DriverClassUtil; +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class UnPooledDataSource extends AbstractDataSourceConfig { + + @Override + public Connection getConnection() throws SQLException { + DriverClassUtil.loadDriverClass(super.driverClass, super.jdbcUrl); + if (StringUtils.isBlank(super.getUser()) && StringUtils.isBlank(super.getPassword())) { + return DriverManager.getConnection(super.jdbcUrl); + } + return DriverManager.getConnection(super.getJdbcUrl(), + super.getUser(), super.getPassword()); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/exception/JdbcPoolException.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/exception/JdbcPoolException.java new file mode 100644 index 00000000..ace4113d --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/exception/JdbcPoolException.java @@ -0,0 +1,28 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.exception; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class JdbcPoolException extends RuntimeException { + + public JdbcPoolException() { + } + + public JdbcPoolException(String message) { + super(message); + } + + public JdbcPoolException(String message, Throwable cause) { + super(message, cause); + } + + public JdbcPoolException(Throwable cause) { + super(cause); + } + + public JdbcPoolException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DataSourceHandleUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DataSourceHandleUtil.java new file mode 100644 index 00000000..604ceeae --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DataSourceHandleUtil.java @@ -0,0 +1,13 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util; + +/** + * Created by raodeming on 2021/3/19. + */ +public class DataSourceHandleUtil { + + + public static void mysqlConnection() { + + + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DriverClassUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DriverClassUtil.java new file mode 100644 index 00000000..da1f71de --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DriverClassUtil.java @@ -0,0 +1,89 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util; + +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.common.RespCommonCode; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by raodeming on 2021/4/19. + */ +public final class DriverClassUtil { + + /** + * 存放驱动类信息 + */ + private static final Map DRIVER_CLASS_MAP; + + static { + DRIVER_CLASS_MAP = new HashMap<>(32); + DRIVER_CLASS_MAP.put("jdbc:db2", "COM.ibm.db2.jdbc.app.DB2Driver"); + DRIVER_CLASS_MAP.put("jdbc:firebirdsql", "org.firebirdsql.jdbc.FBDriver"); + DRIVER_CLASS_MAP.put("jdbc:edbc", "ca.edbc.jdbc.EdbcDriver"); + DRIVER_CLASS_MAP.put("jdbc:pointbase", "com.pointbase.jdbc.jdbcUniversalDriver"); + DRIVER_CLASS_MAP.put("jdbc:fake", "com.alibaba.druid.mock.MockDriver"); + DRIVER_CLASS_MAP.put("jdbc:informix-sqli", "com.informix.jdbc.IfxDriver"); + DRIVER_CLASS_MAP.put("jdbc:sqlite", "org.sqlite.JDBC"); + DRIVER_CLASS_MAP.put("jdbc:microsoft", "com.microsoft.jdbc.sqlserver.SQLServerDriver"); + DRIVER_CLASS_MAP.put("jdbc:hsqldb", "org.hsqldb.jdbcDriver"); + DRIVER_CLASS_MAP.put("jdbc:postgresql", "org.postgresql.Driver"); + DRIVER_CLASS_MAP.put("jdbc:ingres", "com.ingres.jdbc.IngresDriver"); + DRIVER_CLASS_MAP.put("jdbc:cloudscape", "COM.cloudscape.core.JDBCDriver"); + DRIVER_CLASS_MAP.put("jdbc:JSQLConnect", "com.jnetdirect.jsql.JSQLDriver"); + DRIVER_CLASS_MAP.put("jdbc:derby", "org.apache.derby.jdbc.EmbeddedDriver"); + DRIVER_CLASS_MAP.put("jdbc:timesten", "com.timesten.jdbc.TimesTenDriver"); + DRIVER_CLASS_MAP.put("jdbc:interbase", "interbase.interclient.Driver"); + DRIVER_CLASS_MAP.put("jdbc:h2", "org.h2.Driver"); + DRIVER_CLASS_MAP.put("jdbc:as400", "com.ibm.as400.access.AS400JDBCDriver"); + DRIVER_CLASS_MAP.put("jdbc:sybase:Tds", "com.sybase.jdbc2.jdbc.SybDriver"); + DRIVER_CLASS_MAP.put("jdbc:mock", "com.alibaba.druid.mock.MockDriver"); + DRIVER_CLASS_MAP.put("jdbc:oracle", "oracle.jdbc.driver.OracleDriver"); + DRIVER_CLASS_MAP.put("jdbc:mysql", "com.mysql.jdbc.Driver"); + DRIVER_CLASS_MAP.put("jdbc:odps", "com.aliyun.odps.jdbc.OdpsDriver"); + DRIVER_CLASS_MAP.put("jdbc:mckoi", "com.mckoi.JDBCDriver"); + DRIVER_CLASS_MAP.put("jdbc:jtds", "net.sourceforge.jtds.jdbc.Driver"); + DRIVER_CLASS_MAP.put("jdbc:sapdb", "com.sap.dbtech.jdbc.DriverSapDB"); + DRIVER_CLASS_MAP.put("jdbc:JTurbo", "com.newatlanta.jturbo.driver.Driver"); + DRIVER_CLASS_MAP.put("jdbc:mimer:multi1", "com.mimer.jdbc.Driver"); + } + + /** + * 加载驱动类信息 + * @param driverClass 驱动类 + * @param url 连接信息 + */ + public static void loadDriverClass(String driverClass, final String url) { + if(StringUtils.isEmpty(driverClass)) { + driverClass = getDriverClassByUrl(url); + } + + try { + Class.forName(driverClass); + } catch (ClassNotFoundException e) { + throw BusinessExceptionBuilder.build(RespCommonCode.CLASS_NOT_FOUND, e.getMessage()); + } + } + + + /** + * 根据 URL 获取对应的驱动类 + * + * 1. 禁止 url 为空 + * 2. 如果未找到,则直接报错。 + * @param url url + * @return 驱动信息 + */ + private static String getDriverClassByUrl(final String url) { + for(Map.Entry entry : DRIVER_CLASS_MAP.entrySet()) { + String urlPrefix = entry.getKey(); + if(url.startsWith(urlPrefix)) { + return entry.getValue(); + } + } + + throw BusinessExceptionBuilder.build(RespCommonCode.CLASS_NOT_FOUND, "Can't auto find match driver class for url: " + url); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/JdbcUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/JdbcUtil.java new file mode 100644 index 00000000..94d6eb26 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/JdbcUtil.java @@ -0,0 +1,100 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource.PooledDataSource; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource.UnPooledDataSource; +import lombok.extern.slf4j.Slf4j; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by raodeming on 2021/3/18. + */ +@Slf4j +public class JdbcUtil { + + private static Lock lock = new ReentrantLock(); + + private static Lock deleteLock = new ReentrantLock(); + + //所有数据源的连接池存在map里 + static Map map = new HashMap<>(); + + public static PooledDataSource getJdbcConnectionPool(DataSourceDto dataSource) { + if (map.containsKey(dataSource.getId())) { + return map.get(dataSource.getId()); + } else { + lock.lock(); + try { + log.debug(Thread.currentThread().getName() + "获取锁"); + if (!map.containsKey(dataSource.getId())) { + PooledDataSource pool = new PooledDataSource(); + pool.setJdbcUrl(dataSource.getJdbcUrl()); + pool.setUser(dataSource.getUsername()); + pool.setPassword(dataSource.getPassword()); + pool.setDriverClass(dataSource.getDriverName()); + pool.init(); + map.put(dataSource.getId(), pool); + log.info("创建连接池成功:{}", dataSource.getJdbcUrl()); + } + return map.get(dataSource.getId()); + } finally { + lock.unlock(); + } + } + } + + /** + * 删除数据库连接池 + * @param id + */ + public static void removeJdbcConnectionPool(Long id) { + deleteLock.lock(); + try { + PooledDataSource pool = map.get(id); + if (pool != null) { + map.remove(id); + } + } catch (Exception e) { + log.error(e.toString()); + } finally { + deleteLock.unlock(); + } + + } + + /** + * 获取连接 + * @param dataSource + * @return + * @throws SQLException + */ + public static Connection getPooledConnection(DataSourceDto dataSource) throws SQLException { + PooledDataSource pool = getJdbcConnectionPool(dataSource); + return pool.getConnection(); + } + + /** + * 测试数据库连接 获取一个连接 + * @param dataSource + * @return + * @throws ClassNotFoundException driverName不正确 + * @throws SQLException + */ + public static Connection getUnPooledConnection(DataSourceDto dataSource) throws SQLException { + UnPooledDataSource source = new UnPooledDataSource(); + source.setJdbcUrl(dataSource.getJdbcUrl()); + source.setDriverClass(dataSource.getDriverName()); + source.setUser(dataSource.getUsername()); + source.setPassword(dataSource.getPassword()); + return source.getConnection(); + } + + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/DataSourceService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/DataSourceService.java new file mode 100644 index 00000000..220b0b25 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/DataSourceService.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.service; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.DataSourceParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; + +import java.util.List; + +/** +* @desc DataSource 数据集服务接口 +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +public interface DataSourceService extends GaeaBaseService { + + /** + * 获取所有数据源 + * @return + */ + List queryAllDataSource(); + + /** + * 测试 连接 + * @param connectionParam + * @return + */ + Boolean testConnection(ConnectionParam connectionParam); + + /** + * 执行sql + * @param dto + * @return + */ + List execute(DataSourceDto dto); + + /** + * 执行sql,统计数据total + * @param dataSourceDto + * @param dto + * @return + */ + long total(DataSourceDto dataSourceDto, DataSetDto dto); +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/impl/DataSourceServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/impl/DataSourceServiceImpl.java new file mode 100644 index 00000000..a6d2e991 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/impl/DataSourceServiceImpl.java @@ -0,0 +1,384 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.constant.Enabled; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.utils.GaeaAssert; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.DataSourceMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.constant.JdbcConstants; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util.JdbcUtil; +import com.anjiplus.template.gaea.business.modules.data.dataSource.service.DataSourceService; +import com.anjiplus.template.gaea.common.RespCommonCode; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Raod + * @desc DataSource 数据集服务实现 + * @date 2021-03-18 12:09:57.728203200 + **/ +@Service +@Slf4j +public class DataSourceServiceImpl implements DataSourceService { + + @Autowired + private DataSourceMapper dataSourceMapper; + + @Resource(name = "dataSourceRestTemplate") + private RestTemplate restTemplate; + + @Autowired + private DataSetParamService dataSetParamService; + + @Override + public GaeaBaseMapper getMapper() { + return dataSourceMapper; + } + + + /** + * 获取所有数据源 + * @return + */ + @Override + public List queryAllDataSource() { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.select(DataSource::getSourceCode, DataSource::getSourceName) + .eq(DataSource::getEnableFlag, Enabled.YES.getValue()); + return dataSourceMapper.selectList(wrapper); + } + + /** + * 测试 连接 + * + * @param connectionParam + * @return + */ + @Override + public Boolean testConnection(ConnectionParam connectionParam) { + String sourceType = connectionParam.getSourceType(); + String sourceConfig = connectionParam.getSourceConfig(); + DataSourceDto dto = new DataSourceDto(); + dto.setSourceConfig(sourceConfig); + switch (sourceType) { + case JdbcConstants.ELASTIC_SEARCH_SQL: + testElasticsearchSqlConnection(dto); + break; + case JdbcConstants.MYSQL: + case JdbcConstants.KUDU_IMAPLA: + testRelationalDb(dto); + break; + case JdbcConstants.HTTP: + testHttp(dto); + break; + default: + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_TYPE_DOES_NOT_MATCH_TEMPORARILY); + } + return true; + + } + + @Override + public List execute(DataSourceDto dto) { + String sourceType = dto.getSourceType(); + switch (sourceType) { + case JdbcConstants.ELASTIC_SEARCH_SQL: + return executeElasticsearchSql(dto); + case JdbcConstants.MYSQL: + case JdbcConstants.KUDU_IMAPLA: + return executeRelationalDb(dto); + case JdbcConstants.HTTP: + return executeHttp(dto); + default: + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_TYPE_DOES_NOT_MATCH_TEMPORARILY); + } + } + + /** + * 执行sql,统计数据total + * + * @param dto + * @return + */ + @Override + public long total(DataSourceDto sourceDto, DataSetDto dto) { + //区分数据类型 + String sourceType = sourceDto.getSourceType(); + switch (sourceType) { + case JdbcConstants.ELASTIC_SEARCH_SQL: + return 0; + case JdbcConstants.MYSQL: + return mysqlTotal(sourceDto, dto); + default: + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_TYPE_DOES_NOT_MATCH_TEMPORARILY); + } + + } + + /** + * 获取mysql count 和添加limit分页信息 + * @param sourceDto + * @param dto + * @return + */ + public long mysqlTotal(DataSourceDto sourceDto, DataSetDto dto){ + String dynSentence = sourceDto.getDynSentence(); + String sql = "select count(1) as count from (" + dynSentence + ") as gaeaExecute"; + sourceDto.setDynSentence(sql); + List result = execute(sourceDto); + + //sql 拼接 limit 分页信息 + int pageNumber = Integer.parseInt(dto.getContextData().getOrDefault("pageNumber", "1").toString()); + int pageSize = Integer.parseInt(dto.getContextData().getOrDefault("pageSize", "10").toString()); + String sqlLimit = " limit " + (pageNumber - 1) * pageSize + "," + pageSize; + sourceDto.setDynSentence(dynSentence.concat(sqlLimit)); + log.info("当前total:{}, 添加分页参数,sql语句:{}", JSONObject.toJSONString(result), sourceDto.getDynSentence()); + return result.get(0).getLongValue("count"); + } + + + + public List executeElasticsearchSql(DataSourceDto dto) { + analysisHttpConfig(dto); + HttpHeaders headers = new HttpHeaders(); + headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class)); + HttpEntity entity = new HttpEntity<>(dto.getDynSentence(), headers); + ResponseEntity exchange; + try { + exchange = restTemplate.exchange(dto.getApiUrl(), HttpMethod.valueOf(dto.getMethod()), entity, JSONObject.class); + } catch (Exception e) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + List result; + try { + JSONObject body = exchange.getBody(); + //解析es sql数据 + if (null == body) { + return null; + } + JSONArray columns = body.getJSONArray("columns"); + JSONArray rows = body.getJSONArray("rows"); + result = new ArrayList<>(); + for (int i = 0; i < rows.size(); i++) { + JSONArray row = rows.getJSONArray(i); + JSONObject jsonObject = new JSONObject(); + for (int j = 0; j < row.size(); j++) { + String name = columns.getJSONObject(j).getString("name"); + String value = row.getString(j); + jsonObject.put(name, value); + } + result.add(jsonObject); + } + } catch (Exception e) { + throw BusinessExceptionBuilder.build(RespCommonCode.ANALYSIS_DATA_ERROR, e.getMessage()); + } + return result; + } + + public List executeRelationalDb(DataSourceDto dto) { + analysisRelationalDbConfig(dto); + Connection pooledConnection = null; + try { + pooledConnection = JdbcUtil.getPooledConnection(dto); + + PreparedStatement statement = pooledConnection.prepareStatement(dto.getDynSentence()); + ResultSet rs = statement.executeQuery(); + + int columnCount = rs.getMetaData().getColumnCount(); + + List columns = new ArrayList<>(); + for (int i = 1; i <= columnCount; i++) { + String columnName = rs.getMetaData().getColumnLabel(i); + columns.add(columnName); + } + List list = new ArrayList<>(); + while (rs.next()) { + JSONObject jo = new JSONObject(); + columns.forEach(t -> { + try { + Object value = rs.getObject(t); + jo.put(t, value); + } catch (SQLException throwable) { + throw BusinessExceptionBuilder.build(RespCommonCode.EXECUTE_SQL_ERROR, throwable.getMessage()); + } + }); + list.add(jo); + } + return list; + } catch (Exception throwable) { + throw BusinessExceptionBuilder.build(RespCommonCode.EXECUTE_SQL_ERROR, throwable.getMessage()); + } finally { + try { + pooledConnection.close(); + } catch (SQLException throwable) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, throwable.getMessage()); + } + } + } + + /** + * http 执行获取数据 + * + * @param dto + */ + public List executeHttp(DataSourceDto dto) { + analysisHttpConfig(dto); + HttpHeaders headers = new HttpHeaders(); + headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class)); + HttpEntity entity = new HttpEntity<>(dto.getDynSentence(), headers); + ResponseEntity exchange; + try { + exchange = restTemplate.exchange(dto.getApiUrl(), HttpMethod.valueOf(dto.getMethod()), entity, JSONObject.class); + } catch (Exception e) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + JSONObject body = exchange.getBody(); + List result = new ArrayList<>(); + result.add(body); + return result; + } + + /** + * 关系型数据库 测试连接 + * + * @param dto + */ + public void testRelationalDb(DataSourceDto dto) { + analysisRelationalDbConfig(dto); + try { + Connection unPooledConnection = JdbcUtil.getUnPooledConnection(dto); + String catalog = unPooledConnection.getCatalog(); + log.info("数据库测试连接成功:{}", catalog); + unPooledConnection.close(); + } catch (Exception e) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + } + + /** + * http 测试连接 + * + * @param dto + */ + public void testHttp(DataSourceDto dto) { + analysisHttpConfig(dto); + String apiUrl = dto.getApiUrl(); + String method = dto.getMethod(); + String body = dto.getBody(); + HttpHeaders headers = new HttpHeaders(); + headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class)); + HttpEntity entity = new HttpEntity<>(body, headers); + ResponseEntity exchange; + try { + exchange = restTemplate.exchange(apiUrl, HttpMethod.valueOf(method), entity, Object.class); + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + } catch (RestClientException e) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + } + + + /** + * 关系型数据库 测试连接 + * + * @param dto + */ + public void testElasticsearchSqlConnection(DataSourceDto dto) { + analysisHttpConfig(dto); + String apiUrl = dto.getApiUrl(); + String method = dto.getMethod(); + String body = dto.getBody(); + HttpHeaders headers = new HttpHeaders(); + headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class)); + HttpEntity entity = new HttpEntity<>(body, headers); + ResponseEntity exchange; + try { + exchange = restTemplate.exchange(apiUrl, HttpMethod.valueOf(method), entity, Object.class); + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + } catch (RestClientException e) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + + } + + + public void analysisRelationalDbConfig(DataSourceDto dto) { + JSONObject json = JSONObject.parseObject(dto.getSourceConfig()); + GaeaAssert.isFalse(json.containsKey("jdbcUrl"), ResponseCode.PARAM_IS_NULL,"jdbcUrl not empty"); + GaeaAssert.isFalse(json.containsKey("driverName"), ResponseCode.PARAM_IS_NULL,"driverName not empty"); + String jdbcUrl = json.getString("jdbcUrl"); + String username = json.getString("username"); + String password = json.getString("password"); + String driverName = json.getString("driverName"); + dto.setJdbcUrl(jdbcUrl); + dto.setDriverName(driverName); + dto.setUsername(username); + dto.setPassword(password); + } + + + /** + * es通过api获取数据 + * + * @param dto + * @return + */ + public void analysisHttpConfig(DataSourceDto dto) { + JSONObject json = JSONObject.parseObject(dto.getSourceConfig()); + GaeaAssert.isFalse(json.containsKey("apiUrl"), ResponseCode.PARAM_IS_NULL,"apiUrl not empty"); + GaeaAssert.isFalse(json.containsKey("method"), ResponseCode.PARAM_IS_NULL,"method not empty"); + GaeaAssert.isFalse(json.containsKey("header"), ResponseCode.PARAM_IS_NULL,"header not empty"); + GaeaAssert.isFalse(json.containsKey("body"), ResponseCode.PARAM_IS_NULL,"body not empty"); + String apiUrl = json.getString("apiUrl"); + String method = json.getString("method"); + String header = json.getString("header"); + String body = json.getString("body"); + //解决url中存在的动态参数 + apiUrl = dataSetParamService.transform(dto.getContextData(), apiUrl); + //请求头中动态参数 + header = dataSetParamService.transform(dto.getContextData(), header); + dto.setApiUrl(apiUrl); + dto.setMethod(method); + dto.setHeader(header); + dto.setBody(body); + } + + +} \ No newline at end of file