Commit 6d198d72 by inrgihc

接口缓存功能

parent 740e734e
...@@ -8,6 +8,7 @@ body: ...@@ -8,6 +8,7 @@ body:
options: options:
- "1.0.0" - "1.0.0"
- "1.1.0" - "1.1.0"
- "1.2.0"
validations: validations:
required: true required: true
- type: dropdown - type: dropdown
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
- 支持自动生成在线接口文档功能 - 支持自动生成在线接口文档功能
> 基于swagger-ui提供自动生成在线接口文档功能。 > 基于swagger-ui提供自动生成在线接口文档功能。
- 支持接口缓存配置功能
> 执行器基于Hazelcast/Redis支持接口的缓存配置功能。
- 支持接口的流量控制功能 - 支持接口的流量控制功能
> 执行器基于sentinel支持接口的流量控制功能。 > 执行器基于sentinel支持接口的流量控制功能。
...@@ -66,12 +69,12 @@ ...@@ -66,12 +69,12 @@
├── sqlrest-template // sqlrest的SQL内容模板模块 ├── sqlrest-template // sqlrest的SQL内容模板模块
├── sqlrest-cache // sqlrest执行器缓存模块 ├── sqlrest-cache // sqlrest执行器缓存模块
├── sqlrest-persistence // sqlrest的数据库持久化模块 ├── sqlrest-persistence // sqlrest的数据库持久化模块
├── sqlrest-core // sqlrest-core的接口实现模块 ├── sqlrest-core // sqlrest接口核心实现模块
├── sqlrest-gateway // Gateway网关节点 ├── sqlrest-gateway // Gateway网关节点
├── sqlrest-executor // Executor执行节点 ├── sqlrest-executor // Executor执行节点
├── sqlrest-manager // Manager管理节点 ├── sqlrest-manager // Manager管理节点
├── sqlrest-manager-ui // 基于Vue2的Manager前段WEB交互页面 ├── sqlrest-manager-ui // WEB交互页面
├── sqlrest-dist // 基于maven-assembly-plugin插件的项目打包模块 ├── sqlrest-dist // 项目打包模块
``` ```
### 4、正在规划中的功能 ### 4、正在规划中的功能
...@@ -79,10 +82,13 @@ ...@@ -79,10 +82,13 @@
- (1) 接口检索功能 - (1) 接口检索功能
> 支持类似百度搜索的接口搜索功能,方便接口查找 > 支持类似百度搜索的接口搜索功能,方便接口查找
- (2) 支持接口的缓存配置功能 - (2) 接口详情功能
> 基于分布式缓存等构建支持接口的缓存配置功能。 > 支持接口的详细定义、数据来源、访问分析等功能
- (3) 支持接口的长效Token功能
> 支持配置接口的长期Token功能。
- (3) 前端界面整体美化 - (4) 前端界面整体美化
> 美化界面的交互展示,尤其是“拓扑结构”页面。 > 美化界面的交互展示,尤其是“拓扑结构”页面。
## 二、编译打包 ## 二、编译打包
...@@ -198,7 +204,27 @@ MYSQLDB_PASSWORD=123456 ...@@ -198,7 +204,27 @@ MYSQLDB_PASSWORD=123456
启动gateway服务:sh bin/sqlrestctl.sh start gateway 启动gateway服务:sh bin/sqlrestctl.sh start gateway
### 3、系统访问 ### 3、高级配置
>sqlrest的缓存同时支持分布式嵌入的hazelcast和redis,在manager/gateway/executor的application.yml配
>置文件中,可通过如下配置所使用的缓存,默认为使用hazelcast缓存。
```
sqlrest:
cache:
hazelcast:
# 是否开启使用hazelcast缓存
enabled: true
redis:
# 是否开启使用redis缓存
enabled: false
host: 127.0.0.1
port: 6379
password: 123456
database: 0
```
### 4、系统访问
启动完成后,通过http://<MANAGER_HOST>:<MANAGER_PORT> 地址即可访问。 启动完成后,通过http://<MANAGER_HOST>:<MANAGER_PORT> 地址即可访问。
......
docs/images/001.PNG

55.2 KB | W: | H:

docs/images/001.PNG

56 KB | W: | H:

docs/images/001.PNG
docs/images/001.PNG
docs/images/001.PNG
docs/images/001.PNG
  • 2-up
  • Swipe
  • Onion skin
docs/images/002.PNG

70.4 KB | W: | H:

docs/images/002.PNG

81.5 KB | W: | H:

docs/images/002.PNG
docs/images/002.PNG
docs/images/002.PNG
docs/images/002.PNG
  • 2-up
  • Swipe
  • Onion skin
docs/images/003.PNG

41.7 KB | W: | H:

docs/images/003.PNG

41.7 KB | W: | H:

docs/images/003.PNG
docs/images/003.PNG
docs/images/003.PNG
docs/images/003.PNG
  • 2-up
  • Swipe
  • Onion skin
docs/images/004.PNG

38 KB | W: | H:

docs/images/004.PNG

34.6 KB | W: | H:

docs/images/004.PNG
docs/images/004.PNG
docs/images/004.PNG
docs/images/004.PNG
  • 2-up
  • Swipe
  • Onion skin
docs/images/005.PNG

55.8 KB | W: | H:

docs/images/005.PNG

68.7 KB | W: | H:

docs/images/005.PNG
docs/images/005.PNG
docs/images/005.PNG
docs/images/005.PNG
  • 2-up
  • Swipe
  • Onion skin
...@@ -5,4 +5,6 @@ import java.util.Map; ...@@ -5,4 +5,6 @@ import java.util.Map;
public interface CacheFactory { public interface CacheFactory {
<T> Map<String, T> getCacheMap(String key, Class<T> clazz); <T> Map<String, T> getCacheMap(String key, Class<T> clazz);
DistributedCache getDistributedCache(String name);
} }
package com.gitee.sqlrest.cache;
import java.util.concurrent.TimeUnit;
/**
* 支持分布式的缓存接口定义
*/
public interface DistributedCache {
/**
* 获取cache名称
*
* @return String
*/
String getName();
/**
* 指定key获取值
*
* @param key 键
* @param type 类型
* @param <T> 泛型
* @return T
*/
<T> T get(String key, Class<T> type);
/**
* 向cache中写入缓存值
*
* @param key 键
* @param value 值
* @param expire 过期时长
* @param unit 过期时间单位
*/
void put(String key, Object value, long expire, TimeUnit unit);
/**
* 删除指定key的缓存数据
*
* @param key 键
*/
void evict(String key);
}
package com.gitee.sqlrest.cache.hazelcast; package com.gitee.sqlrest.cache.hazelcast;
import com.gitee.sqlrest.cache.CacheFactory; import com.gitee.sqlrest.cache.CacheFactory;
import com.gitee.sqlrest.cache.DistributedCache;
import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.HazelcastInstance;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Resource; import javax.annotation.Resource;
public class HazelcastCacheFactory implements CacheFactory { public class HazelcastCacheFactory implements CacheFactory {
private Map<String, HazelcastDistributedCache> cacheMap = new ConcurrentHashMap<>();
@Resource @Resource
private HazelcastInstance hazelcastInstance; private HazelcastInstance hazelcastInstance;
...@@ -15,4 +19,8 @@ public class HazelcastCacheFactory implements CacheFactory { ...@@ -15,4 +19,8 @@ public class HazelcastCacheFactory implements CacheFactory {
return hazelcastInstance.getMap(key); return hazelcastInstance.getMap(key);
} }
@Override
public DistributedCache getDistributedCache(String name) {
return cacheMap.computeIfAbsent(name, key -> new HazelcastDistributedCache(hazelcastInstance, key));
}
} }
package com.gitee.sqlrest.cache.hazelcast;
import com.gitee.sqlrest.cache.DistributedCache;
import com.hazelcast.core.HazelcastInstance;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
public class HazelcastDistributedCache implements DistributedCache {
private final HazelcastInstance instance;
private final String name;
public HazelcastDistributedCache(HazelcastInstance instance, String name) {
this.instance = Objects.requireNonNull(instance, "instance must not be null");
this.name = Objects.requireNonNull(name, "cache name must not be null");
}
@Override
public String getName() {
return this.name;
}
@Override
public <T> T get(String key, Class<T> type) {
Object value = instance.getMap(name).get(key);
return Optional.ofNullable(value).map(v -> type.cast(v)).orElse(null);
}
@Override
public void put(String key, Object value, long expire, TimeUnit unit) {
if (expire > 0) {
instance.getMap(name).put(key, value, expire, unit);
} else {
instance.getMap(name).put(key, value);
}
}
@Override
public void evict(String key) {
instance.getMap(name).evict(key);
}
}
package com.gitee.sqlrest.cache.redis; package com.gitee.sqlrest.cache.redis;
import com.gitee.sqlrest.cache.CacheFactory; import com.gitee.sqlrest.cache.CacheFactory;
import com.gitee.sqlrest.cache.DistributedCache;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Resource; import javax.annotation.Resource;
public class RedisCacheFactory implements CacheFactory { public class RedisCacheFactory implements CacheFactory {
private Map<String, RedisDistributedCache> cacheMap = new ConcurrentHashMap<>();
@Resource @Resource
private JedisClient jedisClient; private JedisClient jedisClient;
...@@ -13,4 +17,9 @@ public class RedisCacheFactory implements CacheFactory { ...@@ -13,4 +17,9 @@ public class RedisCacheFactory implements CacheFactory {
public <T> Map<String, T> getCacheMap(String key, Class<T> clazz) { public <T> Map<String, T> getCacheMap(String key, Class<T> clazz) {
return new RedisCacheMap<>(key, jedisClient, clazz); return new RedisCacheMap<>(key, jedisClient, clazz);
} }
@Override
public DistributedCache getDistributedCache(String name) {
return cacheMap.computeIfAbsent(name, key -> new RedisDistributedCache(key, jedisClient));
}
} }
package com.gitee.sqlrest.cache.redis;
import cn.hutool.json.JSONUtil;
import com.gitee.sqlrest.cache.DistributedCache;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
public class RedisDistributedCache implements DistributedCache {
private final String FORMAT = "%s#%s";
private final String name;
private JedisClient client;
public RedisDistributedCache(String name, JedisClient client) {
this.name = Objects.requireNonNull(name, "cache name must not be null");
this.client = Objects.requireNonNull(client, "client must not be null");
}
@Override
public String getName() {
return this.name;
}
@Override
public <T> T get(String key, Class<T> type) {
String redisKey = String.format(FORMAT, name, key);
String redisVal = client.doAction(jedis -> jedis.get(redisKey));
if (null == redisVal) {
return null;
}
return JSONUtil.toBean(redisVal, type, true);
}
@Override
public void put(String key, Object value, long expire, TimeUnit unit) {
String redisKey = String.format(FORMAT, name, key);
String redisVal = JSONUtil.toJsonStr(value);
client.doConsume(jedis -> {
jedis.set(redisKey, redisVal);
if (expire > 0) {
jedis.expire(redisKey, unit.toSeconds(expire));
}
});
}
@Override
public void evict(String key) {
String redisKey = String.format(FORMAT, name, key);
client.doConsume(jedis -> {
jedis.del(redisKey);
});
}
}
...@@ -18,6 +18,10 @@ public abstract class Constants { ...@@ -18,6 +18,10 @@ public abstract class Constants {
public static final int SC_TOO_MANY_REQUESTS = 429; public static final int SC_TOO_MANY_REQUESTS = 429;
public static final String CACHE_NAME_API_RESPONSE = "response_result";
public static final String CACHE_NAME_API_VAR = "variable_value";
public static final String API_DOC_PATH_PREFIX = "/apidoc"; public static final String API_DOC_PATH_PREFIX = "/apidoc";
public static final String SYS_PARAM_KEY_API_DOC_OPEN = "apiDocOpen"; public static final String SYS_PARAM_KEY_API_DOC_OPEN = "apiDocOpen";
......
package com.gitee.sqlrest.common.enums;
public enum CacheKeyTypeEnum {
NONE(false, "关闭缓存不需要生产缓存KEY"),
AUTO(true, "根据入参自动生成缓存KEY"),
SPEL(true, "使用SpEL计算生成缓存KEY"),
;
private boolean useCache;
private String name;
CacheKeyTypeEnum(boolean cache, String name) {
this.useCache = cache;
this.name = name;
}
public boolean isUseCache() {
return useCache;
}
public String getName() {
return name;
}
}
...@@ -3,6 +3,7 @@ package com.gitee.sqlrest.core.dto; ...@@ -3,6 +3,7 @@ package com.gitee.sqlrest.core.dto;
import com.baomidou.mybatisplus.annotation.TableField; 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.dto.OutParam; import com.gitee.sqlrest.common.dto.OutParam;
import com.gitee.sqlrest.common.enums.CacheKeyTypeEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum; import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.persistence.entity.ApiContextEntity; import com.gitee.sqlrest.persistence.entity.ApiContextEntity;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
...@@ -54,4 +55,13 @@ public class ApiAssignmentDetailResponse extends ApiAssignmentBaseResponse { ...@@ -54,4 +55,13 @@ public class ApiAssignmentDetailResponse extends ApiAssignmentBaseResponse {
@TableField("阈值大小") @TableField("阈值大小")
private Integer flowCount; private Integer flowCount;
@ApiModelProperty("缓存键类型")
private CacheKeyTypeEnum cacheKeyType;
@ApiModelProperty("缓存表达式")
private String cacheKeyExpr;
@ApiModelProperty("缓存时常")
private Long cacheExpireSeconds;
} }
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.dto.OutParam; import com.gitee.sqlrest.common.dto.OutParam;
import com.gitee.sqlrest.common.enums.CacheKeyTypeEnum;
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.NamingStrategyEnum; import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
...@@ -87,4 +89,13 @@ public class ApiAssignmentSaveRequest { ...@@ -87,4 +89,13 @@ public class ApiAssignmentSaveRequest {
@ApiModelProperty("单机阈值") @ApiModelProperty("单机阈值")
private Integer flowCount; private Integer flowCount;
@ApiModelProperty("缓存键类型")
private CacheKeyTypeEnum cacheKeyType;
@TableField("缓存表达式")
private String cacheKeyExpr;
@TableField("缓存时常")
private Long cacheExpireSeconds;
} }
package com.gitee.sqlrest.core.exec; package com.gitee.sqlrest.core.exec;
import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.gitee.sqlrest.cache.CacheFactory;
import com.gitee.sqlrest.cache.DistributedCache;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.dto.ItemParam; import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.dto.ResultEntity; import com.gitee.sqlrest.common.dto.ResultEntity;
import com.gitee.sqlrest.common.enums.CacheKeyTypeEnum;
import com.gitee.sqlrest.common.enums.HttpMethodEnum; import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import com.gitee.sqlrest.common.enums.ParamLocationEnum; import com.gitee.sqlrest.common.enums.ParamLocationEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum; import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import com.gitee.sqlrest.common.exception.CommonException;
import com.gitee.sqlrest.common.exception.ResponseErrorCode; import com.gitee.sqlrest.common.exception.ResponseErrorCode;
import com.gitee.sqlrest.core.driver.DriverLoadService; import com.gitee.sqlrest.core.driver.DriverLoadService;
import com.gitee.sqlrest.core.exec.engine.ApiExecutorEngineFactory; import com.gitee.sqlrest.core.exec.engine.ApiExecutorEngineFactory;
import com.gitee.sqlrest.core.exec.extractor.HttpRequestBodyExtractor; import com.gitee.sqlrest.core.exec.extractor.HttpRequestBodyExtractor;
import com.gitee.sqlrest.core.util.DataSourceUtils; import com.gitee.sqlrest.core.util.DataSourceUtils;
import com.gitee.sqlrest.core.util.SpelUtils;
import com.gitee.sqlrest.persistence.dao.DataSourceDao; import com.gitee.sqlrest.persistence.dao.DataSourceDao;
import com.gitee.sqlrest.persistence.entity.ApiAssignmentEntity; import com.gitee.sqlrest.persistence.entity.ApiAssignmentEntity;
import com.gitee.sqlrest.persistence.entity.DataSourceEntity; import com.gitee.sqlrest.persistence.entity.DataSourceEntity;
import com.gitee.sqlrest.persistence.util.JsonUtils;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import java.io.File; import java.io.File;
...@@ -26,6 +34,7 @@ import java.util.Collections; ...@@ -26,6 +34,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -41,34 +50,73 @@ import org.springframework.stereotype.Service; ...@@ -41,34 +50,73 @@ import org.springframework.stereotype.Service;
public class ApiExecuteService { public class ApiExecuteService {
@Resource @Resource
private CacheFactory cacheFactory;
@Resource
private DataSourceDao dataSourceDao; private DataSourceDao dataSourceDao;
@Resource @Resource
private DriverLoadService driverLoadService; private DriverLoadService driverLoadService;
@Resource @Resource
private List<HttpRequestBodyExtractor> requestBodyExtractors; private List<HttpRequestBodyExtractor> requestBodyExtractors;
private DistributedCache getDistributedCache() {
return cacheFactory.getDistributedCache(Constants.CACHE_NAME_API_RESPONSE);
}
private String getCacheKeyValue(ApiAssignmentEntity config, Map<String, Object> paramValues) {
String key = CacheKeyTypeEnum.SPEL == config.getCacheKeyType()
? SpelUtils.getExpressionValue(config.getCacheKeyExpr(), paramValues)
: DigestUtil.sha256Hex(JsonUtils.toJsonString(paramValues));
return Constants.getResourceName(config.getMethod().name(), config.getPath()) + ":" + key;
}
public ResultEntity<Object> execute(ApiAssignmentEntity config, HttpServletRequest request) { public ResultEntity<Object> execute(ApiAssignmentEntity config, HttpServletRequest request) {
try { try {
List<ItemParam> invalidArgs = new ArrayList<>();
Map<String, Object> paramValues = mergeParameters(request, config.getParams(), invalidArgs);
if (invalidArgs.size() > 0) {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, convertInvalidArgs(invalidArgs));
}
if (config.getCacheKeyType().isUseCache()) {
String key = getCacheKeyValue(config, paramValues);
DistributedCache cache = getDistributedCache();
ResultEntity result = cache.get(key, ResultEntity.class);
if (null == result) {
result = doExecute(getDataSourceEntity(config), config, paramValues);
cache.put(key, result, config.getCacheExpireSeconds(), TimeUnit.SECONDS);
} else {
String resourceName = Constants.getResourceName(config.getMethod().name(), config.getPath());
log.info("Execute for {} find cache response by cacheKey={}", resourceName, key);
}
return result;
} else {
ResultEntity result = doExecute(getDataSourceEntity(config), config, paramValues);
return ResultEntity.success(result);
}
} catch (CommonException e) {
return ResultEntity.failed(e.getCode(), e.getMessage());
} catch (Throwable t) {
return ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, ExceptionUtil.getMessage(t));
}
}
private DataSourceEntity getDataSourceEntity(ApiAssignmentEntity config) {
DataSourceEntity dsEntity = dataSourceDao.getById(config.getDatasourceId()); DataSourceEntity dsEntity = dataSourceDao.getById(config.getDatasourceId());
if (null == dsEntity) { if (null == dsEntity) {
String message = "datasource[id=" + config.getDatasourceId() + " not exist!"; String message = "datasource[id=" + config.getDatasourceId() + " not exist!";
log.warn("Error for handle api[id={}],information:{}", config.getId(), message); log.warn("Error for handle api[id={}],information:{}", config.getId(), message);
return ResultEntity.failed(ResponseErrorCode.ERROR_RESOURCE_NOT_EXISTS, message); throw new CommonException(ResponseErrorCode.ERROR_RESOURCE_NOT_EXISTS, message);
} }
List<ItemParam> invalidArgs = new ArrayList<>(); return dsEntity;
Map<String, Object> paramValues = extractParameters(request, config.getParams(), invalidArgs);
if (invalidArgs.size() > 0) {
return ResultEntity.failed(ResponseErrorCode.ERROR_INVALID_ARGUMENT, convertInvalidArgs(invalidArgs));
} }
private ResultEntity doExecute(DataSourceEntity dsEntity, ApiAssignmentEntity config,
Map<String, Object> paramValues) {
File driverPath = driverLoadService.getVersionDriverFile(dsEntity.getType(), dsEntity.getVersion()); File driverPath = driverLoadService.getVersionDriverFile(dsEntity.getType(), dsEntity.getVersion());
HikariDataSource dataSource = DataSourceUtils.getHikariDataSource(dsEntity, driverPath.getAbsolutePath()); HikariDataSource dataSource = DataSourceUtils.getHikariDataSource(dsEntity, driverPath.getAbsolutePath());
List<Object> results = ApiExecutorEngineFactory List<Object> results = ApiExecutorEngineFactory
.getExecutor(config.getEngine(), dataSource, dsEntity.getType()) .getExecutor(config.getEngine(), dataSource, dsEntity.getType())
.execute(config.getContextList(), paramValues, config.getNamingStrategy()); .execute(config.getContextList(), paramValues, config.getNamingStrategy());
return ResultEntity.success(results.size() > 1 ? results : results.stream().findAny().orElse(null)); return ResultEntity.success(results.size() > 1 ? results : results.stream().findAny().orElse(null));
} catch (Throwable t) {
return ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, ExceptionUtil.getMessage(t));
}
} }
private String convertInvalidArgs(List<ItemParam> invalidArgs) { private String convertInvalidArgs(List<ItemParam> invalidArgs) {
...@@ -77,7 +125,7 @@ public class ApiExecuteService { ...@@ -77,7 +125,7 @@ public class ApiExecuteService {
).collect(Collectors.joining(";")); ).collect(Collectors.joining(";"));
} }
private Map<String, Object> extractParameters(HttpServletRequest request, List<ItemParam> params, private Map<String, Object> mergeParameters(HttpServletRequest request, List<ItemParam> params,
List<ItemParam> invalidArgs) throws IOException { List<ItemParam> invalidArgs) throws IOException {
if (CollectionUtils.isEmpty(params)) { if (CollectionUtils.isEmpty(params)) {
return Collections.emptyMap(); return Collections.emptyMap();
......
...@@ -6,6 +6,7 @@ import com.gitee.sqlrest.common.enums.ProductTypeEnum; ...@@ -6,6 +6,7 @@ import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.core.dto.ScriptEditorCompletion; import com.gitee.sqlrest.core.dto.ScriptEditorCompletion;
import com.gitee.sqlrest.core.exec.annotation.Module; import com.gitee.sqlrest.core.exec.annotation.Module;
import com.gitee.sqlrest.core.exec.engine.AbstractExecutorEngine; import com.gitee.sqlrest.core.exec.engine.AbstractExecutorEngine;
import com.gitee.sqlrest.core.exec.module.CacheVarModule;
import com.gitee.sqlrest.core.exec.module.DbVarModule; import com.gitee.sqlrest.core.exec.module.DbVarModule;
import com.gitee.sqlrest.core.exec.module.EnvVarModule; import com.gitee.sqlrest.core.exec.module.EnvVarModule;
import com.gitee.sqlrest.persistence.entity.ApiContextEntity; import com.gitee.sqlrest.persistence.entity.ApiContextEntity;
...@@ -21,7 +22,7 @@ import org.codehaus.groovy.control.CompilationFailedException; ...@@ -21,7 +22,7 @@ import org.codehaus.groovy.control.CompilationFailedException;
public class ScriptExecutorService extends AbstractExecutorEngine { public class ScriptExecutorService extends AbstractExecutorEngine {
public static List<ScriptEditorCompletion> syntax = new ArrayList<>(); public static List<ScriptEditorCompletion> syntax = new ArrayList<>();
public static List<Class> modules = Arrays.asList(EnvVarModule.class, DbVarModule.class); public static List<Class> modules = Arrays.asList(EnvVarModule.class, DbVarModule.class, CacheVarModule.class);
static { static {
syntax.add( syntax.add(
...@@ -89,6 +90,7 @@ public class ScriptExecutorService extends AbstractExecutorEngine { ...@@ -89,6 +90,7 @@ public class ScriptExecutorService extends AbstractExecutorEngine {
@Override @Override
public List<Object> execute(List<ApiContextEntity> scripts, Map<String, Object> params, NamingStrategyEnum strategy) { public List<Object> execute(List<ApiContextEntity> scripts, Map<String, Object> params, NamingStrategyEnum strategy) {
EnvVarModule envModule = SpringUtil.getBean(EnvVarModule.class); EnvVarModule envModule = SpringUtil.getBean(EnvVarModule.class);
CacheVarModule cacheModule = SpringUtil.getBean(CacheVarModule.class);
DbVarModule dbModule = new DbVarModule(dataSource, productType, params, strategy); DbVarModule dbModule = new DbVarModule(dataSource, productType, params, strategy);
List<Object> results = new ArrayList<>(); List<Object> results = new ArrayList<>();
...@@ -97,6 +99,7 @@ public class ScriptExecutorService extends AbstractExecutorEngine { ...@@ -97,6 +99,7 @@ public class ScriptExecutorService extends AbstractExecutorEngine {
params.forEach((k, v) -> binding.setProperty(k, v)); params.forEach((k, v) -> binding.setProperty(k, v));
binding.setProperty(getModuleVarName(dbModule.getClass()), dbModule); binding.setProperty(getModuleVarName(dbModule.getClass()), dbModule);
binding.setProperty(getModuleVarName(envModule.getClass()), envModule); binding.setProperty(getModuleVarName(envModule.getClass()), envModule);
binding.setProperty(getModuleVarName(cacheModule.getClass()), cacheModule);
GroovyShell groovyShell = new GroovyShell(binding); GroovyShell groovyShell = new GroovyShell(binding);
try { try {
......
package com.gitee.sqlrest.core.exec.module;
import com.gitee.sqlrest.cache.CacheFactory;
import com.gitee.sqlrest.cache.DistributedCache;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.core.exec.annotation.Comment;
import com.gitee.sqlrest.core.exec.annotation.Module;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
@Module("cache")
public class CacheVarModule {
@Resource
private CacheFactory cacheFactory;
private DistributedCache getDistributedCache() {
return cacheFactory.getDistributedCache(Constants.CACHE_NAME_API_VAR);
}
@Comment("根据键获取缓存中的值")
public String get(@Comment("key") String key) {
DistributedCache cache = getDistributedCache();
return cache.get(key, String.class);
}
@Comment("向缓存中写入指定键的值")
public void put(@Comment("key") String key, @Comment("value") String value, @Comment("ttl") long ttl) {
DistributedCache cache = getDistributedCache();
cache.put(key, value, ttl, TimeUnit.SECONDS);
}
@Comment("删除缓存中指定键的值")
public void evict(@Comment("key") String key) {
DistributedCache cache = getDistributedCache();
cache.evict(key);
}
}
...@@ -8,6 +8,7 @@ import com.gitee.sqlrest.common.dto.PageResult; ...@@ -8,6 +8,7 @@ import com.gitee.sqlrest.common.dto.PageResult;
import com.gitee.sqlrest.common.dto.ParamValue; import com.gitee.sqlrest.common.dto.ParamValue;
import com.gitee.sqlrest.common.dto.ParamValue.BaseParamValue; import com.gitee.sqlrest.common.dto.ParamValue.BaseParamValue;
import com.gitee.sqlrest.common.dto.ResultEntity; import com.gitee.sqlrest.common.dto.ResultEntity;
import com.gitee.sqlrest.common.enums.CacheKeyTypeEnum;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum; import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum; import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.common.enums.OnOffEnum; import com.gitee.sqlrest.common.enums.OnOffEnum;
...@@ -353,10 +354,30 @@ public class ApiAssignmentService { ...@@ -353,10 +354,30 @@ public class ApiAssignmentService {
if (null == request.getNamingStrategy()) { if (null == request.getNamingStrategy()) {
request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE); request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE);
} }
if (null == request.getCacheKeyType()) {
request.setCacheKeyType(CacheKeyTypeEnum.NONE);
}
while (request.getPath().startsWith("/")) { while (request.getPath().startsWith("/")) {
request.setPath(request.getPath().substring(1)); request.setPath(request.getPath().substring(1));
} }
if (request.getCacheKeyType().isUseCache()) {
if (request.getCacheExpireSeconds() <= 0) {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "Invalid param cacheExpireSeconds");
}
if (CacheKeyTypeEnum.SPEL == request.getCacheKeyType()) {
if (StringUtils.isBlank(request.getCacheKeyExpr())) {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "SPEL cache must has cacheKeyExpr");
}
}
if (CacheKeyTypeEnum.AUTO == request.getCacheKeyType()) {
request.setCacheKeyExpr(null);
}
} else {
request.setCacheExpireSeconds(0L);
request.setCacheKeyExpr(null);
}
List<ApiContextEntity> contextList = getContextListEntity(request.getContextList()); List<ApiContextEntity> contextList = getContextListEntity(request.getContextList());
ApiAssignmentEntity assignmentEntity = new ApiAssignmentEntity(); ApiAssignmentEntity assignmentEntity = new ApiAssignmentEntity();
...@@ -380,6 +401,9 @@ public class ApiAssignmentService { ...@@ -380,6 +401,9 @@ public class ApiAssignmentService {
assignmentEntity.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false)); assignmentEntity.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false));
assignmentEntity.setFlowGrade(request.getFlowGrade()); assignmentEntity.setFlowGrade(request.getFlowGrade());
assignmentEntity.setFlowCount(request.getFlowCount()); assignmentEntity.setFlowCount(request.getFlowCount());
assignmentEntity.setCacheKeyType(request.getCacheKeyType());
assignmentEntity.setCacheKeyExpr(request.getCacheKeyExpr());
assignmentEntity.setCacheExpireSeconds(Optional.ofNullable(request.getCacheExpireSeconds()).orElse(0L));
apiAssignmentDao.insert(assignmentEntity); apiAssignmentDao.insert(assignmentEntity);
return assignmentEntity.getId(); return assignmentEntity.getId();
...@@ -428,6 +452,26 @@ public class ApiAssignmentService { ...@@ -428,6 +452,26 @@ public class ApiAssignmentService {
if (null == request.getNamingStrategy()) { if (null == request.getNamingStrategy()) {
request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE); request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE);
} }
if (null == request.getCacheKeyType()) {
request.setCacheKeyType(CacheKeyTypeEnum.NONE);
}
if (request.getCacheKeyType().isUseCache()) {
if (request.getCacheExpireSeconds() <= 0) {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "Invalid param cacheExpireSeconds");
}
if (CacheKeyTypeEnum.SPEL == request.getCacheKeyType()) {
if (StringUtils.isBlank(request.getCacheKeyExpr())) {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "SPEL cache must has cacheKeyExpr");
}
}
if (CacheKeyTypeEnum.AUTO == request.getCacheKeyType()) {
request.setCacheKeyExpr(null);
}
} else {
request.setCacheExpireSeconds(0L);
request.setCacheKeyExpr(null);
}
List<ApiContextEntity> contextList = getContextListEntity(request.getContextList()); List<ApiContextEntity> contextList = getContextListEntity(request.getContextList());
...@@ -453,6 +497,9 @@ public class ApiAssignmentService { ...@@ -453,6 +497,9 @@ public class ApiAssignmentService {
assignmentEntity.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false)); assignmentEntity.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false));
assignmentEntity.setFlowGrade(request.getFlowGrade()); assignmentEntity.setFlowGrade(request.getFlowGrade());
assignmentEntity.setFlowCount(request.getFlowCount()); assignmentEntity.setFlowCount(request.getFlowCount());
assignmentEntity.setCacheKeyType(request.getCacheKeyType());
assignmentEntity.setCacheKeyExpr(request.getCacheKeyExpr());
assignmentEntity.setCacheExpireSeconds(Optional.ofNullable(request.getCacheExpireSeconds()).orElse(0L));
apiAssignmentDao.update(assignmentEntity); apiAssignmentDao.update(assignmentEntity);
} }
......
package com.gitee.sqlrest.core.util;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@Slf4j
public final class SpelUtils {
private final static ExpressionParser expressionParser = new SpelExpressionParser();
public static String getExpressionValue(String expr, Map<String, Object> paramValues) {
EvaluationContext context = new StandardEvaluationContext();
for (Map.Entry<String, Object> entry : paramValues.entrySet()) {
context.setVariable(entry.getKey(), entry.getValue());
}
try {
Object value = expressionParser.parseExpression(expr).getValue(context);
if (null != value) {
return value.toString();
}
} catch (Exception e) {
log.warn("Parse SpEL value from parameters failed:{}", e.getMessage());
}
return expr;
}
}
...@@ -467,6 +467,49 @@ ...@@ -467,6 +467,49 @@
</el-col> </el-col>
</el-row> </el-row>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="缓存配置"
name="cacheConfig">
<el-form-item label="缓存方法"
label-width="120px"
style="width:60%">
<el-select v-model="createParam.cacheKeyType"
style="width:40%"
:disabled="isOnlyShowDetail">
<el-option v-for="item in cacheKeyTypeList"
:key="item.value"
:label="item.name"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label-width="120px"
style="width:60%"
v-show="createParam.cacheKeyType==='SPEL'">
<span slot="label"
style="display:inline-block;">
SpEL表达式
<el-tooltip effect="dark"
content="必填,可以使用Spring表达式语言(Spring Expression Language,SpEL)计算入参值的缓存KEY,例如:#deptNo或#dept.deptNo等形式"
placement="top">
<i class='el-icon-question' />
</el-tooltip>
</span>
<el-input v-model="createParam.cacheKeyExpr"
auto-complete="off"
style="width:75%"
:disabled="isOnlyShowDetail"></el-input>
</el-form-item>
<el-form-item label="过期时长(秒)"
label-width="120px"
style="width:60%"
v-show="createParam.cacheKeyType==='SPEL'|| createParam.cacheKeyType==='AUTO'">
<el-input-number v-model="createParam.cacheExpireSeconds"
size="small"
:min="10"
:step="1"
:disabled="isOnlyShowDetail"
step-strictly></el-input-number>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="流量控制" <el-tab-pane label="流量控制"
name="flowControl"> name="flowControl">
<el-row> <el-row>
...@@ -683,6 +726,11 @@ export default { ...@@ -683,6 +726,11 @@ export default {
{ name: "对象", value: "OBJECT" } { name: "对象", value: "OBJECT" }
], ],
contentTypes: ['application/x-www-form-urlencoded', 'application/json'], contentTypes: ['application/x-www-form-urlencoded', 'application/json'],
cacheKeyTypeList: [
{ name: "关闭缓存功能", value: "NONE" },
{ name: "哈希生存缓存KEY", value: "AUTO" },
{ name: "SpEL生成缓存KEY", value: "SPEL" },
],
showTree: true, showTree: true,
editorHeightNum: 300, editorHeightNum: 300,
createParam: { createParam: {
...@@ -703,7 +751,10 @@ export default { ...@@ -703,7 +751,10 @@ export default {
formatMap: null, formatMap: null,
flowStatus: false, flowStatus: false,
flowGrade: 1, flowGrade: 1,
flowCount: 5 flowCount: 5,
cacheKeyType: 'NONE',
cacheKeyExpr: '',
cacheExpireSeconds: '300',
}, },
showDebugDrawer: false, showDebugDrawer: false,
gatewayApiPrefix: 'http://127.0.0.1:8081/api/', gatewayApiPrefix: 'http://127.0.0.1:8081/api/',
...@@ -833,7 +884,10 @@ export default { ...@@ -833,7 +884,10 @@ export default {
formatMap: detail.formatMap, formatMap: detail.formatMap,
flowStatus: detail.flowStatus, flowStatus: detail.flowStatus,
flowGrade: detail.flowGrade, flowGrade: detail.flowGrade,
flowCount: detail.flowCount flowCount: detail.flowCount,
cacheKeyType: detail.cacheKeyType,
cacheKeyExpr: detail.cacheKeyExpr,
cacheExpireSeconds: detail.cacheExpireSeconds,
} }
this.inputParams = [] this.inputParams = []
if (detail.params) { if (detail.params) {
...@@ -1438,6 +1492,9 @@ export default { ...@@ -1438,6 +1492,9 @@ export default {
flowStatus: this.createParam.flowStatus, flowStatus: this.createParam.flowStatus,
flowGrade: this.createParam.flowGrade, flowGrade: this.createParam.flowGrade,
flowCount: this.createParam.flowCount, flowCount: this.createParam.flowCount,
cacheKeyType: this.createParam.cacheKeyType,
cacheKeyExpr: this.createParam.cacheKeyExpr,
cacheExpireSeconds: this.createParam.cacheExpireSeconds,
engine: this.createParam.engine, engine: this.createParam.engine,
contextList: sqls, contextList: sqls,
params: this.inputParams, params: this.inputParams,
...@@ -1484,6 +1541,9 @@ export default { ...@@ -1484,6 +1541,9 @@ export default {
flowStatus: this.createParam.flowStatus, flowStatus: this.createParam.flowStatus,
flowGrade: this.createParam.flowGrade, flowGrade: this.createParam.flowGrade,
flowCount: this.createParam.flowCount, flowCount: this.createParam.flowCount,
cacheKeyType: this.createParam.cacheKeyType,
cacheKeyExpr: this.createParam.cacheKeyExpr,
cacheExpireSeconds: this.createParam.cacheExpireSeconds,
engine: this.createParam.engine, engine: this.createParam.engine,
contextList: sqls, contextList: sqls,
params: this.inputParams, params: this.inputParams,
......
...@@ -17,6 +17,7 @@ import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; ...@@ -17,6 +17,7 @@ import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
"com.gitee.sqlrest.core.gateway", "com.gitee.sqlrest.core.gateway",
"com.gitee.sqlrest.core.service", "com.gitee.sqlrest.core.service",
"com.gitee.sqlrest.core.exec", "com.gitee.sqlrest.core.exec",
"com.gitee.sqlrest.cache",
"com.gitee.sqlrest.manager" "com.gitee.sqlrest.manager"
} }
) )
......
...@@ -3,3 +3,5 @@ databaseChangeLog: ...@@ -3,3 +3,5 @@ databaseChangeLog:
file: classpath:db/changelog/log-v1.0.1.yaml file: classpath:db/changelog/log-v1.0.1.yaml
- include: - include:
file: classpath:db/changelog/log-v1.0.2.yaml file: classpath:db/changelog/log-v1.0.2.yaml
- include:
file: classpath:db/changelog/log-v1.1.1.yaml
\ No newline at end of file
databaseChangeLog:
- changeSet:
id: 1.1.1
author: sqlrest
runOnChange: false
changes:
- sqlFile:
encoding: UTF-8
path: db/migration/V1_1_1__system-ddl.sql
ALTER TABLE `SQLREST_API_ASSIGNMENT` ADD COLUMN `cache_key_type` varchar(16) not null default 'NONE' COMMENT '缓存键类型' AFTER `content_type`;
ALTER TABLE `SQLREST_API_ASSIGNMENT` ADD COLUMN `cache_key_expr` varchar(255) null COMMENT '缓存key的SpEL表达式' AFTER `cache_key_type`;
ALTER TABLE `SQLREST_API_ASSIGNMENT` ADD COLUMN `cache_expire_seconds` bigint(20) unsigned not null default 0 COMMENT '缓存过期时长(秒)' AFTER `cache_key_expr`;
<!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.072d7e806ffea2dbe3ce273489ed669e.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.075ed85199204f860c2e.js></script><script type=text/javascript src=/static/js/vendor.6bde4750a07bb5a2f647.js></script><script type=text/javascript src=/static/js/app.5b13ca32f61140a99ff5.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.21575699e2f9b8295d3f50748b986c67.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.37da822ab10e62d568da.js></script><script type=text/javascript src=/static/js/vendor.6bde4750a07bb5a2f647.js></script><script type=text/javascript src=/static/js/app.5b13ca32f61140a99ff5.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.
!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,o,c){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 o)Object.prototype.hasOwnProperty.call(o,f)&&(e[f]=o[f]);for(n&&n(r,o,c);b.length;)b.shift()();if(c)for(u=0;u<c.length;u++)i=a(a.s=c[u]);return i};var r={},t={24:0};function a(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,a),t.l=!0,t.exports}a.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,a){n=t[e]=[r,a]});n[2]=r;var o=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.charset="utf-8",c.async=!0,c.timeout=12e4,a.nc&&c.setAttribute("nonce",a.nc),c.src=a.p+"static/js/"+e+"."+{0:"e9559647b804220c4683",1:"b17200cccd46e216dcb3",2:"140338f6a5528feea1a3",3:"776d791724a8de12ff9e",4:"f8494b8dd039413f79c8",5:"530a43b5ad6055214539",6:"8f85de06573e2a5f9562",7:"061807fe4716131f26f8",8:"d1391c270de5a9f111c5",9:"cbdb7fa4f5180acfbb03",10:"7eeaa94fd42d34a86b92",11:"096c0f0eaf2850056b7e",12:"cea57d271a961f0b44ad",13:"4d2138ee1bee3ad573f4",14:"429592868e75adc95933",15:"3b3f0c03ff4fed9903cc",16:"9616cfe0a4f7517b0841",17:"b4bc5fa31e227bee8651",18:"5e7f065a8d031847e833",19:"3936346cb7e30aa279e2",20:"5ef9c751035ee9a08f94",21:"d8007e7169c085e13dab"}[e]+".js";var f=setTimeout(d,12e4);function d(){c.onerror=c.onload=null,clearTimeout(f);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return c.onerror=c.onload=d,o.appendChild(c),r},a.m=e,a.c=r,a.d=function(e,n,r){a.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},a.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="/",a.oe=function(e){throw console.error(e),e}}([]); !function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,o,c){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 o)Object.prototype.hasOwnProperty.call(o,f)&&(e[f]=o[f]);for(n&&n(r,o,c);b.length;)b.shift()();if(c)for(u=0;u<c.length;u++)i=a(a.s=c[u]);return i};var r={},t={24:0};function a(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,a),t.l=!0,t.exports}a.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,a){n=t[e]=[r,a]});n[2]=r;var o=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.charset="utf-8",c.async=!0,c.timeout=12e4,a.nc&&c.setAttribute("nonce",a.nc),c.src=a.p+"static/js/"+e+"."+{0:"f72dbb9d754b88a9e6e3",1:"b17200cccd46e216dcb3",2:"140338f6a5528feea1a3",3:"776d791724a8de12ff9e",4:"f8494b8dd039413f79c8",5:"530a43b5ad6055214539",6:"8f85de06573e2a5f9562",7:"061807fe4716131f26f8",8:"d1391c270de5a9f111c5",9:"cbdb7fa4f5180acfbb03",10:"7eeaa94fd42d34a86b92",11:"096c0f0eaf2850056b7e",12:"cea57d271a961f0b44ad",13:"4d2138ee1bee3ad573f4",14:"429592868e75adc95933",15:"3b3f0c03ff4fed9903cc",16:"9616cfe0a4f7517b0841",17:"b4bc5fa31e227bee8651",18:"5e7f065a8d031847e833",19:"3936346cb7e30aa279e2",20:"5ef9c751035ee9a08f94",21:"d8007e7169c085e13dab"}[e]+".js";var f=setTimeout(d,12e4);function d(){c.onerror=c.onload=null,clearTimeout(f);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return c.onerror=c.onload=d,o.appendChild(c),r},a.m=e,a.c=r,a.d=function(e,n,r){a.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},a.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="/",a.oe=function(e){throw console.error(e),e}}([]);
//# sourceMappingURL=manifest.075ed85199204f860c2e.js.map //# sourceMappingURL=manifest.37da822ab10e62d568da.js.map
\ No newline at end of file \ No newline at end of file
...@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableId; ...@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; 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.dto.OutParam; import com.gitee.sqlrest.common.dto.OutParam;
import com.gitee.sqlrest.common.enums.CacheKeyTypeEnum;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum; import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
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;
...@@ -78,7 +79,7 @@ public class ApiAssignmentEntity { ...@@ -78,7 +79,7 @@ public class ApiAssignmentEntity {
@TableField(value = "naming_strategy", typeHandler = EnumTypeHandler.class) @TableField(value = "naming_strategy", typeHandler = EnumTypeHandler.class)
private NamingStrategyEnum namingStrategy; private NamingStrategyEnum namingStrategy;
@TableField(value = "flow_status") @TableField("flow_status")
private Boolean flowStatus; private Boolean flowStatus;
@TableField("flow_grade") @TableField("flow_grade")
...@@ -87,6 +88,15 @@ public class ApiAssignmentEntity { ...@@ -87,6 +88,15 @@ public class ApiAssignmentEntity {
@TableField("flow_count") @TableField("flow_count")
private Integer flowCount; private Integer flowCount;
@TableField(value = "cache_key_type", typeHandler = EnumTypeHandler.class)
private CacheKeyTypeEnum cacheKeyType;
@TableField("cache_key_expr")
private String cacheKeyExpr;
@TableField("cache_expire_seconds")
private Long cacheExpireSeconds;
@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