大时代的小青年呀 3 years ago
parent 41de9a96c1
commit 4fefe37cfe

@ -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<DataSetParam, DataSet, DataSetDto> {
@Autowired
private DataSetService dataSetService;
@Override
public GaeaBaseService<DataSetParam, DataSet> 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());
}
}

@ -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<DataSetParamDto> dataSetParamDtoList;
/** 数据转换集合 */
private List<DataSetTransformDto> dataSetTransformDtoList;
/** 传入的自定义参数*/
private Map<String, Object> contextData;
private Set<String> setParamList;
}

@ -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<JSONObject> data;
public OriginalDataDto(List<JSONObject> data) {
this.data = data;
}
public OriginalDataDto(long total, List<JSONObject> data) {
this.total = total;
this.data = data;
}
public OriginalDataDto() {
}
}

@ -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;
}

@ -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<DataSetParamDto> dataSetParamDtoList;
/** 数据转换集合 */
private List<DataSetTransformDto> dataSetTransformDtoList;
}

@ -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<DataSet> {
}

@ -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;
}

@ -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<DataSetParam, DataSet> {
/**
*
* @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<DataSet> queryAllDataSet();
}

@ -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<DataSet> 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<DataSetParam> dataSetParamList = dataSetParamService.list(
new QueryWrapper<DataSetParam>()
.lambda()
.eq(DataSetParam::getSetCode, setCode)
);
List<DataSetParamDto> dataSetParamDtoList = new ArrayList<>();
dataSetParamList.forEach(dataSetParam -> {
DataSetParamDto dataSetParamDto = new DataSetParamDto();
GaeaBeanUtils.copyAndFormatter(dataSetParam, dataSetParamDto);
dataSetParamDtoList.add(dataSetParamDto);
});
dto.setDataSetParamDtoList(dataSetParamDtoList);
//数据转换
List<DataSetTransform> dataSetTransformList = dataSetTransformService.list(
new QueryWrapper<DataSetTransform>()
.lambda()
.eq(DataSetTransform::getSetCode, setCode)
.orderByAsc(DataSetTransform::getOrderNum)
);
List<DataSetTransformDto> 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<DataSetParamDto> dataSetParamDtoList = dto.getDataSetParamDtoList();
List<DataSetTransformDto> 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<DataSetParamDto> dataSetParamDtoList = dto.getDataSetParamDtoList();
List<DataSetTransformDto> 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<DataSetParam>()
.lambda()
.eq(DataSetParam::getSetCode, setCode)
);
//3.删除数据转换
dataSetTransformService.delete(
new QueryWrapper<DataSetTransform>()
.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<JSONObject> data = dataSourceService.execute(dataSourceDto);
//5.数据转换
List<JSONObject> 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<String, Object> 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<JSONObject> data = dataSourceService.execute(dataSourceDto);
//5.数据转换
List<JSONObject> transform = dataSetTransformService.transform(dto.getDataSetTransformDtoList(), data);
originalDataDto.setData(transform);
return originalDataDto;
}
/**
*
*
* @return
*/
@Override
public List<DataSet> queryAllDataSet() {
LambdaQueryWrapper<DataSet> 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<DataSetParamDto> dataSetParamDtoList,String setCode){
dataSetParamService.delete(
new QueryWrapper<DataSetParam>()
.lambda()
.eq(DataSetParam::getSetCode, setCode)
);
if (null == dataSetParamDtoList || dataSetParamDtoList.size() <= 0) {
return;
}
List<DataSetParam> 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<DataSetTransformDto> dataSetTransformDtoList,String setCode){
dataSetTransformService.delete(
new QueryWrapper<DataSetTransform>()
.lambda()
.eq(DataSetTransform::getSetCode, setCode)
);
if (null == dataSetTransformDtoList || dataSetTransformDtoList.size() <= 0) {
return;
}
List<DataSetTransform> 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);
}
}

@ -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,springBeanspring
*/
@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<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
// 注册http和https请求
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory).build();
//使用Httpclient连接池的方式配置(推荐)同时支持nettyokHttp以及其他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<Header> 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<Map.Entry<String, Integer>> 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<Header> getDefaultHeaders() {
List<Header> 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<HttpMessageConverter<?>> 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));
}
}

@ -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 {
/**
* javaymlymljava
*/
/**
*
*/
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<String,Integer> keepAliveTargetHost;
/**
* ,, s
*/
private int keepAliveTime = 60;
}

@ -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<DataSourceParam, DataSource, DataSourceDto> {
@Autowired
private DataSourceService dataSourceService;
@Override
public GaeaBaseService<DataSourceParam, DataSource> 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));
}
}

@ -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; mysqloracesqlserverelasticsearch接口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<String, Object> contextData;
}

@ -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; mysqloracesqlserverelasticsearch接口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;
}

@ -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; mysqloracesqlserverelasticsearch接口javaBean数据源类型字典中item-extend动态生成表单 */
@Query(QueryEnum.EQ)
private String sourceType;
}

@ -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<DataSource> {
}

@ -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; mysqloracesqlserverelasticsearch接口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;
}

@ -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);
}

@ -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 {
}

@ -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();
}

@ -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);
}

@ -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();
}

@ -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<String, Class<?>> getTypeMap() throws SQLException {
checkStatus();
return connection.getTypeMap();
}
@Override
public void setTypeMap(Map<String, Class<?>> 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> T unwrap(Class<T> 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");
}
}
}

@ -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";
}

@ -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;
}

@ -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;
}
}

@ -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() {
}
}

@ -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> T unwrap(Class<T> 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) {
}
}

@ -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<IPooledConnection> 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<IPooledConnection> 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<IPooledConnection> 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<IPooledConnection> 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
* <p>
* 使 {@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");
}
}

@ -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());
}
}

@ -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);
}
}

@ -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() {
}
}

@ -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<String, String> 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<String, String> 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);
}
}

@ -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<Long, PooledDataSource> 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();
}
}

@ -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<DataSourceParam, DataSource> {
/**
*
* @return
*/
List<DataSource> queryAllDataSource();
/**
*
* @param connectionParam
* @return
*/
Boolean testConnection(ConnectionParam connectionParam);
/**
* sql
* @param dto
* @return
*/
List<JSONObject> execute(DataSourceDto dto);
/**
* sql,total
* @param dataSourceDto
* @param dto
* @return
*/
long total(DataSourceDto dataSourceDto, DataSetDto dto);
}

@ -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<DataSource> getMapper() {
return dataSourceMapper;
}
/**
*
* @return
*/
@Override
public List<DataSource> queryAllDataSource() {
LambdaQueryWrapper<DataSource> 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<JSONObject> 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<JSONObject> 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<JSONObject> executeElasticsearchSql(DataSourceDto dto) {
analysisHttpConfig(dto);
HttpHeaders headers = new HttpHeaders();
headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class));
HttpEntity<String> entity = new HttpEntity<>(dto.getDynSentence(), headers);
ResponseEntity<JSONObject> 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<JSONObject> 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<JSONObject> 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<String> columns = new ArrayList<>();
for (int i = 1; i <= columnCount; i++) {
String columnName = rs.getMetaData().getColumnLabel(i);
columns.add(columnName);
}
List<JSONObject> 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<JSONObject> executeHttp(DataSourceDto dto) {
analysisHttpConfig(dto);
HttpHeaders headers = new HttpHeaders();
headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class));
HttpEntity<String> entity = new HttpEntity<>(dto.getDynSentence(), headers);
ResponseEntity<JSONObject> 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<JSONObject> 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<String> entity = new HttpEntity<>(body, headers);
ResponseEntity<Object> 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<String> entity = new HttpEntity<>(body, headers);
ResponseEntity<Object> 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);
}
/**
* esapi
*
* @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);
}
}
Loading…
Cancel
Save