This commit is contained in:
Jane
2023-12-22 10:59:10 +08:00
parent 751c43e199
commit d1ede2d4aa
2774 changed files with 291509 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>data-market-service-parent</artifactId>
<groupId>com.platform</groupId>
<version>0.4.x</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>0.4.x</version>
<artifactId>data-market-service</artifactId>
<dependencies>
<!--web 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!--配置中心客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-mybatis</artifactId>
<version>0.4.x</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-redis</artifactId>
<version>0.4.x</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-security</artifactId>
<version>0.4.x</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-database</artifactId>
<version>0.4.x</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-log</artifactId>
<version>0.4.x</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>data-market-service-api</artifactId>
<version>0.4.x</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-rabbitmq</artifactId>
<version>0.4.x</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>data-metadata-service-api</artifactId>
<version>0.4.x</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,15 @@
package cn.datax.service.data.market;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients(basePackages = {"cn.datax.service.system.api.feign"})
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class DataxMarketApplication {
public static void main(String[] args) {
SpringApplication.run(DataxMarketApplication.class);
}
}

View File

@@ -0,0 +1,78 @@
package cn.datax.service.data.market.config;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationAdvisor;
import com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor;
import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.YmlDynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceCreatorAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidDynamicDataSourceConfiguration;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Role;
import javax.sql.DataSource;
import java.util.Map;
/**
* 动态数据源核心自动配置类
* @author AllDataDC
* @date 2023/03/17
*/
@Slf4j
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@Import(value = {DruidDynamicDataSourceConfiguration.class, DynamicDataSourceCreatorAutoConfiguration.class})
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class DynamicDSConfiguration {
private final DynamicDataSourceProperties properties;
//读取多数据源配置注入到spring容器中
@Bean
@ConditionalOnMissingBean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
return new YmlDynamicDataSourceProvider(datasourceMap);
}
//注册自己的动态多数据源DataSource
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setProvider(dynamicDataSourceProvider);
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
//AOP切面对DS注解过的方法进行增强达到切换数据源的目的
@Role(value = BeanDefinition.ROLE_INFRASTRUCTURE)
@Bean
@ConditionalOnMissingBean
public DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {
DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor(properties.isAllowedPublicOnly(), dsProcessor);
DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);
advisor.setOrder(properties.getOrder());
return advisor;
}
}

View File

@@ -0,0 +1,32 @@
package cn.datax.service.data.market.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Slf4j
@Configuration
public class RabbitConfig {
@Bean
public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
// 消息是否成功发送到Exchange
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
log.info("消息成功发送到Exchange");
} else {
log.info("消息发送到Exchange失败, {}, cause: {}", correlationData, cause);
}
});
// 触发setReturnCallback回调必须设置mandatory=true, 否则Exchange没有找到Queue就会丢弃掉消息, 而不会触发回调
rabbitTemplate.setMandatory(true);
// 消息是否从Exchange路由到Queue, 注意: 这是一个失败回调, 只有消息从Exchange路由到Queue失败才会回调这个方法
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
log.info("消息从Exchange路由到Queue失败: exchange: {}, route: {}, replyCode: {}, replyText: {}, message: {}", exchange, routingKey, replyCode, replyText, message);
});
return rabbitTemplate;
}
}

View File

@@ -0,0 +1,32 @@
package cn.datax.service.data.market.config;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
@RequiredArgsConstructor
public class StartedUpRunner implements ApplicationRunner {
private final ConfigurableApplicationContext context;
private final Environment environment;
@Override
public void run(ApplicationArguments args) {
if (context.isActive()) {
String banner = "-----------------------------------------\n" +
"服务启动成功,时间:" + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()) + "\n" +
"服务名称:" + environment.getProperty("spring.application.name") + "\n" +
"端口号:" + environment.getProperty("server.port") + "\n" +
"-----------------------------------------";
System.out.println(banner);
}
}
}

View File

@@ -0,0 +1,117 @@
package cn.datax.service.data.market.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.*;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
@Configuration
@ConditionalOnProperty(prefix = "swagger", name = "enable", havingValue = "true")
@EnableConfigurationProperties(SwaggerProperties.class)
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
public class SwaggerConfig {
@Autowired
private SwaggerProperties swaggerProperties;
/**
* 创建API应用
* apiInfo() 增加API相关信息
* 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现
* 本例采用指定扫描的包路径来定义指定要建立API的目录。
*
* @return
*/
@Bean
public Docket createRestApi(){
//版本类型是swagger2
return new Docket(DocumentationType.SWAGGER_2)
//通过调用自定义方法apiInfo获得文档的主要信息
.apiInfo(apiInfo())
//设置全局参数
.globalOperationParameters(globalParamBuilder())
//设置全局响应参数
.globalResponseMessage(RequestMethod.GET,responseBuilder())
.globalResponseMessage(RequestMethod.POST,responseBuilder())
.globalResponseMessage(RequestMethod.PUT,responseBuilder())
.globalResponseMessage(RequestMethod.DELETE,responseBuilder())
.select()
//扫描该包下面的API注解
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
.paths(PathSelectors.any())
.build()
//设置安全认证
;
}
/**
* 创建该API的基本信息这些基本信息会展现在文档页面中
* 访问地址http://项目实际地址/swagger-ui.html
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
.version(swaggerProperties.getVersion())
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
.build();
}
/**
* 安全认证参数
* @return
*/
private List<ApiKey> security() {
List<ApiKey> apiKeys = new ArrayList<>();
apiKeys.add(new ApiKey("Authorization", "Authorization", "header"));
return apiKeys;
}
/**
* 构建全局参数列表
* @return
*/
private List<Parameter> globalParamBuilder(){
List<Parameter> pars = new ArrayList<>();
pars.add(parameterBuilder("Authorization","令牌","string","header",false).build());
return pars;
}
/**
* 创建参数
* @return
*/
private ParameterBuilder parameterBuilder(String name, String desc, String type, String parameterType, boolean required) {
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar.name(name).description(desc).modelRef(new ModelRef(type)).parameterType(parameterType).required(required).build();
return tokenPar;
}
/**
* 创建全局响应值
* @return
*/
private List<ResponseMessage> responseBuilder() {
List<ResponseMessage> responseMessageList = new ArrayList<>();
responseMessageList.add(new ResponseMessageBuilder().code(200).message("响应成功").build());
responseMessageList.add(new ResponseMessageBuilder().code(500).message("服务器内部错误").build());
return responseMessageList;
}
}

View File

@@ -0,0 +1,101 @@
package cn.datax.service.data.market.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(ignoreUnknownFields = false, prefix = "swagger")
public class SwaggerProperties {
private Boolean enable;
private String title;
private String description;
private String version;
private String termsOfServiceUrl;
private String basePackage;
private Contact contact;
public Boolean getEnable() {
return enable;
}
public void setEnable(Boolean enable) {
this.enable = enable;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getTermsOfServiceUrl() {
return termsOfServiceUrl;
}
public void setTermsOfServiceUrl(String termsOfServiceUrl) {
this.termsOfServiceUrl = termsOfServiceUrl;
}
public String getBasePackage() {
return basePackage;
}
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public static class Contact {
private String name;
private String url;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
}

View File

@@ -0,0 +1,17 @@
package cn.datax.service.data.market.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity(debug = false)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().permitAll().and().logout().permitAll();
}
}

View File

@@ -0,0 +1,144 @@
package cn.datax.service.data.market.controller;
import cn.datax.common.base.BaseController;
import cn.datax.common.core.JsonPage;
import cn.datax.common.core.R;
import cn.datax.common.validate.ValidationGroups;
import cn.datax.service.data.market.api.dto.ApiMaskDto;
import cn.datax.service.data.market.api.entity.ApiMaskEntity;
import cn.datax.service.data.market.api.query.ApiMaskQuery;
import cn.datax.service.data.market.api.vo.ApiMaskVo;
import cn.datax.service.data.market.mapstruct.ApiMaskMapper;
import cn.datax.service.data.market.service.ApiMaskService;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 数据API脱敏信息表 前端控制器
* </p>
*
* @author AllDataDC
* @date 2022-11-14
*/
@Api(tags = {"数据API脱敏信息表"})
@RestController
@RequestMapping("/apiMasks")
public class ApiMaskController extends BaseController {
@Autowired
private ApiMaskService apiMaskService;
@Autowired
private ApiMaskMapper apiMaskMapper;
/**
* 通过ID查询信息
*
* @param id
* @return
*/
@ApiOperation(value = "获取详细信息", notes = "根据url的id来获取详细信息")
@ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "String", paramType = "path")
@GetMapping("/{id}")
public R getApiMaskById(@PathVariable String id) {
ApiMaskEntity apiMaskEntity = apiMaskService.getApiMaskById(id);
return R.ok().setData(apiMaskMapper.toVO(apiMaskEntity));
}
/**
* 通过ID查询信息
*
* @param id
* @return
*/
@ApiOperation(value = "获取详细信息", notes = "根据url的id来获取详细信息")
@ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "String", paramType = "path")
@GetMapping("/api/{id}")
public R getApiMaskByApiId(@PathVariable String id) {
ApiMaskEntity apiMaskEntity = apiMaskService.getApiMaskByApiId(id);
return R.ok().setData(apiMaskMapper.toVO(apiMaskEntity));
}
/**
* 分页查询信息
*
* @param apiMaskQuery
* @return
*/
@ApiOperation(value = "分页查询", notes = "")
@ApiImplicitParams({
@ApiImplicitParam(name = "apiMaskQuery", value = "查询实体apiMaskQuery", required = true, dataTypeClass = ApiMaskQuery.class)
})
@GetMapping("/page")
public R getApiMaskPage(ApiMaskQuery apiMaskQuery) {
QueryWrapper<ApiMaskEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(apiMaskQuery.getMaskName()), "mask_name", apiMaskQuery.getMaskName());
IPage<ApiMaskEntity> page = apiMaskService.page(new Page<>(apiMaskQuery.getPageNum(), apiMaskQuery.getPageSize()), queryWrapper);
List<ApiMaskVo> collect = page.getRecords().stream().map(apiMaskMapper::toVO).collect(Collectors.toList());
JsonPage<ApiMaskVo> jsonPage = new JsonPage<>(page.getCurrent(), page.getSize(), page.getTotal(), collect);
return R.ok().setData(jsonPage);
}
/**
* 添加
* @param apiMask
* @return
*/
@ApiOperation(value = "添加信息", notes = "根据apiMask对象添加信息")
@ApiImplicitParam(name = "apiMask", value = "详细实体apiMask", required = true, dataType = "ApiMaskDto")
@PostMapping()
public R saveApiMask(@RequestBody @Validated({ValidationGroups.Insert.class}) ApiMaskDto apiMask) {
apiMaskService.saveApiMask(apiMask);
return R.ok();
}
/**
* 修改
* @param apiMask
* @return
*/
@ApiOperation(value = "修改信息", notes = "根据url的id来指定修改对象并根据传过来的信息来修改详细信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "String", paramType = "path"),
@ApiImplicitParam(name = "apiMask", value = "详细实体apiMask", required = true, dataType = "ApiMaskDto")
})
@PutMapping("/{id}")
public R updateApiMask(@PathVariable String id, @RequestBody @Validated({ValidationGroups.Update.class}) ApiMaskDto apiMask) {
apiMaskService.updateApiMask(apiMask);
return R.ok();
}
/**
* 删除
* @param id
* @return
*/
@ApiOperation(value = "删除", notes = "根据url的id来指定删除对象")
@ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "String", paramType = "path")
@DeleteMapping("/{id}")
public R deleteApiMaskById(@PathVariable String id) {
apiMaskService.deleteApiMaskById(id);
return R.ok();
}
@ApiOperation(value = "批量删除", notes = "根据url的ids来批量删除对象")
@ApiImplicitParam(name = "ids", value = "ID集合", required = true, dataType = "List", paramType = "path")
@DeleteMapping("/batch/{ids}")
public R deleteApiMaskBatch(@PathVariable List<String> ids) {
apiMaskService.deleteApiMaskBatch(ids);
return R.ok();
}
}

View File

@@ -0,0 +1,235 @@
package cn.datax.service.data.market.controller;
import cn.datax.common.base.BaseController;
import cn.datax.common.core.JsonPage;
import cn.datax.common.core.R;
import cn.datax.common.security.annotation.DataInner;
import cn.datax.common.validate.ValidationGroups;
import cn.datax.service.data.market.api.dto.DataApiDto;
import cn.datax.service.data.market.api.dto.SqlParseDto;
import cn.datax.service.data.market.api.entity.DataApiEntity;
import cn.datax.service.data.market.api.query.DataApiQuery;
import cn.datax.service.data.market.api.vo.DataApiVo;
import cn.datax.service.data.market.api.vo.SqlParseVo;
import cn.datax.service.data.market.mapstruct.DataApiMapper;
import cn.datax.service.data.market.service.DataApiService;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 数据API信息表 前端控制器
* </p>
*
* @author AllDataDC
* @date 2022-11-31
*/
@Api(tags = {"数据API信息表"})
@RestController
@RequestMapping("/dataApis")
public class DataApiController extends BaseController {
@Autowired
private DataApiService dataApiService;
@Autowired
private DataApiMapper dataApiMapper;
/**
* 通过ID查询信息
*
* @param sourceId
* @return
*/
@DataInner
@GetMapping("/source/{sourceId}")
public DataApiEntity getBySourceId(@PathVariable String sourceId) {
return dataApiService.getBySourceId(sourceId);
}
/**
* 通过ID查询信息
*
* @param id
* @return
*/
@ApiOperation(value = "获取详细信息", notes = "根据url的id来获取详细信息")
@ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "String", paramType = "path")
@GetMapping("/{id}")
public R getDataApiById(@PathVariable String id) {
DataApiEntity dataApiEntity = dataApiService.getDataApiById(id);
return R.ok().setData(dataApiMapper.toVO(dataApiEntity));
}
@ApiOperation(value = "获取列表", notes = "")
@GetMapping("/list")
public R getDataApiList() {
QueryWrapper<DataApiEntity> queryWrapper = new QueryWrapper<>();
List<DataApiEntity> list = dataApiService.list(queryWrapper);
List<DataApiVo> collect = list.stream().map(dataApiMapper::toVO).collect(Collectors.toList());
return R.ok().setData(collect);
}
/**
* 分页查询信息
*
* @param dataApiQuery
* @return
*/
@ApiOperation(value = "分页查询", notes = "")
@ApiImplicitParams({
@ApiImplicitParam(name = "dataApiQuery", value = "查询实体dataApiQuery", required = true, dataTypeClass = DataApiQuery.class)
})
@GetMapping("/page")
public R getDataApiPage(DataApiQuery dataApiQuery) {
QueryWrapper<DataApiEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(dataApiQuery.getApiName()), "api_name", dataApiQuery.getApiName());
IPage<DataApiEntity> page = dataApiService.page(new Page<>(dataApiQuery.getPageNum(), dataApiQuery.getPageSize()), queryWrapper);
List<DataApiVo> collect = page.getRecords().stream().map(dataApiMapper::toVO).collect(Collectors.toList());
JsonPage<DataApiVo> jsonPage = new JsonPage<>(page.getCurrent(), page.getSize(), page.getTotal(), collect);
return R.ok().setData(jsonPage);
}
/**
* 添加
*
* @param dataApi
* @return
*/
@ApiOperation(value = "添加信息", notes = "根据dataApi对象添加信息")
@ApiImplicitParam(name = "dataApi", value = "详细实体dataApi", required = true, dataType = "DataApiDto")
@PostMapping()
public R saveDataApi(@RequestBody @Validated({ValidationGroups.Insert.class}) DataApiDto dataApi) {
dataApiService.saveDataApi(dataApi);
return R.ok();
}
/**
* 修改
*
* @param dataApi
* @return
*/
@ApiOperation(value = "修改信息", notes = "根据url的id来指定修改对象并根据传过来的信息来修改详细信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "String", paramType = "path"),
@ApiImplicitParam(name = "dataApi", value = "详细实体dataApi", required = true, dataType = "DataApiDto")
})
@PutMapping("/{id}")
public R updateDataApi(@PathVariable String id, @RequestBody @Validated({ValidationGroups.Update.class}) DataApiDto dataApi) {
dataApiService.updateDataApi(dataApi);
return R.ok();
}
/**
* 删除
*
* @param id
* @return
*/
@ApiOperation(value = "删除", notes = "根据url的id来指定删除对象")
@ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "String", paramType = "path")
@DeleteMapping("/{id}")
public R deleteDataApiById(@PathVariable String id) {
dataApiService.deleteDataApiById(id);
return R.ok();
}
@ApiOperation(value = "批量删除", notes = "根据url的ids来批量删除对象")
@ApiImplicitParam(name = "ids", value = "ID集合", required = true, dataType = "List", paramType = "path")
@DeleteMapping("/batch/{ids}")
public R deleteDataApiBatch(@PathVariable List<String> ids) {
dataApiService.deleteDataApiBatch(ids);
return R.ok();
}
/**
* SQL解析
*
* @param sqlParseDto
* @return
*/
@ApiOperation(value = "SQL解析")
@ApiImplicitParam(name = "sqlParseDto", value = "SQL解析实体sqlParseDto", required = true, dataType = "SqlParseDto")
@PostMapping("/sql/parse")
public R sqlParse(@RequestBody @Validated SqlParseDto sqlParseDto) {
SqlParseVo sqlParseVo = dataApiService.sqlParse(sqlParseDto);
return R.ok().setData(sqlParseVo);
}
/**
* 拷贝接口
*
* @param id
* @return
*/
@PostMapping("/{id}/copy")
public R copyDataApi(@PathVariable String id) {
dataApiService.copyDataApi(id);
return R.ok();
}
/**
* 发布接口
*
* @param id
* @return
*/
@PostMapping(value = "/{id}/release")
public R releaseDataApi(@PathVariable String id) {
dataApiService.releaseDataApi(id);
return R.ok();
}
/**
* 注销接口
*
* @param id
* @return
*/
@PostMapping(value = "/{id}/cancel")
public R cancelDataApi(@PathVariable String id) {
dataApiService.cancelDataApi(id);
return R.ok();
}
@ApiOperation(value = "接口文档", notes = "根据url的id来指定生成接口文档对象")
@ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "String", paramType = "path")
@PostMapping("/word/{id}")
public R wordDataApi(@PathVariable String id, HttpServletResponse response) throws Exception {
// 清空response
response.reset();
// 设置response的Header
response.setContentType("application/octet-stream;charset=utf-8");
// 设置content-disposition响应头控制浏览器以下载的形式打开文件
response.addHeader("Content-Disposition", "attachment;filename=" + new String("接口文档.docx".getBytes()));
return R.ok();
}
@GetMapping("/detail/{id}")
public R getDataApiDetailById(@PathVariable String id) {
Map<String, Object> map = dataApiService.getDataApiDetailById(id);
return R.ok().setData(map);
}
}

View File

@@ -0,0 +1,51 @@
package cn.datax.service.data.market.controller;
import cn.datax.common.base.BaseController;
import cn.datax.common.core.DataConstant;
import cn.datax.common.security.annotation.DataInner;
import cn.datax.service.data.market.api.entity.ApiMaskEntity;
import cn.datax.service.data.market.api.entity.DataApiEntity;
import cn.datax.service.data.market.service.ApiMaskService;
import cn.datax.service.data.market.service.DataApiService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/inner")
public class InnerController extends BaseController {
@Autowired
private DataApiService dataApiService;
@Autowired
private ApiMaskService apiMaskService;
@DataInner
@GetMapping("/apis/{id}")
public DataApiEntity getDataApiById(@PathVariable("id") String id) {
DataApiEntity dataApiEntity = dataApiService.getDataApiById(id);
return dataApiEntity;
}
@DataInner
@GetMapping("/apis/release/list")
public List<DataApiEntity> getReleaseDataApiList() {
QueryWrapper<DataApiEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("status", DataConstant.ApiState.RELEASE.getKey());
List<DataApiEntity> dataApiEntityList = dataApiService.list(queryWrapper);
return dataApiEntityList;
}
@DataInner
@GetMapping("/apiMasks/api/{id}")
public ApiMaskEntity getApiMaskByApiId(@PathVariable("id") String id) {
ApiMaskEntity apiMaskEntity = apiMaskService.getApiMaskByApiId(id);
return apiMaskEntity;
}
}

View File

@@ -0,0 +1,29 @@
package cn.datax.service.data.market.dao;
import cn.datax.common.base.BaseDao;
import cn.datax.service.data.market.api.entity.ApiMaskEntity;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.io.Serializable;
/**
* <p>
* 数据API脱敏信息表 Mapper 接口
* </p>
*
* @author AllDataDC
* @date 2022-11-14
*/
@Mapper
public interface ApiMaskDao extends BaseDao<ApiMaskEntity> {
@Override
ApiMaskEntity selectById(Serializable id);
@Override
<E extends IPage<ApiMaskEntity>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<ApiMaskEntity> queryWrapper);
}

View File

@@ -0,0 +1,33 @@
package cn.datax.service.data.market.dao;
import cn.datax.common.base.BaseDao;
import cn.datax.service.data.market.api.entity.DataApiEntity;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.io.Serializable;
import java.util.List;
/**
* <p>
* 数据API信息表 Mapper 接口
* </p>
*
* @author AllDataDC
* @date 2022-11-31
*/
@Mapper
public interface DataApiDao extends BaseDao<DataApiEntity> {
@Override
DataApiEntity selectById(Serializable id);
@Override
List<DataApiEntity> selectList(@Param(Constants.WRAPPER) Wrapper<DataApiEntity> queryWrapper);
@Override
<E extends IPage<DataApiEntity>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<DataApiEntity> queryWrapper);
}

View File

@@ -0,0 +1,20 @@
package cn.datax.service.data.market.mapstruct;
import cn.datax.common.mapstruct.EntityMapper;
import cn.datax.service.data.market.api.dto.ApiMaskDto;
import cn.datax.service.data.market.api.entity.ApiMaskEntity;
import cn.datax.service.data.market.api.vo.ApiMaskVo;
import org.mapstruct.Mapper;
/**
* <p>
* 数据API脱敏信息表 Mapper 实体映射
* </p>
*
* @author AllDataDC
* @date 2022-11-14
*/
@Mapper(componentModel = "spring")
public interface ApiMaskMapper extends EntityMapper<ApiMaskDto, ApiMaskEntity, ApiMaskVo> {
}

View File

@@ -0,0 +1,20 @@
package cn.datax.service.data.market.mapstruct;
import cn.datax.common.mapstruct.EntityMapper;
import cn.datax.service.data.market.api.dto.DataApiDto;
import cn.datax.service.data.market.api.entity.DataApiEntity;
import cn.datax.service.data.market.api.vo.DataApiVo;
import org.mapstruct.Mapper;
/**
* <p>
* 数据API信息表 Mapper 实体映射
* </p>
*
* @author AllDataDC
* @date 2022-11-31
*/
@Mapper(componentModel = "spring")
public interface DataApiMapper extends EntityMapper<DataApiDto, DataApiEntity, DataApiVo> {
}

View File

@@ -0,0 +1,30 @@
package cn.datax.service.data.market.service;
import cn.datax.common.base.BaseService;
import cn.datax.service.data.market.api.dto.ApiMaskDto;
import cn.datax.service.data.market.api.entity.ApiMaskEntity;
import java.util.List;
/**
* <p>
* 数据API脱敏信息表 服务类
* </p>
*
* @author AllDataDC
* @date 2022-11-14
*/
public interface ApiMaskService extends BaseService<ApiMaskEntity> {
void saveApiMask(ApiMaskDto dataApiMask);
void updateApiMask(ApiMaskDto dataApiMask);
ApiMaskEntity getApiMaskById(String id);
ApiMaskEntity getApiMaskByApiId(String apiId);
void deleteApiMaskById(String id);
void deleteApiMaskBatch(List<String> ids);
}

View File

@@ -0,0 +1,43 @@
package cn.datax.service.data.market.service;
import cn.datax.service.data.market.api.dto.SqlParseDto;
import cn.datax.service.data.market.api.entity.DataApiEntity;
import cn.datax.service.data.market.api.dto.DataApiDto;
import cn.datax.common.base.BaseService;
import cn.datax.service.data.market.api.vo.SqlParseVo;
import java.util.List;
import java.util.Map;
/**
* <p>
* 数据API信息表 服务类
* </p>
*
* @author AllDataDC
* @date 2022-11-31
*/
public interface DataApiService extends BaseService<DataApiEntity> {
void saveDataApi(DataApiDto dataApi);
void updateDataApi(DataApiDto dataApi);
DataApiEntity getDataApiById(String id);
void deleteDataApiById(String id);
void deleteDataApiBatch(List<String> ids);
SqlParseVo sqlParse(SqlParseDto sqlParseDto);
void copyDataApi(String id);
void releaseDataApi(String id);
void cancelDataApi(String id);
Map<String, Object> getDataApiDetailById(String id);
DataApiEntity getBySourceId(String sourceId);
}

View File

@@ -0,0 +1,85 @@
package cn.datax.service.data.market.service.impl;
import cn.datax.common.base.BaseServiceImpl;
import cn.datax.common.core.RedisConstant;
import cn.datax.common.exception.DataException;
import cn.datax.service.data.market.api.dto.ApiMaskDto;
import cn.datax.service.data.market.api.entity.ApiMaskEntity;
import cn.datax.service.data.market.dao.ApiMaskDao;
import cn.datax.service.data.market.mapstruct.ApiMaskMapper;
import cn.datax.service.data.market.service.ApiMaskService;
import cn.datax.service.system.api.entity.DeptEntity;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* <p>
* 数据API脱敏信息表 服务实现类
* </p>
*
* @author AllDataDC
* @date 2022-11-14
*/
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class ApiMaskServiceImpl extends BaseServiceImpl<ApiMaskDao, ApiMaskEntity> implements ApiMaskService {
@Autowired
private ApiMaskDao apiMaskDao;
@Autowired
private ApiMaskMapper apiMaskMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void saveApiMask(ApiMaskDto apiMaskDto) {
ApiMaskEntity apiMask = apiMaskMapper.toEntity(apiMaskDto);
// 校验api唯一
int n = apiMaskDao.selectCount(Wrappers.<ApiMaskEntity>lambdaQuery().eq(ApiMaskEntity::getApiId, apiMask.getApiId()));
if(n > 0){
throw new DataException("该api已进行过脱敏配置");
}
apiMaskDao.insert(apiMask);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateApiMask(ApiMaskDto apiMaskDto) {
ApiMaskEntity apiMask = apiMaskMapper.toEntity(apiMaskDto);
apiMaskDao.updateById(apiMask);
}
@Override
public ApiMaskEntity getApiMaskById(String id) {
ApiMaskEntity apiMaskEntity = super.getById(id);
return apiMaskEntity;
}
@Override
public ApiMaskEntity getApiMaskByApiId(String apiId) {
ApiMaskEntity apiMaskEntity = apiMaskDao.selectOne(new QueryWrapper<ApiMaskEntity>().eq("api_id", apiId));
return apiMaskEntity;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteApiMaskById(String id) {
apiMaskDao.deleteById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteApiMaskBatch(List<String> ids) {
apiMaskDao.deleteBatchIds(ids);
}
}

View File

@@ -0,0 +1,461 @@
package cn.datax.service.data.market.service.impl;
import cn.datax.common.base.BaseServiceImpl;
import cn.datax.common.core.DataConstant;
import cn.datax.common.core.RedisConstant;
import cn.datax.common.exception.DataException;
import cn.datax.common.rabbitmq.config.RabbitMqConstant;
import cn.datax.common.redis.service.RedisService;
import cn.datax.common.utils.MD5Util;
import cn.datax.common.utils.SecurityUtil;
import cn.datax.common.utils.ThrowableUtil;
import cn.datax.service.data.market.api.dto.DataApiDto;
import cn.datax.service.data.market.api.dto.ReqParam;
import cn.datax.service.data.market.api.dto.ResParam;
import cn.datax.service.data.market.api.dto.SqlParseDto;
import cn.datax.service.data.market.api.entity.ApiMaskEntity;
import cn.datax.service.data.market.api.entity.DataApiEntity;
import cn.datax.service.data.market.api.enums.ConfigType;
import cn.datax.service.data.market.api.vo.ApiHeader;
import cn.datax.service.data.market.api.vo.SqlParseVo;
import cn.datax.service.data.market.dao.ApiMaskDao;
import cn.datax.service.data.market.dao.DataApiDao;
import cn.datax.service.data.market.mapstruct.DataApiMapper;
import cn.datax.service.data.market.service.DataApiService;
import cn.datax.service.data.market.utils.SqlBuilderUtil;
import cn.datax.service.data.metadata.api.entity.MetadataAuthorizeEntity;
import cn.datax.service.data.metadata.api.entity.MetadataColumnEntity;
import cn.datax.service.data.metadata.api.entity.MetadataSourceEntity;
import cn.datax.service.data.metadata.api.entity.MetadataTableEntity;
import cn.datax.service.data.metadata.api.enums.DataLevel;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.JdbcNamedParameter;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.parser.SimpleNode;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitorAdapter;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import net.sf.jsqlparser.statement.select.SelectItemVisitorAdapter;
import net.sf.jsqlparser.statement.select.SelectVisitorAdapter;
import net.sf.jsqlparser.util.SelectUtils;
import net.sf.jsqlparser.util.TablesNamesFinder;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import net.sf.jsqlparser.util.deparser.SelectDeParser;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* <p>
* 数据API信息表 服务实现类
* </p>
*
* @author AllDataDC
* @date 2022-11-31
*/
@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class DataApiServiceImpl extends BaseServiceImpl<DataApiDao, DataApiEntity> implements DataApiService {
@Autowired
private DataApiDao dataApiDao;
@Autowired
private ApiMaskDao apiMaskDao;
@Autowired
private DataApiMapper dataApiMapper;
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private RedisService redisService;
@Override
@Transactional(rollbackFor = Exception.class)
public void saveDataApi(DataApiDto dataApiDto) {
DataApiEntity dataApi = shareCode(dataApiDto);
dataApiDao.insert(dataApi);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateDataApi(DataApiDto dataApiDto) {
DataApiEntity dataApi = shareCode(dataApiDto);
dataApiDao.updateById(dataApi);
}
private DataApiEntity shareCode(DataApiDto dataApiDto) {
DataApiEntity dataApi = dataApiMapper.toEntity(dataApiDto);
String configType = dataApi.getExecuteConfig().getConfigType();
if (ConfigType.FORM.getKey().equals(configType)) {
try {
dataApi.getExecuteConfig().setSqlText(sqlJdbcNamedParameterBuild(dataApi));
} catch (JSQLParserException e) {
log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
throw new DataException("SQL语法有问题解析出错");
}
} else if (ConfigType.SCRIPT.getKey().equals(configType)) {
}
return dataApi;
}
@Override
public DataApiEntity getDataApiById(String id) {
DataApiEntity dataApiEntity = super.getById(id);
return dataApiEntity;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteDataApiById(String id) {
//zrx 判断有无脱敏依赖
ApiMaskEntity apiMaskEntity = apiMaskDao.selectOne(new QueryWrapper<ApiMaskEntity>().eq("api_id", id).last("limit 1"));
if (apiMaskEntity != null) {
throw new RuntimeException("存在与之关联的数据脱敏服务,不允许删除!");
}
dataApiDao.deleteById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteDataApiBatch(List<String> ids) {
//zrx check
for (String id : ids) {
deleteDataApiById(id);
}
//dataApiDao.deleteBatchIds(ids);
}
@Override
public SqlParseVo sqlParse(SqlParseDto sqlParseDto) {
String sourceId = sqlParseDto.getSourceId();
String sql = sqlParseDto.getSqlText();
sql = sql.replace(SqlBuilderUtil.getInstance().MARK_KEY_START, "");
sql = sql.replace(SqlBuilderUtil.getInstance().MARK_KEY_END, "");
Statement stmt;
try {
stmt = CCJSqlParserUtil.parse(sql);
} catch (JSQLParserException e) {
log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
throw new DataException("SQL语法有问题解析出错");
}
// 维护元数据缓存数据
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
List<String> tables = tablesNamesFinder.getTableList(stmt);
// 查询字段
final List<Map<String, String>> cols = new ArrayList<>();
// 查询参数
final List<String> vars = new ArrayList<>();
if (tables.size() == 1) {
// 单表解析
singleSqlParse(stmt, cols, vars, tables.get(0));
} else if (tables.size() > 1) {
// 多表解析
multipleSqlParse(stmt, cols, vars);
}
SqlParseVo sqlParseVo = new SqlParseVo();
List<ReqParam> reqParams = vars.stream().map(s -> {
ReqParam reqParam = new ReqParam();
reqParam.setParamName(s);
reqParam.setNullable(DataConstant.TrueOrFalse.FALSE.getKey());
return reqParam;
}).collect(Collectors.toList());
sqlParseVo.setReqParams(reqParams);
List<ResParam> resParams = new ArrayList<>();
List<MetadataSourceEntity> sourceEntityList = (List<MetadataSourceEntity>) redisService.get(RedisConstant.METADATA_SOURCE_KEY);
MetadataSourceEntity sourceEntity = sourceEntityList.stream().filter(s -> sourceId.equals(s.getId())).findFirst().orElse(null);
boolean admin = SecurityUtil.isAdmin();
if (sourceEntity != null) {
List<MetadataTableEntity> tableEntityList = (List<MetadataTableEntity>) redisService.hget(RedisConstant.METADATA_TABLE_KEY, sourceEntity.getId());
Map<String, List<Map<String, String>>> map = cols.stream().collect(Collectors.groupingBy(e -> e.get("tableName").toString()));
for (Map.Entry<String, List<Map<String, String>>> entry : map.entrySet()) {
String entryKey = entry.getKey().toLowerCase();
List<Map<String, String>> entryValue = entry.getValue();
MetadataTableEntity tableEntity = tableEntityList.stream().filter(t -> entryKey.equals(t.getTableName().toLowerCase())).findFirst().orElse(null);
if (tableEntity != null) {
List<MetadataColumnEntity> columnEntityList = (List<MetadataColumnEntity>) redisService.hget(RedisConstant.METADATA_COLUMN_KEY, tableEntity.getId());
entryValue.stream().forEach(m -> {
String columnName = m.get("columnName").toLowerCase();
String columnAliasName = m.get("columnAliasName");
Stream<MetadataColumnEntity> stream = columnEntityList.stream().filter(c -> columnName.equals(c.getColumnName().toLowerCase()));
if (!admin) {
Set<String> set = new HashSet<>();
List<String> roleIds = SecurityUtil.getUserRoleIds();
roleIds.stream().forEach(role -> {
List<MetadataAuthorizeEntity> list = (List<MetadataAuthorizeEntity>) redisService.hget(RedisConstant.METADATA_AUTHORIZE_KEY, role);
set.addAll(Optional.ofNullable(list).orElseGet(ArrayList::new).stream()
.filter(s -> Objects.equals(DataLevel.COLUMN.getKey(), s.getObjectType()))
.map(s -> s.getObjectId()).collect(Collectors.toSet()));
});
stream = stream.filter(s -> set.contains(s.getId()));
}
MetadataColumnEntity columnEntity = stream.findFirst().orElse(null);
if (columnEntity != null) {
ResParam resParam = new ResParam();
resParam.setFieldName(columnEntity.getColumnName());
resParam.setFieldComment(StrUtil.isNotBlank(columnEntity.getColumnComment()) ? columnEntity.getColumnComment() : "");
resParam.setDataType(StrUtil.isNotBlank(columnEntity.getDataType()) ? columnEntity.getDataType() : "");
resParam.setFieldAliasName(StrUtil.isNotBlank(columnAliasName) ? columnAliasName : "");
resParams.add(resParam);
}
});
}
}
}
sqlParseVo.setResParams(resParams);
return sqlParseVo;
}
private void singleSqlParse(Statement stmt, List<Map<String, String>> cols, List<String> vars, String tableName) {
stmt.accept(new StatementVisitorAdapter() {
@Override
public void visit(Select select) {
select.getSelectBody().accept(new SelectVisitorAdapter() {
@Override
public void visit(PlainSelect plainSelect) {
plainSelect.getSelectItems().stream().forEach(selectItem -> {
selectItem.accept(new SelectItemVisitorAdapter() {
@Override
public void visit(SelectExpressionItem item) {
Map<String, String> map = new HashMap<>();
String columnName;
SimpleNode node = item.getExpression().getASTNode();
Object value = node.jjtGetValue();
if (value instanceof Column) {
Column column = (Column) value;
columnName = column.getColumnName();
if (item.getAlias() != null) {
map.put("columnAliasName", item.getAlias().getName());
}
} else if (value instanceof Function) {
columnName = value.toString();
} else {
// 增加对select 'aaa' from table; 的支持
columnName = String.valueOf(value);
columnName = columnName.replace("'", "");
columnName = columnName.replace("\"", "");
columnName = columnName.replace("`", "");
}
columnName = columnName.replace("'", "");
columnName = columnName.replace("\"", "");
columnName = columnName.replace("`", "");
map.put("tableName", tableName);
map.put("columnName", columnName);
cols.add(map);
}
});
});
plainSelect.getWhere().accept(new ExpressionVisitorAdapter() {
@Override
public void visit(JdbcNamedParameter jdbcNamedParameter) {
vars.add(jdbcNamedParameter.getName());
}
});
}
});
}
});
}
private void multipleSqlParse(Statement stmt, List<Map<String, String>> cols, List<String> vars) {
stmt.accept(new StatementVisitorAdapter() {
@Override
public void visit(Select select) {
select.getSelectBody().accept(new SelectVisitorAdapter() {
@Override
public void visit(PlainSelect plainSelect) {
// 存储表名
Map<String, String> map = new HashMap<>();
Table table = (Table) plainSelect.getFromItem();
if (table.getAlias() != null) {
map.put(table.getName(), table.getAlias().getName());
}
for (Join join : plainSelect.getJoins()) {
Table table1 = (Table) join.getRightItem();
if (table1.getAlias() != null) {
map.put(table1.getName(), table1.getAlias().getName());
}
}
plainSelect.getSelectItems().stream().forEach(selectItem -> {
selectItem.accept(new SelectItemVisitorAdapter() {
@Override
public void visit(SelectExpressionItem item) {
Map<String, String> m = new HashMap<>();
String tableName = "", columnName;
SimpleNode node = item.getExpression().getASTNode();
Object value = node.jjtGetValue();
if (value instanceof Column) {
Column column = (Column) value;
Table table = column.getTable();
if (table != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
if (table.getName().equals(entry.getValue())) {
tableName = entry.getKey();
break;
}
}
}
columnName = column.getColumnName();
if (item.getAlias() != null) {
m.put("columnAliasName", item.getAlias().getName());
}
} else if (value instanceof Function) {
columnName = value.toString();
} else {
// 增加对select 'aaa' from table; 的支持
columnName = String.valueOf(value);
columnName = columnName.replace("'", "");
columnName = columnName.replace("\"", "");
columnName = columnName.replace("`", "");
}
columnName = columnName.replace("'", "");
columnName = columnName.replace("\"", "");
columnName = columnName.replace("`", "");
m.put("tableName", tableName);
m.put("columnName", columnName);
cols.add(m);
}
});
});
plainSelect.getWhere().accept(new ExpressionVisitorAdapter() {
@Override
public void visit(JdbcNamedParameter jdbcNamedParameter) {
vars.add(jdbcNamedParameter.getName());
}
});
}
});
}
});
}
private String sqlJdbcNamedParameterBuild(DataApiEntity dataApi) throws JSQLParserException {
Table table = new Table(dataApi.getExecuteConfig().getTableName());
String[] resParams = dataApi.getResParams().stream().map(s -> s.getFieldName()).toArray(String[]::new);
Select select = SelectUtils.buildSelectFromTableAndExpressions(table, resParams);
return SqlBuilderUtil.getInstance().buildHql(select.toString(), dataApi.getReqParams());
}
private String sqlJdbcNamedParameterParse(String sqlText) throws JSQLParserException {
final StringBuilder buffer = new StringBuilder();
ExpressionDeParser expressionDeParser = new ExpressionDeParser() {
@Override
public void visit(JdbcNamedParameter jdbcNamedParameter) {
this.getBuffer().append("?");
}
};
SelectDeParser deparser = new SelectDeParser(expressionDeParser, buffer);
expressionDeParser.setSelectVisitor(deparser);
expressionDeParser.setBuffer(buffer);
Statement stmt = CCJSqlParserUtil.parse(sqlText);
stmt.accept(new StatementVisitorAdapter() {
@Override
public void visit(Select select) {
select.getSelectBody().accept(deparser);
}
});
return buffer.toString();
}
@Override
public void copyDataApi(String id) {
DataApiEntity dataApiEntity = Optional.ofNullable(super.getById(id)).orElseThrow(() -> new DataException("获取失败"));
DataApiEntity copy = new DataApiEntity();
copy.setApiName(dataApiEntity.getApiName() + "_副本" + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN));
copy.setApiVersion(dataApiEntity.getApiVersion());
copy.setApiUrl(dataApiEntity.getApiUrl() + "/copy" + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN));
copy.setReqMethod(dataApiEntity.getReqMethod());
copy.setResType(dataApiEntity.getResType());
copy.setDeny(dataApiEntity.getDeny());
copy.setRateLimit(dataApiEntity.getRateLimit());
copy.setExecuteConfig(dataApiEntity.getExecuteConfig());
copy.setReqParams(dataApiEntity.getReqParams());
copy.setResParams(dataApiEntity.getResParams());
copy.setStatus(DataConstant.ApiState.WAIT.getKey());
dataApiDao.insert(copy);
}
@Override
public void releaseDataApi(String id) {
Map<String, Object> map = new HashMap<>(2);
map.put("id", id);
map.put("type", "1");
rabbitTemplate.convertAndSend(RabbitMqConstant.FANOUT_EXCHANGE_API, "", map);
LambdaUpdateWrapper<DataApiEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(DataApiEntity::getStatus, DataConstant.ApiState.RELEASE.getKey());
updateWrapper.eq(DataApiEntity::getId, id);
dataApiDao.update(null, updateWrapper);
}
@Override
public void cancelDataApi(String id) {
Map<String, Object> map = new HashMap<>(2);
map.put("id", id);
map.put("type", "2");
rabbitTemplate.convertAndSend(RabbitMqConstant.FANOUT_EXCHANGE_API, "", map);
LambdaUpdateWrapper<DataApiEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(DataApiEntity::getStatus, DataConstant.ApiState.CANCEL.getKey());
updateWrapper.eq(DataApiEntity::getId, id);
dataApiDao.update(null, updateWrapper);
}
@Override
public Map<String, Object> getDataApiDetailById(String id) {
DataApiEntity dataApiEntity = super.getById(id);
ApiHeader apiHeader = new ApiHeader();
MD5Util mt = null;
try {
mt = MD5Util.getInstance();
apiHeader.setApiKey(mt.encode(id));
apiHeader.setSecretKey(mt.encode(SecurityUtil.getUserId()));
} catch (Exception e) {
e.printStackTrace();
}
Map<String, Object> map = new HashMap<>(2);
map.put("data", dataApiMapper.toVO(dataApiEntity));
map.put("header", apiHeader);
return map;
}
@Override
public DataApiEntity getBySourceId(String sourceId) {
return dataApiDao.selectOne(new QueryWrapper<DataApiEntity>().eq("source_id", sourceId).last("limit 1"));
}
}

View File

@@ -0,0 +1,147 @@
package cn.datax.service.data.market.utils;
import cn.datax.common.exception.DataException;
import org.springframework.util.Assert;
import java.util.*;
/**
* 带参数sql处理工具类
*/
public class NamedParameterUtil {
// public static void main(String[] args) {
// String sql = "select * from user where 1 = 1 ${ and id = :id } ${and name = :name}";
// int start = sql.indexOf("${");
// int end = sql.indexOf("}", start);
// String key = sql.substring(start + 2, end);
// System.out.println(key);
// Map<String, Object> params = new HashMap<>();
// params.put("name", "yuwei");
// params.put("id", "123");
// params.put("age", 12);
// ParsedSql parsedSql = NamedParameterUtil.parseSqlStatement(key);
// System.out.println(parsedSql);
// String actualSql = NamedParameterUtil.substituteNamedParams(parsedSql, params);
// Map<String, Object> acceptedFilters = NamedParameterUtil.buildValueArray(parsedSql, params);
// System.out.println(actualSql);
// System.out.println(acceptedFilters);
// SqlBuilderUtil.SqlFilterResult sqlFilterResult = SqlBuilderUtil.getInstance().applyFilters(sql, params);
// System.out.println(sqlFilterResult.getSql());
// Object[] array = new Object[] {};
// array = sqlFilterResult.getAcceptedFilters().values().toArray();
// Arrays.stream(array).forEach(s -> System.out.println(s));
// }
private NamedParameterUtil() {}
/**
* 定义特殊字符(增加最后的自定义的'}'
*/
private static final char[] PARAMETER_SEPARATORS =
new char[] {'"', '\'', ':', '&', ',', ';', '(', ')', '|', '=', '+', '-', '*', '%', '/', '\\', '<', '>', '^', '}'};
/**
* 对带参数sql的统计式封装便于后续肢解拼装
* @param originalSql
* @return
*/
public static ParsedSql parseSqlStatement(String originalSql) {
Assert.notNull(originalSql, "SQL must not be null");
ParsedSql parsedSql = new ParsedSql(originalSql);
Set<String> namedParameters = new HashSet();
char[] sqlchars = originalSql.toCharArray();
int namedParamCount = 0;
int unNamedParamCount = 0;
int totalParamCount = 0;
int i = 0;
while (i < sqlchars.length) {
char statement = sqlchars[i];
if (statement == ':') {
int j = i + 1;
while (j < sqlchars.length && !isSeparatorsChar(sqlchars[j])) {
j++;
}
if (j - i > 1) {
String paramName = originalSql.substring(i + 1, j);
if (!namedParameters.contains(paramName)) {
namedParameters.add(paramName);
namedParamCount++;
}
parsedSql.addParamNames(paramName, i, j);
totalParamCount++;
}
i = j - 1;
} else if (statement == '?') {
unNamedParamCount++;
totalParamCount++;
}
i++;
}
parsedSql.setNamedParamCount(namedParamCount);
parsedSql.setUnnamedParamCount(unNamedParamCount);
parsedSql.setTotalParamCount(totalParamCount);
return parsedSql;
}
/**
* 获得不带参数的sql即替换参数为
* @param parsedSql
* @param params
* @return
*/
public static String substituteNamedParams(ParsedSql parsedSql, Map<String, Object> params){
String original = parsedSql.getOriginalSql();
StringBuffer actual = new StringBuffer("");
int lastIndex = 0;
List<String> paramNames = parsedSql.getParamNames();
for (int i = 0; i < paramNames.size(); i++) {
int[] indexs = parsedSql.getParamIndexs(i);
int startIndex = indexs[0];
int endIndex = indexs[1];
String paramName = paramNames.get(i);
actual.append(original.substring(lastIndex, startIndex));
if (params != null && params.containsKey(paramName)) {
actual.append("?");
} else{
actual.append("?");
}
lastIndex = endIndex;
}
actual.append(original.subSequence(lastIndex, original.length()));
return actual.toString();
}
/**
* 获得sql所需参数K,V
* @param parsedSql
* @param params
* @return
*/
public static LinkedHashMap<String, Object> buildValueArray(ParsedSql parsedSql, Map<String, Object> params){
List<String> paramNames = parsedSql.getParamNames();
LinkedHashMap<String, Object> acceptedFilters = new LinkedHashMap<>(parsedSql.getTotalParamCount());
if (parsedSql.getNamedParamCount() > 0 && parsedSql.getUnnamedParamCount() > 0) {
throw new DataException("parameter方式与方式不能混合");
}
for (int i = 0; i < paramNames.size(); i++) {
String keyName = paramNames.get(i);
if (params.containsKey(keyName)) {
acceptedFilters.put(keyName, params.get(keyName));
}
}
return acceptedFilters;
}
private static boolean isSeparatorsChar(char statement){
if (Character.isWhitespace(statement)) {
return true;
}
for (int i = 0; i < PARAMETER_SEPARATORS.length; i++) {
if (statement == PARAMETER_SEPARATORS[i]) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,82 @@
package cn.datax.service.data.market.utils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 此类封装NamedParameterSql
*/
public class ParsedSql implements Serializable {
private static final long serialVersionUID=1L;
private String originalSql;
//参数名
private List<String> paramNames = new ArrayList<>();
//参数在sql中对应的位置
private List<int[]> paramIndexs = new ArrayList<>();
//统计参数个数(不包含重复)
private int namedParamCount;
//统计sql中的个数
private int unnamedParamCount;
private int totalParamCount;
public ParsedSql(String originalSql){
this.originalSql = originalSql;
}
public List<String> getParamNames() {
return paramNames;
}
public void addParamNames(String paramName,int startIndex,int endIndex) {
paramNames.add(paramName);
paramIndexs.add(new int[]{startIndex,endIndex});
}
public int[] getParamIndexs(int position) {
return paramIndexs.get(position);
}
public String getOriginalSql() {
return originalSql;
}
public int getNamedParamCount() {
return namedParamCount;
}
public void setNamedParamCount(int namedParamCount) {
this.namedParamCount = namedParamCount;
}
public int getUnnamedParamCount() {
return unnamedParamCount;
}
public void setUnnamedParamCount(int unnamedParamCount) {
this.unnamedParamCount = unnamedParamCount;
}
public int getTotalParamCount() {
return totalParamCount;
}
public void setTotalParamCount(int totalParamCount) {
this.totalParamCount = totalParamCount;
}
@Override
public String toString() {
return "ParsedSql{" +
"originalSql='" + originalSql + '\'' +
", paramNames=" + paramNames +
", paramIndexs=" + paramIndexs +
", namedParamCount=" + namedParamCount +
", unnamedParamCount=" + unnamedParamCount +
", totalParamCount=" + totalParamCount +
'}';
}
}

View File

@@ -0,0 +1,295 @@
package cn.datax.service.data.market.utils;
import cn.datax.service.data.market.api.dto.ReqParam;
import cn.datax.service.data.market.api.enums.WhereType;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 用于动态构造sql语句
* ${ segment... } 为一个条件代码块
*
* String sql = "select * from user where 1=1
* ${ and username = :username }
* ${ and password = :password }
* ${ and age = :age }"
*
* Map filters = new HashMap();
* filters.put("username", "yuwei");
* filters.put("age", "12");
* filters.put("id", "123");
*
* SqlFilterResult result = SqlBuilderUtil.applyFilters(sql, filters);
*
* result.getSql()结果
* select * from user where 1=1 and username=:username and age=:age
*
* result.getAcceptedFilters()结果
* {username=yuwei}
* {age=12}
*/
@Slf4j
public class SqlBuilderUtil {
private SqlBuilderUtil() {}
private static volatile SqlBuilderUtil instance;
public static SqlBuilderUtil getInstance() {
if(instance == null) {
synchronized (SqlBuilderUtil.class) {
if(instance == null) {
instance = new SqlBuilderUtil();
}
}
}
return instance;
}
/**
* 空格
*/
private final String SPACE = " ";
/**
* 冒号占位符
*/
private final String COLON = ":";
/**
* 问号占位符
*/
private final String MARK = "?";
/**
* where关键字
*/
private final String WHERE_SQL = "WHERE";
/**
* AND连接符
*/
private final String WHERE_AND = "AND";
/**
* where 1=1条件
*/
private final String WHERE_INIT = WHERE_SQL + " 1 = 1";
/**
* 左括号
*/
private final String LEFT_BRACKET = "(";
/**
* 右括号
*/
private final String RIGHT_BRACKET = ")";
/**
* 百分号%
*/
private final String PERCENT_SIGN = "%";
/**
* 单引号 '
*/
private final String SINGLE_QUOTE = "'";
/**
* 条件代码块标记开始
*/
public final String MARK_KEY_START = "${";
/**
* 条件代码块标记结束
*/
public final String MARK_KEY_END = "}";
/**
* 拼接命名参数sql
* @param sql
* @param params
* @return
*/
public String buildHql(String sql, List<ReqParam> params){
Assert.notNull(sql, "SQL must not be null");
return buildHql(new StringBuffer(sql), params);
}
private String buildHql(StringBuffer sql, List<ReqParam> params){
if(CollUtil.isEmpty(params)){
return sql.toString();
}
sql.append(SPACE).append(WHERE_INIT);
for (int i = 0; i < params.size(); i++) {
ReqParam reqParam = params.get(i);
sql.append(SPACE).append(MARK_KEY_START).append(WHERE_AND).append(SPACE).append(reqParam.getParamName());
if (WhereType.LIKE.getType() == reqParam.getWhereType()) {
// LIKE '%' :username '%' ,:username 两边一定要有空格,如果没有空格,是查询不到数据的
sql.append(SPACE).append(WhereType.getWhereType(reqParam.getWhereType()).getKey())
.append(SPACE).append(SINGLE_QUOTE).append(PERCENT_SIGN).append(SINGLE_QUOTE).append(SPACE)
.append(COLON).append(reqParam.getParamName())
.append(SPACE).append(SINGLE_QUOTE).append(PERCENT_SIGN).append(SINGLE_QUOTE).append(MARK_KEY_END);
} else if(WhereType.LIKE_LEFT.getType() == reqParam.getWhereType()) {
sql.append(SPACE).append(WhereType.getWhereType(reqParam.getWhereType()).getKey())
.append(SPACE).append(SINGLE_QUOTE).append(PERCENT_SIGN).append(SINGLE_QUOTE).append(SPACE)
.append(COLON).append(reqParam.getParamName()).append(MARK_KEY_END);
} else if(WhereType.LIKE_RIGHT.getType() == reqParam.getWhereType()) {
sql.append(SPACE).append(WhereType.getWhereType(reqParam.getWhereType()).getKey())
.append(SPACE).append(COLON).append(reqParam.getParamName())
.append(SPACE).append(SINGLE_QUOTE).append(PERCENT_SIGN).append(SINGLE_QUOTE).append(MARK_KEY_END);
} else if(WhereType.NULL.getType() == reqParam.getWhereType() || WhereType.NOT_NULL.getType() == reqParam.getWhereType()){
// is null或is not null不需要参数值
sql.append(SPACE).append(WhereType.getWhereType(reqParam.getWhereType()).getKey()).append(MARK_KEY_END);
} else if(WhereType.IN.getType() == reqParam.getWhereType()){
// in (:ids)
sql.append(SPACE).append(WhereType.getWhereType(reqParam.getWhereType()).getKey())
.append(SPACE).append(LEFT_BRACKET)
.append(COLON).append(reqParam.getParamName())
.append(RIGHT_BRACKET).append(MARK_KEY_END);
} else {
sql.append(SPACE).append(WhereType.getWhereType(reqParam.getWhereType()).getKey())
.append(SPACE).append(COLON).append(reqParam.getParamName()).append(MARK_KEY_END);
}
}
return sql.toString();
}
/**
* 根据入参动态构造sql语句
* @param sql
* @param filters
* @return
*/
public SqlFilterResult applyFilters(String sql, Map<String, Object> filters){
Assert.notNull(sql, "SQL must not be null");
return applyFilters(new StringBuffer(sql), filters);
}
private SqlFilterResult applyFilters(StringBuffer sql, Map<String, Object> filters){
LinkedHashMap<String, Object> acceptedFilters = new LinkedHashMap<>();
for (int i = 0, end = 0, start = sql.indexOf(MARK_KEY_START); ((start = sql.indexOf(MARK_KEY_START, end)) >= 0); i++) {
end = sql.indexOf(MARK_KEY_END, start);
// 封装该条件代码块中的NamedParameterSql
ParsedSql parsedSql = getSegmentParsedSql(sql, start, end);
if (CollUtil.isEmpty(parsedSql.getParamNames())){
throw new IllegalArgumentException("Not key found in segment=" + sql.substring(start, end + MARK_KEY_END.length()));
}
// 判断输入参数filters中是否存在查询参数
if (isAcceptedKeys(filters, parsedSql.getParamNames())) {
// 动态构造可执行的sql语句去掉条件代码块两边的${ }标记符
if (log.isDebugEnabled()) {
log.debug("The filter namedParameters=" + parsedSql.getParamNames() + " is accepted on segment=" + sql.substring(start, end + MARK_KEY_END.length()));
}
// 下面方法2选1可以获取条件代码块
// select id, name from user where 1 = 1 and id = :id
// String segment = sql.substring(start + MARK_KEY_START.length(), end);
String segment = parsedSql.getOriginalSql();
// 转换命名参数:为?
// select id, name from user where 1 = 1 and id = ?
// String segment = NamedParameterUtil.substituteNamedParams(parsedSql, filters);
// 获取传参中包含命名参数的数据
LinkedHashMap<String, Object> linkAcceptedFilters = NamedParameterUtil.buildValueArray(parsedSql, filters);
acceptedFilters.putAll(linkAcceptedFilters);
sql.replace(start, end + MARK_KEY_END.length(), segment);
end = start + segment.length();
} else {
// 抛弃该条件代码块
if (log.isDebugEnabled()) {
log.debug("The filter namedParameters=" + parsedSql.getParamNames() + " is removed from the query on segment=" + sql.substring(start, end + MARK_KEY_END.length()));
}
sql.replace(start, end + MARK_KEY_END.length(), "");
end = start;
}
}
return new SqlFilterResult(sql.toString(), acceptedFilters);
}
/**
* 验证入参,并过滤值为空的入参
*/
private boolean isAcceptedKeys(Map<String, Object> filters, List<String> keys) {
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
Object value = getProperty(filters, key);
if (!isValuePopulated(value, true)) {
return false;
}
}
return true;
}
/**
* 封装该条件代码块中的NamedParameterSql
*/
private ParsedSql getSegmentParsedSql(StringBuffer sql, int start, int end) {
String segment = sql.substring(start + MARK_KEY_START.length(), end);
ParsedSql parsedSql = NamedParameterUtil.parseSqlStatement(segment);
return parsedSql;
}
/**
* 获取参数值
* @param filters
* @param key
* @return
*/
private Object getProperty(Map<String, Object> filters, String key) {
if (MapUtil.isEmpty(filters))
return null;
return filters.get(key);
}
/**
* 验证参数值是否空
* @param value
* @param isRemoveEmpty
* @return
*/
private boolean isValuePopulated(Object value, boolean isRemoveEmpty) {
if (value == null) {
return false;
}
if (isRemoveEmpty) {
return ObjectUtil.isNotEmpty(value);
} else {
return true;
}
}
public class SqlFilterResult implements Serializable {
private static final long serialVersionUID=1L;
private String sql;
private Map<String, Object> acceptedFilters;
public SqlFilterResult(String sql, Map<String, Object> acceptedFilters) {
this.setSql(sql);
this.setAcceptedFilters(acceptedFilters);
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public Map<String, Object> getAcceptedFilters() {
return acceptedFilters;
}
public void setAcceptedFilters(Map<String, Object> acceptedFilters) {
this.acceptedFilters = acceptedFilters;
}
@Override
public String toString() {
return "SqlFilterResult{" +
"sql='" + sql + '\'' +
", acceptedFilters=" + acceptedFilters +
'}';
}
}
}

View File

@@ -0,0 +1,35 @@
package cn.datax.service.data.market.utils;
import cn.datax.service.data.market.api.dto.ApiLogDto;
public class ThreadUtil {
private ThreadUtil() {}
private static volatile ThreadUtil instance;
public static ThreadUtil getInstance() {
if(instance == null) {
synchronized (ThreadUtil.class) {
if(instance == null) {
instance = new ThreadUtil();
}
}
}
return instance;
}
private final static ThreadLocal<ApiLogDto> logHolder = new ThreadLocal<>();
public void set(ApiLogDto log){
logHolder.set(log);
}
public void remove(){
logHolder.remove();
}
public ApiLogDto get(){
return logHolder.get();
}
}

View File

@@ -0,0 +1,30 @@
server:
port: 8822
spring:
application:
name: service-data-market
profiles:
active: dev
cloud:
config:
label: master
name: ${spring.application.name}
profile: ${spring.profiles.active}
discovery:
enabled: true
service-id: config
# 注册中心配置
eureka:
instance:
lease-renewal-interval-in-seconds: 20
prefer-ip-address: true
ip-address: 192.168.1.169
client:
register-with-eureka: true
fetch-registry: true
instance-info-replication-interval-seconds: 30
registry-fetch-interval-seconds: 3
service-url:
defaultZone: http://192.168.1.169:8610/eureka

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<springProperty scope="context" name="springAppName" source="spring.application.name"/>
<property name="log.path" value="logs/service-data-market"/>
<property name="log.maxHistory" value="15"/>
<property name="log.totalSizeCap" value="500MB"/>
<property name="log.maxFileSize" value="10MB"/>
<property name="log.colorPattern"
value="%magenta(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %boldCyan(${springAppName:-}) %yellow(%thread) %green(%logger) %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level ${springAppName:-} %thread %logger %msg%n"/>
<!--输出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.colorPattern}</pattern>
</encoder>
</appender>
<!--输出到文件-->
<!-- RollingFileAppender滚动记录文件先将日志记录到指定文件当符合某个条件时将日志记录到其他文件 -->
<!-- 以下的大概意思是1.先按日期存日志日期变了将前一天的日志文件名重命名为XXX%日期%索引新的日志仍然是project_info.log -->
<!-- 2.如果日期没有发生变化但是当前日志的文件大小超过10MB时对当前日志进行分割 重命名-->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径和名称-->
<File>${log.path}/info/info.log</File>
<!--是否追加到文件末尾,默认为true-->
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名logs/project_info.2017-12-05.0.log -->
<!-- 注意SizeAndTimeBasedRollingPolicy中 i和d令牌都是强制性的必须存在要不会报错 -->
<fileNamePattern>${log.path}/info/info.%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天, ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天
如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd-->
<MaxHistory>${log.maxHistory}</MaxHistory>
<!-- 每个日志文件到2mb的时候开始切分最多保留30天但最大到500MB哪怕没到30天也要删除多余的日志 -->
<totalSizeCap>${log.totalSizeCap}</totalSizeCap>
<!-- maxFileSize:这是活动文件的大小默认值是10MB测试时可改成5KB看效果 -->
<maxFileSize>${log.maxFileSize}</maxFileSize>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.path}/error/error.log</File>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/error.%d.%i.log</fileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
<totalSizeCap>${log.totalSizeCap}</totalSizeCap>
<maxFileSize>${log.maxFileSize}</maxFileSize>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="debug">
<appender-ref ref="console"/>
</root>
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.datax.service.data.market.dao.ApiMaskDao">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.datax.service.data.market.api.entity.ApiMaskEntity">
<result column="id" property="id" />
<result column="status" property="status" />
<result column="create_by" property="createBy" />
<result column="create_time" property="createTime" />
<result column="create_dept" property="createDept" />
<result column="update_by" property="updateBy" />
<result column="update_time" property="updateTime" />
<result column="api_id" property="apiId" />
<result column="mask_name" property="maskName" />
<result column="remark" property="remark" />
</resultMap>
<resultMap id="ExtendResultMap" type="cn.datax.service.data.market.api.entity.ApiMaskEntity" extends="BaseResultMap">
<result column="config_json" property="rules" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id,
status,
create_by,
create_time,
create_dept,
update_by,
update_time,
api_id, mask_name, remark
</sql>
<sql id="Extend_Column_List">
id,
status,
create_by,
create_time,
create_dept,
update_by,
update_time,
api_id, mask_name, remark, config_json
</sql>
<select id="selectById" resultMap="ExtendResultMap">
SELECT
<include refid="Extend_Column_List"></include>
FROM market_api_mask
WHERE 1=1 AND id = #{id}
</select>
<select id="selectPage" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"></include>
FROM market_api_mask
${ew.customSqlSegment}
</select>
</mapper>

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.datax.service.data.market.dao.DataApiDao">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.datax.service.data.market.api.entity.DataApiEntity">
<result column="id" property="id" />
<result column="status" property="status" />
<result column="create_by" property="createBy" />
<result column="create_time" property="createTime" />
<result column="create_dept" property="createDept" />
<result column="update_by" property="updateBy" />
<result column="update_time" property="updateTime" />
<result column="api_name" property="apiName" />
<result column="api_version" property="apiVersion" />
<result column="api_url" property="apiUrl" />
<result column="remark" property="remark" />
<result column="req_method" property="reqMethod" />
<result column="res_type" property="resType" />
<result column="deny" property="deny" />
<result column="source_id" property="sourceId" />
</resultMap>
<resultMap id="ExtendResultMap" type="cn.datax.service.data.market.api.entity.DataApiEntity" extends="BaseResultMap">
<result column="limit_json" property="rateLimit" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
<result column="config_json" property="executeConfig" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
<result column="req_json" property="reqParams" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
<result column="res_json" property="resParams" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id,
status,
create_by,
create_time,
create_dept,
update_by,
update_time,
api_name, api_version, api_url, remark, req_method, res_type, deny, source_id
</sql>
<sql id="Extend_Column_List">
id,
status,
create_by,
create_time,
create_dept,
update_by,
update_time,
api_name, api_version, api_url, remark, req_method, res_type, deny, source_id, limit_json, config_json, req_json, res_json
</sql>
<select id="selectById" resultMap="ExtendResultMap">
SELECT
<include refid="Extend_Column_List"/>
FROM market_api
WHERE 1=1 AND id = #{id}
</select>
<select id="selectList" resultMap="ExtendResultMap">
SELECT
<include refid="Extend_Column_List"/>
FROM market_api
${ew.customSqlSegment}
</select>
<select id="selectPage" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM market_api
${ew.customSqlSegment}
</select>
</mapper>

View File

@@ -0,0 +1,25 @@
module.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,batch,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
# 开启过滤
filter=true
# 配置不打印的内容
exclude=select 1