Commit d564a649 by inrgihc

接入sentinel的流量控制

parent a90ceb6f
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
- 支持生成在线接口文档功能 - 支持生成在线接口文档功能
> 基于swagger-ui提供生成在线接口文档功能。 > 基于swagger-ui提供生成在线接口文档功能。
- 支持接口的流量控制功能
> 执行器基于sentinel支持接口的流量控制功能。
### 2、支持的数据库 ### 2、支持的数据库
- 甲骨文的Oracle - 甲骨文的Oracle
......
...@@ -31,7 +31,7 @@ cd $PROJECT_ROOT_DIR && sh docker-maven-clean.sh && cd - ...@@ -31,7 +31,7 @@ cd $PROJECT_ROOT_DIR && sh docker-maven-clean.sh && cd -
# login and push docker image # login and push docker image
docker login -u inrgihc docker login -u inrgihc
docker push inrgihc/sqlrest-manager:${SQLREST_VERSION} docker push registry.cn-hangzhou.aliyuncs.com/inrgihc/sqlrest-manager:${SQLREST_VERSION}
docker push inrgihc/sqlrest-executor:${SQLREST_VERSION} docker push registry.cn-hangzhou.aliyuncs.com/inrgihc/sqlrest-executor:${SQLREST_VERSION}
docker push inrgihc/sqlrest-gateway:${SQLREST_VERSION} docker push registry.cn-hangzhou.aliyuncs.com/inrgihc/sqlrest-gateway:${SQLREST_VERSION}
...@@ -19,7 +19,7 @@ services: ...@@ -19,7 +19,7 @@ services:
start_period: 30s start_period: 30s
manager: manager:
container_name: sqlrest_manager container_name: sqlrest_manager
image: inrgihc/sqlrest-manager:1.0.0 image: registry.cn-hangzhou.aliyuncs.com/inrgihc/sqlrest-manager:1.0.0
network_mode: host network_mode: host
environment: environment:
MYSQLDB_HOST: localhost MYSQLDB_HOST: localhost
...@@ -40,7 +40,7 @@ services: ...@@ -40,7 +40,7 @@ services:
condition: service_healthy condition: service_healthy
executor: executor:
container_name: sqlrest_executor container_name: sqlrest_executor
image: inrgihc/sqlrest-executor:1.0.0 image: registry.cn-hangzhou.aliyuncs.com/inrgihc/sqlrest-executor:1.0.0
network_mode: host network_mode: host
environment: environment:
MYSQLDB_HOST: localhost MYSQLDB_HOST: localhost
...@@ -61,7 +61,7 @@ services: ...@@ -61,7 +61,7 @@ services:
condition: service_healthy condition: service_healthy
gateway: gateway:
container_name: sqlrest_gateway container_name: sqlrest_gateway
image: inrgihc/sqlrest-gateway:1.0.0 image: registry.cn-hangzhou.aliyuncs.com/inrgihc/sqlrest-gateway:1.0.0
network_mode: host network_mode: host
environment: environment:
MYSQLDB_HOST: localhost MYSQLDB_HOST: localhost
......
FROM openjdk:8-jre-alpine FROM registry.cn-hangzhou.aliyuncs.com/inrgihc/openjdk:8-jre-alpine
ENV TZ=Asia/Shanghai ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
...@@ -11,7 +11,7 @@ USER root ...@@ -11,7 +11,7 @@ USER root
WORKDIR /sqlrest-release WORKDIR /sqlrest-release
RUN chmod u+x /sqlrest-release/bin/startup.sh RUN chmod u+x /sqlrest-release/bin/sqlrestctl.sh
CMD ["/sqlrest-release/bin/startup.sh","executor"] CMD ["/sqlrest-release/bin/sqlrestctl.sh","executor"]
FROM openjdk:8-jre-alpine FROM registry.cn-hangzhou.aliyuncs.com/inrgihc/openjdk:8-jre-alpine
ENV TZ=Asia/Shanghai ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
...@@ -11,7 +11,7 @@ USER root ...@@ -11,7 +11,7 @@ USER root
WORKDIR /sqlrest-release WORKDIR /sqlrest-release
RUN chmod u+x /sqlrest-release/bin/startup.sh RUN chmod u+x /sqlrest-release/bin/sqlrestctl.sh
CMD ["/sqlrest-release/bin/startup.sh","gateway"] CMD ["/sqlrest-release/bin/sqlrestctl.sh","gateway"]
FROM openjdk:8-jre-alpine FROM registry.cn-hangzhou.aliyuncs.com/inrgihc/openjdk:8-jre-alpine
ENV TZ=Asia/Shanghai ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
...@@ -11,7 +11,7 @@ USER root ...@@ -11,7 +11,7 @@ USER root
WORKDIR /sqlrest-release WORKDIR /sqlrest-release
RUN chmod u+x /sqlrest-release/bin/startup.sh RUN chmod u+x /sqlrest-release/bin/sqlrestctl.sh
CMD ["/sqlrest-release/bin/startup.sh","manager"] CMD ["/sqlrest-release/bin/sqlrestctl.sh","manager"]
...@@ -5,5 +5,5 @@ docker run -it --rm \ ...@@ -5,5 +5,5 @@ docker run -it --rm \
-v ~/.m2:/opt/maven/localRepository \ -v ~/.m2:/opt/maven/localRepository \
-v "$PWD":/usr/src/mymaven \ -v "$PWD":/usr/src/mymaven \
-w /usr/src/mymaven \ -w /usr/src/mymaven \
inrgihc/maven-aliyun:3.6.3-jdk-8 mvn clean package registry.cn-hangzhou.aliyuncs.com/inrgihc/maven-aliyun:3.6.3-jdk-8 mvn clean package
...@@ -5,5 +5,5 @@ docker run -it --rm \ ...@@ -5,5 +5,5 @@ docker run -it --rm \
-v ~/.m2:/opt/maven/localRepository \ -v ~/.m2:/opt/maven/localRepository \
-v "$PWD":/usr/src/mymaven \ -v "$PWD":/usr/src/mymaven \
-w /usr/src/mymaven \ -w /usr/src/mymaven \
inrgihc/maven-aliyun:3.6.3-jdk-8 mvn clean registry.cn-hangzhou.aliyuncs.com/inrgihc/maven-aliyun:3.6.3-jdk-8 mvn clean
...@@ -52,7 +52,13 @@ ...@@ -52,7 +52,13 @@
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2023.0.1.0</version>
</dependency>
<dependency> <dependency>
<groupId>com.hazelcast</groupId> <groupId>com.hazelcast</groupId>
<artifactId>hazelcast-all</artifactId> <artifactId>hazelcast-all</artifactId>
......
...@@ -15,4 +15,10 @@ public abstract class Constants { ...@@ -15,4 +15,10 @@ public abstract class Constants {
public static final String CACHE_KEY_TOKEN_CLIENT = "token_client"; public static final String CACHE_KEY_TOKEN_CLIENT = "token_client";
public static final Long CLIENT_TOKEN_DURATION_SECONDS = 7200L; public static final Long CLIENT_TOKEN_DURATION_SECONDS = 7200L;
public static final int SC_TOO_MANY_REQUESTS = 429;
public static final String getResourceName(String method, String path) {
return String.format("/%s/%s[%s]", Constants.API_PATH_PREFIX, path, method);
}
} }
package com.gitee.sqlrest.common.dto; package com.gitee.sqlrest.common.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
...@@ -9,9 +11,15 @@ import lombok.NoArgsConstructor; ...@@ -9,9 +11,15 @@ import lombok.NoArgsConstructor;
@Builder @Builder
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@ApiModel("按照日期的统计")
public class DateCount { public class DateCount {
@ApiModelProperty("日期")
private String ofDate; private String ofDate;
@ApiModelProperty("总数")
private Long total; private Long total;
@ApiModelProperty("成功数")
private Long success; private Long success;
} }
...@@ -23,6 +23,8 @@ public enum ResponseErrorCode { ...@@ -23,6 +23,8 @@ public enum ResponseErrorCode {
ERROR_ACCESS_FORBIDDEN(403, "access forbidden"), ERROR_ACCESS_FORBIDDEN(403, "access forbidden"),
ERROR_TOKEN_EXPIRED(401, "token is expired"), ERROR_TOKEN_EXPIRED(401, "token is expired"),
ERROR_PATH_NOT_EXISTS(404, "path not exists"), ERROR_PATH_NOT_EXISTS(404, "path not exists"),
ERROR_TOO_MANY_REQUESTS(429, "too many requests"),
; ;
private int code; private int code;
......
package com.gitee.sqlrest.core.dto; package com.gitee.sqlrest.core.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.gitee.sqlrest.common.dto.ItemParam; import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import com.gitee.sqlrest.persistence.entity.ApiContextEntity; import com.gitee.sqlrest.persistence.entity.ApiContextEntity;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
...@@ -34,4 +34,13 @@ public class ApiAssignmentDetailResponse extends ApiAssignmentBaseResponse { ...@@ -34,4 +34,13 @@ public class ApiAssignmentDetailResponse extends ApiAssignmentBaseResponse {
@ApiModelProperty("SQL列表") @ApiModelProperty("SQL列表")
private List<ApiContextEntity> sqlList; private List<ApiContextEntity> sqlList;
@ApiModelProperty("是否开启流量控制")
private Boolean flowStatus;
@ApiModelProperty("阈值类型")
private Integer flowGrade;
@TableField("阈值大小")
private Integer flowCount;
} }
...@@ -52,4 +52,13 @@ public class ApiAssignmentSaveRequest { ...@@ -52,4 +52,13 @@ public class ApiAssignmentSaveRequest {
@ApiModelProperty("接口入参") @ApiModelProperty("接口入参")
private List<ItemParam> params; private List<ItemParam> params;
@ApiModelProperty("是否开启流量控制")
private Boolean flowStatus;
@ApiModelProperty("阈值类型")
private Integer flowGrade;
@ApiModelProperty("单机阈值")
private Integer flowCount;
} }
package com.gitee.sqlrest.core.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.sql.Timestamp;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
@ApiModel("流控规则详情")
public class FlowRuleDetailResponse {
@ApiModelProperty("ID编号")
private Long id;
@ApiModelProperty("标题")
private String name;
@ApiModelProperty("阈值类型")
private Integer flowGrade;
@ApiModelProperty("单机阈值")
private Integer flowCount;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createTime;
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp updateTime;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
@ApiModel("流控规则详情")
public class FlowRuleSaveRequest {
@ApiModelProperty("ID编号")
private Long id;
@ApiModelProperty("标题")
private String name;
@ApiModelProperty("阈值类型")
private Integer flowGrade;
@ApiModelProperty("单机阈值")
private Integer flowCount;
}
...@@ -9,9 +9,9 @@ import lombok.NoArgsConstructor; ...@@ -9,9 +9,9 @@ import lombok.NoArgsConstructor;
@Data @Data
@Builder @Builder
@ApiModel("列信息")
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@ApiModel("列信息")
public class MetadataColumnResponse { public class MetadataColumnResponse {
@ApiModelProperty("列名") @ApiModelProperty("列名")
......
package com.gitee.sqlrest.core.dto; package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
...@@ -13,6 +14,7 @@ import java.util.TreeSet; ...@@ -13,6 +14,7 @@ import java.util.TreeSet;
/** /**
* Swagger接口信息 * Swagger接口信息
*/ */
@ApiModel("Swagger的数据接口")
public class SwaggerEntity { public class SwaggerEntity {
private String swagger = "2.0"; private String swagger = "2.0";
......
...@@ -35,6 +35,8 @@ public class AuthenticationFilter implements Filter { ...@@ -35,6 +35,8 @@ public class AuthenticationFilter implements Filter {
@Resource @Resource
private ApiAssignmentDao apiAssignmentDao; private ApiAssignmentDao apiAssignmentDao;
@Resource @Resource
private FlowControlManger flowControlManger;
@Resource
private ClientTokenService clientTokenService; private ClientTokenService clientTokenService;
@Resource @Resource
private AccessRecordMapper accessRecordMapper; private AccessRecordMapper accessRecordMapper;
...@@ -62,6 +64,18 @@ public class AuthenticationFilter implements Filter { ...@@ -62,6 +64,18 @@ public class AuthenticationFilter implements Filter {
return; return;
} }
if (apiConfigEntity.getFlowStatus()) {
String resourceName = Constants.getResourceName(method.name(), path);
if (flowControlManger.checkFlowControl(resourceName, response)) {
doAuthenticationFilter(chain, request, response, apiConfigEntity);
}
} else {
doAuthenticationFilter(chain, request, response, apiConfigEntity);
}
}
private void doAuthenticationFilter(FilterChain chain, HttpServletRequest request, HttpServletResponse response,
ApiAssignmentEntity apiConfigEntity) throws IOException {
AccessRecordEntity accessRecordEntity = AccessRecordEntity.builder() AccessRecordEntity accessRecordEntity = AccessRecordEntity.builder()
.path(request.getRequestURI()) .path(request.getRequestURI())
.status(HttpStatus.OK.value()) .status(HttpStatus.OK.value())
...@@ -71,6 +85,9 @@ public class AuthenticationFilter implements Filter { ...@@ -71,6 +85,9 @@ public class AuthenticationFilter implements Filter {
.apiId(apiConfigEntity.getId()) .apiId(apiConfigEntity.getId())
.build(); .build();
String path = apiConfigEntity.getPath();
HttpMethodEnum method = apiConfigEntity.getMethod();
try { try {
if (!apiConfigEntity.getOpen()) { if (!apiConfigEntity.getOpen()) {
String tokenStr = TokenUtils.getRequestToken(request); String tokenStr = TokenUtils.getRequestToken(request);
......
package com.gitee.sqlrest.core.filter;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
public interface FlowControlManger {
boolean checkFlowControl(String resourceName, HttpServletResponse response) throws IOException;
}
...@@ -103,9 +103,9 @@ public class ApiAssignmentService { ...@@ -103,9 +103,9 @@ public class ApiAssignmentService {
public List<SqlParamParseResponse> parseSqlParams(String text) { public List<SqlParamParseResponse> parseSqlParams(String text) {
Configuration cfg = new Configuration(); Configuration cfg = new Configuration();
SqlTemplate template = cfg.getTemplate(text); SqlTemplate template = cfg.getTemplate(text);
List<SqlParamParseResponse> responses = new ArrayList<>(); return template.getParameterNames().entrySet().stream()
template.getParameterNames().forEach((k, v) -> responses.add(new SqlParamParseResponse(k, v))); .map(e -> new SqlParamParseResponse(e.getKey(), e.getValue()))
return responses; .collect(Collectors.toList());
} }
public Object debugExecute(ApiDebugExecuteRequest request) { public Object debugExecute(ApiDebugExecuteRequest request) {
...@@ -178,6 +178,9 @@ public class ApiAssignmentService { ...@@ -178,6 +178,9 @@ public class ApiAssignmentService {
assignmentEntity.setEngine(request.getEngine()); assignmentEntity.setEngine(request.getEngine());
assignmentEntity.setStatus(false); assignmentEntity.setStatus(false);
assignmentEntity.setContextList(contextList); assignmentEntity.setContextList(contextList);
assignmentEntity.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false));
assignmentEntity.setFlowGrade(request.getFlowGrade());
assignmentEntity.setFlowCount(request.getFlowCount());
apiAssignmentDao.insert(assignmentEntity); apiAssignmentDao.insert(assignmentEntity);
return assignmentEntity.getId(); return assignmentEntity.getId();
...@@ -215,6 +218,9 @@ public class ApiAssignmentService { ...@@ -215,6 +218,9 @@ public class ApiAssignmentService {
assignmentEntity.setStatus(false); assignmentEntity.setStatus(false);
assignmentEntity.setEngine(request.getEngine()); assignmentEntity.setEngine(request.getEngine());
assignmentEntity.setContextList(contextList); assignmentEntity.setContextList(contextList);
assignmentEntity.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false));
assignmentEntity.setFlowGrade(request.getFlowGrade());
assignmentEntity.setFlowCount(request.getFlowCount());
apiAssignmentDao.update(assignmentEntity); apiAssignmentDao.update(assignmentEntity);
} }
......
...@@ -9,11 +9,29 @@ ...@@ -9,11 +9,29 @@
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>sqlrest-dist</artifactId> <artifactId>sqlrest-dist</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version> <version>2.6</version>
<executions> <executions>
......
...@@ -13,7 +13,7 @@ GATEWAY_PORT=8091 ...@@ -13,7 +13,7 @@ GATEWAY_PORT=8091
# mysql的host地址 # mysql的host地址
MYSQLDB_HOST=127.0.0.1 MYSQLDB_HOST=192.168.31.57
# mysql的端口号 # mysql的端口号
MYSQLDB_PORT=3306 MYSQLDB_PORT=3306
......
...@@ -33,6 +33,11 @@ ...@@ -33,6 +33,11 @@
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
...@@ -11,8 +11,10 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; ...@@ -11,8 +11,10 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Slf4j @Slf4j
@EnableScheduling
@Configuration @Configuration
public class ExecutorServletConfig { public class ExecutorServletConfig {
...@@ -32,7 +34,7 @@ public class ExecutorServletConfig { ...@@ -32,7 +34,7 @@ public class ExecutorServletConfig {
registrationBean.setFilter(authenticationFilter); registrationBean.setFilter(authenticationFilter);
registrationBean.addUrlPatterns(URL_PATH_PATTERN); registrationBean.addUrlPatterns(URL_PATH_PATTERN);
registrationBean.setOrder(2); registrationBean.setOrder(2);
log.info("Register authFilter for {} UrlPatterns, and order is {}", URL_PATH_PATTERN); log.info("Register authFilter for {} UrlPatterns, and order is {}", URL_PATH_PATTERN, 2);
return registrationBean; return registrationBean;
} }
......
package com.gitee.sqlrest.executor.flowcontrol;
import cn.hutool.json.JSONUtil;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.dto.ResultEntity;
import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import com.gitee.sqlrest.common.exception.ResponseErrorCode;
import com.gitee.sqlrest.core.filter.FlowControlManger;
import com.gitee.sqlrest.persistence.dao.ApiAssignmentDao;
import com.gitee.sqlrest.persistence.entity.ApiAssignmentEntity;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class SentinelFlowControlManager implements FlowControlManger {
@Resource
private ApiAssignmentDao apiAssignmentDao;
/*每分钟执行一次*/
@EventListener(ApplicationReadyEvent.class)
@Scheduled(cron = "${cron.flow.expression:0 0/1 * * * ?}")
public void loadFlowRules() {
try {
doLoadFlowRules();
log.info("Success load flow rules");
} catch (Exception e) {
log.error("load flow rules failed:{}", e.getMessage(), e);
}
}
private void doLoadFlowRules() {
List<FlowRule> rules = new ArrayList<>();
for (ApiAssignmentEntity assignmentEntity : apiAssignmentDao.listFlowControlAll()) {
if (assignmentEntity.getFlowCount() <= 0) {
continue;
}
HttpMethodEnum method = assignmentEntity.getMethod();
String path = assignmentEntity.getPath();
String resourceName = Constants.getResourceName(method.name(), path);
FlowRule rule = new FlowRule(resourceName);
if (RuleConstant.FLOW_GRADE_THREAD == assignmentEntity.getFlowGrade()) {
rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
} else {
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
}
rule.setCount(assignmentEntity.getFlowCount());
rule.setId(assignmentEntity.getId());
rules.add(rule);
}
FlowRuleManager.loadRules(rules);
}
@Override
public boolean checkFlowControl(String resourceName, HttpServletResponse response) throws IOException {
Entry entry = null;
try {
entry = SphU.entry(resourceName, 0, EntryType.IN);
return true;
} catch (BlockException be) {
this.handleBlockException(resourceName, response);
return false;
} finally {
if (entry != null) {
entry.exit(1);
}
}
}
public void handleBlockException(String resourceName, HttpServletResponse response)
throws IOException {
response.setStatus(Constants.SC_TOO_MANY_REQUESTS);
ResultEntity result = ResultEntity.failed(ResponseErrorCode.ERROR_TOO_MANY_REQUESTS, resourceName);
response.getWriter().append(JSONUtil.toJsonStr(result));
}
}
...@@ -15,29 +15,34 @@ public class HttpApiServlet extends HttpServlet { ...@@ -15,29 +15,34 @@ public class HttpApiServlet extends HttpServlet {
public HttpApiServlet(ApiServletService apiServletService) { public HttpApiServlet(ApiServletService apiServletService) {
this.apiServletService = apiServletService; this.apiServletService = apiServletService;
} }
private void doHandle(HttpMethodEnum method, HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
apiServletService.process(method, request, response);
}
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
apiServletService.process(HttpMethodEnum.GET, req, resp); doHandle(HttpMethodEnum.GET, req, resp);
} }
@Override @Override
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
apiServletService.process(HttpMethodEnum.HEAD, req, resp); doHandle(HttpMethodEnum.HEAD, req, resp);
} }
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
apiServletService.process(HttpMethodEnum.POST, req, resp); doHandle(HttpMethodEnum.POST, req, resp);
} }
@Override @Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
apiServletService.process(HttpMethodEnum.PUT, req, resp); doHandle(HttpMethodEnum.PUT, req, resp);
} }
@Override @Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
apiServletService.process(HttpMethodEnum.DELETE, req, resp); doHandle(HttpMethodEnum.DELETE, req, resp);
} }
} }
...@@ -36,6 +36,10 @@ ...@@ -36,6 +36,10 @@
<p> <p>
基于swagger-ui提供生成在线接口文档功能。 基于swagger-ui提供生成在线接口文档功能。
</p> </p>
<li>支持接口的流量控制功能</li>
<p>
执行器基于sentinel支持接口的流量控制功能。
</p>
</ul> </ul>
</div> </div>
</el-card> </el-card>
......
...@@ -67,7 +67,8 @@ ...@@ -67,7 +67,8 @@
prop="name"> prop="name">
<el-input v-model="createParam.name" <el-input v-model="createParam.name"
auto-complete="off" auto-complete="off"
style="width:75%"></el-input> style="width:75%"
:disabled=isOnlyShowDetail></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
...@@ -78,7 +79,8 @@ ...@@ -78,7 +79,8 @@
<el-select placeholder="请选择数据源" <el-select placeholder="请选择数据源"
style="width:60%" style="width:60%"
v-model="createParam.dataSourceId" v-model="createParam.dataSourceId"
@change="loadTreeData"> @change="loadTreeData"
:disabled=isOnlyShowDetail>
<el-option v-for="(item,index) in connectionList" <el-option v-for="(item,index) in connectionList"
:key="index" :key="index"
:label="`[${item.id}]${item.name}`" :label="`[${item.id}]${item.name}`"
...@@ -95,7 +97,8 @@ ...@@ -95,7 +97,8 @@
:required=true :required=true
prop="group"> prop="group">
<el-select v-model="createParam.group" <el-select v-model="createParam.group"
placeholder="请选择"> placeholder="请选择"
:disabled=isOnlyShowDetail>
<el-option v-for="(item,index) in groupList" <el-option v-for="(item,index) in groupList"
:key="index" :key="index"
:label="`[${item.id}]${item.name}`" :label="`[${item.id}]${item.name}`"
...@@ -110,7 +113,7 @@ ...@@ -110,7 +113,7 @@
:required=true :required=true
prop="method"> prop="method">
<el-select v-model="createParam.method" <el-select v-model="createParam.method"
:disabled="$route.query.id>0"> :disabled=isOnlyShowDetail>
<el-option label="GET" <el-option label="GET"
value="GET"></el-option> value="GET"></el-option>
<el-option label="PUT" <el-option label="PUT"
...@@ -131,7 +134,7 @@ ...@@ -131,7 +134,7 @@
:required=true :required=true
prop="path"> prop="path">
<el-input v-model="createParam.path" <el-input v-model="createParam.path"
:disabled="$route.query.id>0"> :disabled=isOnlyShowDetail>
<template slot="prepend">{{gatewayApiPrefix}}</template> <template slot="prepend">{{gatewayApiPrefix}}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
...@@ -143,7 +146,8 @@ ...@@ -143,7 +146,8 @@
style="width:80%" style="width:80%"
prop="module"> prop="module">
<el-select v-model="createParam.module" <el-select v-model="createParam.module"
placeholder="请选择"> placeholder="请选择"
:disabled=isOnlyShowDetail>
<el-option v-for="(item,index) in moduleList" <el-option v-for="(item,index) in moduleList"
:key="index" :key="index"
:label="`[${item.id}]${item.name}`" :label="`[${item.id}]${item.name}`"
...@@ -173,7 +177,7 @@ ...@@ -173,7 +177,7 @@
:required=true :required=true
prop="contentType"> prop="contentType">
<el-select v-model="createParam.contentType" <el-select v-model="createParam.contentType"
:disabled="$route.query.id>0"> :disabled=isOnlyShowDetail>
<el-option v-for="(item,index) in contentTypes" <el-option v-for="(item,index) in contentTypes"
:key="index" :key="index"
:label="item" :label="item"
...@@ -257,13 +261,15 @@ ...@@ -257,13 +261,15 @@
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.name" <el-input v-model="scope.row.name"
type="string"> </el-input> type="string"
:disabled=isOnlyShowDetail> </el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="参数类型" <el-table-column label="参数类型"
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.type"> <el-select v-model="scope.row.type"
:disabled=isOnlyShowDetail>
<el-option label='整型' <el-option label='整型'
value='LONG'></el-option> value='LONG'></el-option>
<el-option label='浮点型' <el-option label='浮点型'
...@@ -280,7 +286,8 @@ ...@@ -280,7 +286,8 @@
<el-table-column label="为数组" <el-table-column label="为数组"
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.isArray"> <el-select v-model="scope.row.isArray"
:disabled=isOnlyShowDetail>
<el-option label='是' <el-option label='是'
:value=true></el-option> :value=true></el-option>
<el-option label='否' <el-option label='否'
...@@ -291,7 +298,8 @@ ...@@ -291,7 +298,8 @@
<el-table-column label="必填" <el-table-column label="必填"
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.required"> <el-select v-model="scope.row.required"
:disabled=isOnlyShowDetail>
<el-option label='是' <el-option label='是'
:value=true></el-option> :value=true></el-option>
<el-option label='否' <el-option label='否'
...@@ -303,14 +311,16 @@ ...@@ -303,14 +311,16 @@
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.defaultValue" <el-input v-model="scope.row.defaultValue"
type="string"></el-input> type="string"
:disabled=isOnlyShowDetail></el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="描述" <el-table-column label="描述"
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.remark" <el-input v-model="scope.row.remark"
type="string"></el-input> type="string"
:disabled=isOnlyShowDetail></el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" <el-table-column label="操作"
...@@ -339,6 +349,41 @@ ...@@ -339,6 +349,41 @@
</el-col> </el-col>
</el-row> </el-row>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="流量控制"
name="flowControl">
<el-row>
<el-col :span="24">
<el-form-item label="是否开启">
<el-switch v-model="createParam.flowStatus"
active-color="#13ce66"
:active-value="true"
:inactive-value="false"
active-text="开启"
inactive-text="关闭"
:disabled=isOnlyShowDetail>
</el-switch>
</el-form-item>
<div v-show="createParam.flowStatus">
<el-form-item label="阈值类型">
<el-radio-group size="small"
v-model="createParam.flowGrade"
:disabled=isOnlyShowDetail
border>
<el-radio :label="1">QPS</el-radio>
<el-radio :label="0">并发线程数</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="单机阈值">
<el-input-number v-model="createParam.flowCount"
size="small"
:step="1"
:disabled=isOnlyShowDetail
step-strictly></el-input-number>
</el-form-item>
</div>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs> </el-tabs>
</el-form> </el-form>
</div> </div>
...@@ -515,6 +560,9 @@ export default { ...@@ -515,6 +560,9 @@ export default {
sqls: [], sqls: [],
script: '', script: '',
open: false, open: false,
flowStatus: false,
flowGrade: 1,
flowCount: 5
}, },
showDebugDrawer: false, showDebugDrawer: false,
gatewayApiPrefix: 'http://127.0.0.1:8081/api/', gatewayApiPrefix: 'http://127.0.0.1:8081/api/',
...@@ -622,6 +670,9 @@ export default { ...@@ -622,6 +670,9 @@ export default {
engine: detail.engine, engine: detail.engine,
sqls: [], sqls: [],
script: "", script: "",
flowStatus: detail.flowStatus,
flowGrade: detail.flowGrade,
flowCount: detail.flowCount
} }
this.inputParams = [] this.inputParams = []
if (detail.params) { if (detail.params) {
...@@ -1061,6 +1112,9 @@ export default { ...@@ -1061,6 +1112,9 @@ export default {
contentType: this.createParam.contentType, contentType: this.createParam.contentType,
path: this.createParam.path, path: this.createParam.path,
open: this.createParam.open, open: this.createParam.open,
flowStatus: this.createParam.flowStatus,
flowGrade: this.createParam.flowGrade,
flowCount: this.createParam.flowCount,
engine: this.createParam.engine, engine: this.createParam.engine,
contextList: sqls, contextList: sqls,
params: this.inputParams params: this.inputParams
...@@ -1096,6 +1150,9 @@ export default { ...@@ -1096,6 +1150,9 @@ export default {
contentType: this.createParam.contentType, contentType: this.createParam.contentType,
path: this.createParam.path, path: this.createParam.path,
open: this.createParam.open, open: this.createParam.open,
flowStatus: this.createParam.flowStatus,
flowGrade: this.createParam.flowGrade,
flowCount: this.createParam.flowCount,
engine: this.createParam.engine, engine: this.createParam.engine,
contextList: sqls, contextList: sqls,
params: this.inputParams params: this.inputParams
......
...@@ -52,7 +52,7 @@ CREATE TABLE `SQLREST_API_ASSIGNMENT` ...@@ -52,7 +52,7 @@ CREATE TABLE `SQLREST_API_ASSIGNMENT`
( (
`id` bigint(20) unsigned not null auto_increment comment '主键', `id` bigint(20) unsigned not null auto_increment comment '主键',
`group_id` bigint(20) unsigned not null comment '分组ID', `group_id` bigint(20) unsigned not null comment '分组ID',
`module_id` bigint(20) unsigned not null comment '模块ID', `module_id` bigint(20) unsigned not null comment '模块ID',
`datasource_id` bigint(20) unsigned not null comment '数据源ID', `datasource_id` bigint(20) unsigned not null comment '数据源ID',
`name` varchar(255) not null default '' comment '接口名称', `name` varchar(255) not null default '' comment '接口名称',
`description` varchar(1024) default null comment '接口描述', `description` varchar(1024) default null comment '接口描述',
...@@ -62,6 +62,9 @@ CREATE TABLE `SQLREST_API_ASSIGNMENT` ...@@ -62,6 +62,9 @@ CREATE TABLE `SQLREST_API_ASSIGNMENT`
`status` tinyint(1) not null default 0 comment '是否发布', `status` tinyint(1) not null default 0 comment '是否发布',
`open` tinyint(1) not null default 0 comment '是否公开', `open` tinyint(1) not null default 0 comment '是否公开',
`engine` varchar(16) not null default 'SQL' comment '执行引擎', `engine` varchar(16) not null default 'SQL' comment '执行引擎',
`flow_status` tinyint(1) not null default 0 comment '是否开启流量控制',
`flow_grade` bigint(20) unsigned default null comment '流控类型',
`flow_count` bigint(20) unsigned default null comment '流控阈值',
`content_type` varchar(50) not null default '' comment 'ContentType', `content_type` varchar(50) not null default '' comment 'ContentType',
`create_time` timestamp not null default current_timestamp comment '创建时间', `create_time` timestamp not null default current_timestamp comment '创建时间',
`update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间', `update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间',
......
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>SQLREST工具</title><link href=/static/css/app.d22aaa58e5186516a00d39ee7f45a39c.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.070750a1b98317df6608.js></script><script type=text/javascript src=/static/js/vendor.b8089f9fd73f8896df25.js></script><script type=text/javascript src=/static/js/app.907b2e3813e3bdcda00d.js></script></body></html> <!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>SQLREST工具</title><link href=/static/css/app.ca40fc8269b428e8762bbd3028de33d9.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.e707a97f388d19a32b5e.js></script><script type=text/javascript src=/static/js/vendor.b8089f9fd73f8896df25.js></script><script type=text/javascript src=/static/js/app.907b2e3813e3bdcda00d.js></script></body></html>
\ No newline at end of file \ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,a){for(var f,d,i,u=0,s=[];u<r.length;u++)d=r[u],t[d]&&s.push(t[d][0]),t[d]=0;for(f in c)Object.prototype.hasOwnProperty.call(c,f)&&(e[f]=c[f]);for(n&&n(r,c,a);s.length;)s.shift()();if(a)for(u=0;u<a.length;u++)i=o(o.s=a[u]);return i};var r={},t={22:0};function o(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,o){n=t[e]=[r,o]});n[2]=r;var c=document.getElementsByTagName("head")[0],a=document.createElement("script");a.type="text/javascript",a.charset="utf-8",a.async=!0,a.timeout=12e4,o.nc&&a.setAttribute("nonce",o.nc),a.src=o.p+"static/js/"+e+"."+{0:"abe0376c7e6a5404f1a6",1:"0dd0668e608dd0f54f6e",2:"140338f6a5528feea1a3",3:"712d5b861100b5e0b704",4:"f8494b8dd039413f79c8",5:"f69840e8bd74f4d4e92b",6:"8f85de06573e2a5f9562",7:"7ea6008d16a44e79a428",8:"7483ee6d3a25506eb489",9:"1f165c58c9933d0da8a7",10:"cdd03027e5c73f31170c",11:"cdde61370dec5108c322",12:"57d1188c7336fe654844",13:"2865b5654b1d3bdf6e13",14:"42cdbd66a7803b30c641",15:"3b3f0c03ff4fed9903cc",16:"4de955682c1f7710c7ea",17:"819547b2361d544d3b8b",18:"5e7f065a8d031847e833",19:"3936346cb7e30aa279e2"}[e]+".js";var f=setTimeout(d,12e4);function d(){a.onerror=a.onload=null,clearTimeout(f);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return a.onerror=a.onload=d,c.appendChild(a),r},o.m=e,o.c=r,o.d=function(e,n,r){o.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="/",o.oe=function(e){throw console.error(e),e}}([]); !function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,a){for(var f,d,i,u=0,b=[];u<r.length;u++)d=r[u],t[d]&&b.push(t[d][0]),t[d]=0;for(f in c)Object.prototype.hasOwnProperty.call(c,f)&&(e[f]=c[f]);for(n&&n(r,c,a);b.length;)b.shift()();if(a)for(u=0;u<a.length;u++)i=o(o.s=a[u]);return i};var r={},t={22:0};function o(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,o){n=t[e]=[r,o]});n[2]=r;var c=document.getElementsByTagName("head")[0],a=document.createElement("script");a.type="text/javascript",a.charset="utf-8",a.async=!0,a.timeout=12e4,o.nc&&a.setAttribute("nonce",o.nc),a.src=o.p+"static/js/"+e+"."+{0:"13ff46be1994a329d393",1:"347dcbee299ce37dade6",2:"140338f6a5528feea1a3",3:"712d5b861100b5e0b704",4:"f8494b8dd039413f79c8",5:"f69840e8bd74f4d4e92b",6:"8f85de06573e2a5f9562",7:"7ea6008d16a44e79a428",8:"7483ee6d3a25506eb489",9:"1f165c58c9933d0da8a7",10:"cdd03027e5c73f31170c",11:"cdde61370dec5108c322",12:"57d1188c7336fe654844",13:"2865b5654b1d3bdf6e13",14:"42cdbd66a7803b30c641",15:"3b3f0c03ff4fed9903cc",16:"4de955682c1f7710c7ea",17:"819547b2361d544d3b8b",18:"5e7f065a8d031847e833",19:"3936346cb7e30aa279e2"}[e]+".js";var f=setTimeout(d,12e4);function d(){a.onerror=a.onload=null,clearTimeout(f);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return a.onerror=a.onload=d,c.appendChild(a),r},o.m=e,o.c=r,o.d=function(e,n,r){o.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="/",o.oe=function(e){throw console.error(e),e}}([]);
//# sourceMappingURL=manifest.070750a1b98317df6608.js.map //# sourceMappingURL=manifest.e707a97f388d19a32b5e.js.map
\ No newline at end of file \ No newline at end of file
...@@ -80,7 +80,8 @@ public class ApiAssignmentDao { ...@@ -80,7 +80,8 @@ public class ApiAssignmentDao {
return apiConfigEntity; return apiConfigEntity;
} }
public List<ApiAssignmentEntity> listAll(Long groupId, Long moduleId, Boolean publish, Boolean open, String searchText) { public List<ApiAssignmentEntity> listAll(Long groupId, Long moduleId, Boolean publish, Boolean open,
String searchText) {
return apiAssignmentMapper.selectList( return apiAssignmentMapper.selectList(
Wrappers.<ApiAssignmentEntity>lambdaQuery() Wrappers.<ApiAssignmentEntity>lambdaQuery()
.eq(Objects.nonNull(groupId), ApiAssignmentEntity::getGroupId, groupId) .eq(Objects.nonNull(groupId), ApiAssignmentEntity::getGroupId, groupId)
...@@ -96,6 +97,16 @@ public class ApiAssignmentDao { ...@@ -96,6 +97,16 @@ public class ApiAssignmentDao {
return apiAssignmentMapper.selectList(null); return apiAssignmentMapper.selectList(null);
} }
public List<ApiAssignmentEntity> listFlowControlAll() {
return apiAssignmentMapper.selectList(
Wrappers.<ApiAssignmentEntity>lambdaQuery()
.eq(ApiAssignmentEntity::getStatus, true)
.eq(ApiAssignmentEntity::getFlowStatus, true)
.isNotNull(ApiAssignmentEntity::getFlowGrade)
.isNotNull(ApiAssignmentEntity::getFlowCount)
);
}
public boolean existsDataSourceById(Long dataSourceId) { public boolean existsDataSourceById(Long dataSourceId) {
QueryWrapper<ApiAssignmentEntity> queryWrapper = new QueryWrapper<>(); QueryWrapper<ApiAssignmentEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(ApiAssignmentEntity::getDatasourceId, dataSourceId); queryWrapper.lambda().eq(ApiAssignmentEntity::getDatasourceId, dataSourceId);
......
...@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.annotation.TableName; ...@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sqlrest.common.dto.ItemParam; import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum; import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import com.gitee.sqlrest.common.enums.HttpMethodEnum; import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import com.gitee.sqlrest.common.enums.OnOffEnum;
import com.gitee.sqlrest.persistence.handler.ListParamHandler; import com.gitee.sqlrest.persistence.handler.ListParamHandler;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.List; import java.util.List;
...@@ -63,6 +64,15 @@ public class ApiAssignmentEntity { ...@@ -63,6 +64,15 @@ public class ApiAssignmentEntity {
@TableField(value = "engine", typeHandler = EnumTypeHandler.class) @TableField(value = "engine", typeHandler = EnumTypeHandler.class)
private ExecuteEngineEnum engine; private ExecuteEngineEnum engine;
@TableField(value = "flow_status")
private Boolean flowStatus;
@TableField("flow_grade")
private Integer flowGrade;
@TableField("flow_count")
private Integer flowCount;
@TableField(value = "create_time", insertStrategy = FieldStrategy.NEVER, updateStrategy = FieldStrategy.NEVER) @TableField(value = "create_time", insertStrategy = FieldStrategy.NEVER, updateStrategy = FieldStrategy.NEVER)
private Timestamp createTime; private Timestamp createTime;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment