Commit 5c7245ac by inrgihc

接口出参格式可配置

parent 543350cb
# SQLREST
![SQLREST](https://gitee.com/inrgihc/sqlrest/raw/master/sqlrest-manager-ui/src/assets/LOGO.png#pic_center)
> 将数据库的SQL生成RESTful风格的http接口的工具
## 一、工具介绍
......@@ -33,15 +35,18 @@
- Greenplum(需使用PostgreSQL类型)
- IBM的DB2
- Sybase数据库
- 国产达梦数据库DMDB
- 国产达梦数据库DM
- 国产人大金仓数据库Kingbase8
- 国产翰高数据库HighGo
- 国产神通数据库Oscar
- 国产南大通用数据库GBase8a
- Apache Hive
- SQLite3
- OpenGuass
- OpenGauss
- ClickHouse
- Apache Doris
- StarRocks
- OceanBase
### 3、模块结构功能
......
docs/images/003.PNG

83.2 KB | W: | H:

docs/images/003.PNG

63.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
......@@ -153,6 +153,12 @@
<version>3.0.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</dependencyManagement>
......
......@@ -38,6 +38,12 @@
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-eureka-one</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.gitee.sqlrest.cache;
import java.util.Map;
public interface CacheFactory {
<T> Map<String, T> getCacheMap(String key);
}
package com.gitee.sqlrest.cache;
import com.gitee.sqlrest.common.consts.Constants;
import com.hazelcast.config.Config;
import com.hazelcast.eureka.one.EurekaOneDiscoveryStrategyFactory;
import com.netflix.discovery.EurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HazelcastCacheConfig {
@Bean
public Config hazelcastCacheConfigFromEureka(EurekaClient eurekaClient) {
EurekaOneDiscoveryStrategyFactory.setEurekaClient(eurekaClient);
Config config = new Config();
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
config.getNetworkConfig().getJoin().getEurekaConfig()
.setEnabled(true)
.setProperty("self-registration", "true")
.setProperty("namespace", "hazelcast")
.setProperty("use-metadata-for-host-and-port", "true")
.setProperty("skip-eureka-registration-verification", "true");
config.getMapConfig(Constants.CACHE_KEY_TOKEN_CLIENT)
.setTimeToLiveSeconds(Constants.CLIENT_TOKEN_DURATION_SECONDS.intValue());
return config;
}
}
package com.gitee.sqlrest.cache;
import com.gitee.sqlrest.cache.hazelcast.HazelcastCacheFactory;
import com.gitee.sqlrest.cache.redis.JedisClient;
import com.gitee.sqlrest.cache.redis.RedisCacheFactory;
import com.gitee.sqlrest.cache.redis.RedisProperties;
import com.gitee.sqlrest.common.consts.Constants;
import com.hazelcast.config.Config;
import com.hazelcast.eureka.one.EurekaOneDiscoveryStrategyFactory;
import com.netflix.discovery.EurekaClient;
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 redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class SqlrestCacheConfiguration {
@Configuration
@ConditionalOnProperty(value = "sqlrest.cache.hazelcast.enabled", havingValue = "true")
static class HazelcastCacheConfig {
@Bean
public Config hazelcastCacheConfigFromEureka(EurekaClient eurekaClient) {
EurekaOneDiscoveryStrategyFactory.setEurekaClient(eurekaClient);
Config config = new Config();
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
config.getNetworkConfig().getJoin().getEurekaConfig()
.setEnabled(true)
.setProperty("self-registration", "true")
.setProperty("namespace", "hazelcast")
.setProperty("use-metadata-for-host-and-port", "true")
.setProperty("skip-eureka-registration-verification", "true");
config.getMapConfig(Constants.CACHE_KEY_TOKEN_CLIENT)
.setTimeToLiveSeconds(Constants.CLIENT_TOKEN_DURATION_SECONDS.intValue());
return config;
}
@Bean
public CacheFactory hazelcastCacheFactory() {
return new HazelcastCacheFactory();
}
}
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
@ConditionalOnProperty(value = "sqlrest.cache.redis.enabled", havingValue = "true")
static class RedisCacheConfig {
@Bean
public JedisPool jedisPool(RedisProperties properties) {
RedisProperties.Pool pool = properties.getPool();
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(pool.getMaxActive());
poolConfig.setMaxIdle(pool.getMaxIdle());
poolConfig.setMinIdle(pool.getMinIdle());
if (pool.getTimeBetweenEvictionRuns() != null) {
poolConfig.setTimeBetweenEvictionRunsMillis(pool.getTimeBetweenEvictionRuns().toMillis());
}
if (pool.getMaxWait() != null) {
poolConfig.setMaxWaitMillis(pool.getMaxWait().toMillis());
}
return new JedisPool(poolConfig, properties.getHost(),
properties.getPort(), (int) properties.getTimeout().toMillis(),
properties.getUsername(), properties.getPassword(),
properties.getDatabase(), properties.isSsl());
}
@Bean
public JedisClient jedisClient(JedisPool jedisPool) {
return new JedisClient(jedisPool);
}
@Bean
public CacheFactory redisCacheFactory() {
return new RedisCacheFactory();
}
}
}
package com.gitee.sqlrest.cache;
package com.gitee.sqlrest.cache.hazelcast;
import com.gitee.sqlrest.cache.CacheFactory;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class HazelcastCacheFactory {
public class HazelcastCacheFactory implements CacheFactory {
@Resource
private HazelcastInstance hazelcastInstance;
public <T> IMap<String, T> getCacheMap(String key) {
@Override
public <T> Map<String, T> getCacheMap(String key) {
return hazelcastInstance.getMap(key);
}
......
package com.gitee.sqlrest.cache.redis;
import java.util.function.Consumer;
import java.util.function.Function;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class JedisClient {
private JedisPool jedisPool;
public JedisClient(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
private Jedis getJedis() {
Jedis jedis = this.jedisPool.getResource();
jedis.ping();
return jedis;
}
public <T> T doAction(Function<Jedis, T> function) {
Jedis jedis = getJedis();
try {
return function.apply(jedis);
} finally {
jedis.close();
}
}
public void doConsume(Consumer<Jedis> action) {
Jedis jedis = getJedis();
try {
action.accept(jedis);
} finally {
jedis.close();
}
}
}
package com.gitee.sqlrest.cache.redis;
import com.gitee.sqlrest.cache.CacheFactory;
import java.util.Map;
import javax.annotation.Resource;
public class RedisCacheFactory implements CacheFactory {
@Resource
private JedisClient jedisClient;
@Override
public <T> Map<String, T> getCacheMap(String key) {
return new RedisCacheMap<>(key, jedisClient);
}
}
package com.gitee.sqlrest.cache.redis;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.json.JSONUtil;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class RedisCacheMap<V> implements Map<String, V> {
private final String hashTableKey;
final private JedisClient jedisClient;
public RedisCacheMap(String hashTableKey, JedisClient jedisClient) {
this.hashTableKey = hashTableKey;
this.jedisClient = jedisClient;
}
@Override
public int size() {
return jedisClient.doAction(
jedis -> jedis.hgetAll(hashTableKey).size()
);
}
@Override
public boolean isEmpty() {
return 0 == size();
}
@Override
public boolean containsKey(Object o) {
return jedisClient.doAction(
jedis -> jedis.hexists(hashTableKey, o.toString())
);
}
@Override
public boolean containsValue(Object o) {
return false;
}
@Override
public V get(Object o) {
return jedisClient.doAction(
jedis -> {
String value = jedis.hget(hashTableKey, o.toString());
return JSONUtil.toBean(value, new TypeReference<V>() {
}, true);
}
);
}
@Override
public V put(String k, V v) {
return jedisClient.doAction(
jedis -> {
String value = jedis.hget(hashTableKey, k);
jedis.hset(hashTableKey, k, JSONUtil.toJsonStr(v));
return JSONUtil.toBean(value, new TypeReference<V>() {
}, true);
}
);
}
@Override
public V remove(Object o) {
return jedisClient.doAction(
jedis -> {
String value = jedis.hget(hashTableKey, o.toString());
jedis.hdel(hashTableKey, o.toString());
return JSONUtil.toBean(value, new TypeReference<V>() {
}, true);
}
);
}
@Override
public void putAll(Map<? extends String, ? extends V> map) {
Map<String, String> values = new HashMap<>();
map.forEach((k, v) -> values.put(k, JSONUtil.toJsonStr(v)));
jedisClient.doConsume(
jedis -> jedis.hmset(hashTableKey, values)
);
}
@Override
public void clear() {
jedisClient.doConsume(
jedis -> jedis.hmset(hashTableKey, Collections.emptyMap())
);
}
@Override
public Set<String> keySet() {
return jedisClient.doAction(
jedis -> jedis.hkeys(hashTableKey)
);
}
@Override
public Collection<V> values() {
return Collections.emptyList();
}
@Override
public Set<Entry<String, V>> entrySet() {
return Collections.emptySet();
}
}
package com.gitee.sqlrest.cache.redis;
import java.time.Duration;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "sqlrest.cache.redis")
public class RedisProperties {
@Data
public static class Pool {
private int maxIdle = 8;
private int minIdle = 0;
private int maxActive = 8;
private Duration maxWait = Duration.ofMillis(-1L);
private Duration timeBetweenEvictionRuns;
}
private boolean enabled = false;
private int database = 0;
private String host = "127.0.0.1";
private String username;
private String password;
private int port = 6379;
private boolean ssl = false;
private Duration timeout = Duration.ofSeconds(1);
private Duration connectTimeout = Duration.ofSeconds(1);
private String clientName = "sqlrest";
private Pool pool;
}
package com.gitee.sqlrest.common.dto;
import com.gitee.sqlrest.common.enums.ParamLocationEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
......@@ -16,6 +17,9 @@ public class ItemParam {
@ApiModelProperty("参数名")
private String name;
@ApiModelProperty("参数位置")
private ParamLocationEnum location;
@ApiModelProperty("参数类型")
private ParamTypeEnum type;
......
......@@ -39,4 +39,11 @@ public enum DataTypeFormatEnum {
public int getNumberScale() {
return numberScale;
}
public String getDefault() {
if (numberScale > 0) {
return String.valueOf(numberScale);
}
return defaultPattern;
}
}
package com.gitee.sqlrest.common.enums;
import cn.hutool.core.util.StrUtil;
import java.util.function.Function;
public enum NamingStrategyEnum {
LOWER_CAMEL_CASE("属性名转换为小驼峰命名"),
UPPER_CAMEL_CASE("属性名转换为大驼峰命名"),
SNAKE_CASE("属性名转换为蛇形命名"),
LOWER_CASE("属性名转换为小写字母"),
NONE(Function.identity(), "无转换"),
CAMEL_CASE(StrUtil::toCamelCase, "属性名转换为驼峰命名"),
SNAKE_CASE(StrUtil::toUnderlineCase, "属性名转换为蛇形命名"),
LOWER_CASE(String::toLowerCase, "属性名转换为小写字母"),
UPPER_CASE(String::toUpperCase, "属性名转换为大写字母"),
;
private Function<String, String> function;
private String description;
NamingStrategyEnum(String description) {
NamingStrategyEnum(Function<String, String> function, String description) {
this.function = function;
this.description = description;
}
public Function<String, String> getFunction() {
return function;
}
public String getDescription() {
return description;
}
......
package com.gitee.sqlrest.common.enums;
public enum ParamLocationEnum {
REQUEST_HEADER("请求头"),
REQUEST_BODY("请求体"),
FORM_DATA("表单数据"),
;
private String name;
ParamLocationEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
......@@ -123,7 +123,8 @@ public enum ProductTypeEnum {
"jdbc:db2://172.17.2.10:50000/testdb:driverType=4;fullyMaterializeLobData=true;fullyMaterializeInputStreams=true;progressiveStreaming=2;progresssiveLocators=2;")
.sqlSchemaList("SELECT SCHEMANAME FROM SYSCAT.SCHEMATA ")
.adapter(database -> Pair.of(null, database))
.pageSql("SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS ROW_ID FROM ( %s ) AS TMP_PAGE) TMP_PAGE WHERE ROW_ID BETWEEN ? AND ?")
.pageSql(
"SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS ROW_ID FROM ( %s ) AS TMP_PAGE) TMP_PAGE WHERE ROW_ID BETWEEN ? AND ?")
.build()),
/**
......@@ -297,7 +298,68 @@ public enum ProductTypeEnum {
.sqlSchemaList("SELECT schema_name FROM information_schema.schemata ")
.adapter(database -> Pair.of(null, database))
.pageSql("select * from (%s) alias limit ?, ? ")
.build());
.build()),
/**
* Doris数据库类型
*/
DORIS(
ProductContext.builder()
.id(16)
.quote("`")
.name("doris")
.driver("com.mysql.jdbc.Driver")
.defaultPort(3306)
.testSql("/* ping */ SELECT 1")
.urlPrefix("jdbc:mysql://")
.tplUrls(new String[]{"jdbc:mysql://{host}[:{port}]/[{database}][\\?{params}]"})
.urlSample(
"jdbc:mysql://172.17.2.10:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&tinyInt1isBit=false&rewriteBatchedStatements=true&useCompression=true")
.sqlSchemaList("SELECT `SCHEMA_NAME` FROM `information_schema`.`SCHEMATA`")
.adapter(database -> Pair.of(database, null))
.pageSql("select * from (%s) alias limit ?, ? ")
.build()),
/**
* StarRocks数据库类型
*/
STARROCKS(
ProductContext.builder()
.id(17)
.quote("`")
.name("starrocks")
.driver("com.mysql.jdbc.Driver")
.defaultPort(3306)
.testSql("/* ping */ SELECT 1")
.urlPrefix("jdbc:mysql://")
.tplUrls(new String[]{"jdbc:mysql://{host}[:{port}]/[{database}][\\?{params}]"})
.urlSample(
"jdbc:mysql://172.17.2.10:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&tinyInt1isBit=false&rewriteBatchedStatements=true&useCompression=true")
.sqlSchemaList("SELECT `SCHEMA_NAME` FROM `information_schema`.`SCHEMATA`")
.adapter(database -> Pair.of(database, null))
.pageSql("select * from (%s) alias limit ?, ? ")
.build()),
/**
* OceanBase数据库类型
*/
OCEANBASE(
ProductContext.builder()
.id(18)
.quote("`")
.name("oceanbase")
.driver("com.oceanbase.jdbc.Driver")
.defaultPort(2881)
.testSql("/* ping */ SELECT 1")
.urlPrefix("jdbc:oceanbase://")
.tplUrls(new String[]{"jdbc:oceanbase://{host}[:{port}]/[{database}][\\?{params}]"})
.urlSample(
"jdbc:oceanbase://127.0.0.1:2881/test?pool=false&useUnicode=true&characterEncoding=utf-8&useSSL=false")
.sqlSchemaList("SELECT `SCHEMA_NAME` FROM `information_schema`.`SCHEMATA`")
.adapter(database -> Pair.of(database, null))
.pageSql("select * from (%s) alias limit ?, ? ")
.build()),
;
private ProductContext context;
......@@ -325,6 +387,10 @@ public enum ProductTypeEnum {
return this.context.getTplUrls();
}
public String getTestSql() {
return this.context.getTestSql();
}
public String getSample() {
return this.context.getUrlSample();
}
......
......@@ -47,6 +47,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -2,6 +2,7 @@ package com.gitee.sqlrest.core.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.persistence.entity.ApiContextEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
......@@ -35,6 +36,12 @@ public class ApiAssignmentDetailResponse extends ApiAssignmentBaseResponse {
@ApiModelProperty("SQL列表")
private List<ApiContextEntity> sqlList;
@ApiModelProperty("接口出参数据类型转换格式")
private List<DataTypeFormatMapValue> formatMap;
@ApiModelProperty("接口出参属性命名策略")
private NamingStrategyEnum namingStrategy;
@ApiModelProperty("是否开启流量控制")
private Boolean flowStatus;
......
package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.NoArgsConstructor;
......@@ -50,9 +53,15 @@ public class ApiAssignmentSaveRequest {
@ApiModelProperty("SQL列表")
private List<String> contextList;
@ApiModelProperty("接口入参")
@ApiModelProperty("接口入参列表")
private List<ItemParam> params;
@ApiModelProperty("接口出参数据类型转换格式")
private List<DataTypeFormatMapValue> formatMap;
@ApiModelProperty("接口出参属性命名策略")
private NamingStrategyEnum namingStrategy;
@ApiModelProperty("是否开启流量控制")
private Boolean flowStatus;
......
package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.dto.ParamValue;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.NoArgsConstructor;
......@@ -23,7 +21,7 @@ public class ApiDebugExecuteRequest {
private ExecuteEngineEnum engine;
@ApiModelProperty("数据类型转换格式")
private Map<DataTypeFormatEnum, String> formatMap;
private List<DataTypeFormatMapValue> formatMap;
@ApiModelProperty("属性命名策略")
private NamingStrategyEnum namingStrategy;
......
package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DataTypeFormatMapValue {
private DataTypeFormatEnum key;
private String value;
private String remark;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@Data
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("枚举键值")
public class NameValueBaseResponse {
@ApiModelProperty("枚举至")
private Enum key;
@ApiModelProperty("说明")
private String value;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@Data
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("带说明的枚举键值")
public class NameValueRemarkResponse extends NameValueBaseResponse {
@ApiModelProperty("注释")
private String remark;
}
package com.gitee.sqlrest.core.exec;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.IoUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.dto.ResultEntity;
import com.gitee.sqlrest.common.enums.ParamLocationEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import com.gitee.sqlrest.common.exception.ResponseErrorCode;
import com.gitee.sqlrest.core.driver.DriverLoadService;
......@@ -10,19 +15,24 @@ import com.gitee.sqlrest.core.util.DataSourceUtils;
import com.gitee.sqlrest.persistence.dao.DataSourceDao;
import com.gitee.sqlrest.persistence.entity.ApiAssignmentEntity;
import com.gitee.sqlrest.persistence.entity.DataSourceEntity;
import com.google.common.base.Charsets;
import com.zaxxer.hikari.HikariDataSource;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@Slf4j
......@@ -34,57 +44,92 @@ public class ApiExecuteService {
@Resource
private DriverLoadService driverLoadService;
public ResultEntity<Object> execute(ApiAssignmentEntity config, HttpServletRequest request,
HttpServletResponse response) {
DataSourceEntity dsEntity = dataSourceDao.getById(config.getDatasourceId());
if (null == dsEntity) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
String message = "datasource[id=" + config.getDatasourceId() + " not exist!";
log.warn("Error for handle api[id={}],information:{}", config.getId(), message);
return ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, message);
}
Map<String, Object> paramValues = obtainParameterValues(request, config.getParams());
File driverPath = driverLoadService.getVersionDriverFile(dsEntity.getType(), dsEntity.getVersion());
HikariDataSource dataSource = DataSourceUtils.getHikariDataSource(dsEntity, driverPath.getAbsolutePath());
Object result = ApiExecutorEngineFactory
.getExecutor(config.getEngine(), dataSource, dsEntity.getType())
.execute(config.getContextList(), paramValues);
if (result instanceof Collection) {
Collection r = (Collection) result;
return ResultEntity.success(config.getContextList().size() == 1 ? r.stream().findFirst().get() : r);
public ResultEntity<Object> execute(ApiAssignmentEntity config, HttpServletRequest request) {
try {
DataSourceEntity dsEntity = dataSourceDao.getById(config.getDatasourceId());
if (null == dsEntity) {
String message = "datasource[id=" + config.getDatasourceId() + " not exist!";
log.warn("Error for handle api[id={}],information:{}", config.getId(), message);
return ResultEntity.failed(ResponseErrorCode.ERROR_RESOURCE_NOT_EXISTS, message);
}
Map<String, Object> paramValues = obtainParameterValues(request, config.getParams());
File driverPath = driverLoadService.getVersionDriverFile(dsEntity.getType(), dsEntity.getVersion());
HikariDataSource dataSource = DataSourceUtils.getHikariDataSource(dsEntity, driverPath.getAbsolutePath());
Object result = ApiExecutorEngineFactory
.getExecutor(config.getEngine(), dataSource, dsEntity.getType())
.execute(config.getContextList(), paramValues, config.getNamingStrategy());
if (result instanceof Collection) {
Collection r = (Collection) result;
return ResultEntity.success(config.getContextList().size() == 1 ? r.stream().findFirst().get() : r);
}
return ResultEntity.success(result);
} catch (Throwable t) {
return ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, ExceptionUtil.getMessage(t));
}
return ResultEntity.success(result);
}
private Map<String, Object> obtainParameterValues(HttpServletRequest request, List<ItemParam> params) {
Map<String, Object> map = new HashMap<>();
if (null != params && params.size() > 0) {
Map<String, Object> bodyMap = getRequestBodyMap(request);
for (ItemParam param : params) {
String name = param.getName();
ParamTypeEnum type = param.getType();
boolean isArray = Optional.ofNullable(param.getIsArray()).orElse(false);
Boolean required = Optional.ofNullable(param.getRequired()).orElse(false);
ParamLocationEnum location = param.getLocation();
String defaultValue = param.getDefaultValue();
if (isArray) {
String[] values = request.getParameterValues(name);
if (null != values && values.length > 0) {
List list = Arrays.asList(values).stream()
.map(v -> type.getConverter().apply(v))
.collect(Collectors.toList());
map.put(name, list);
} else {
map.put(name, null);
}
if (location == ParamLocationEnum.REQUEST_HEADER) {
map.put(name, request.getHeader(name));
} else if (location == ParamLocationEnum.REQUEST_BODY) {
map.put(name, bodyMap.get(name));
} else {
String value = request.getParameter(name);
if (!required && null == value) {
value = defaultValue;
boolean isArray = Optional.ofNullable(param.getIsArray()).orElse(false);
Boolean required = Optional.ofNullable(param.getRequired()).orElse(false);
if (isArray) {
String[] values = request.getParameterValues(name);
if (null != values && values.length > 0) {
List list = Arrays.asList(values).stream()
.map(v -> type.getConverter().apply(v))
.collect(Collectors.toList());
map.put(name, list);
} else {
map.put(name, null);
}
} else {
String value = request.getParameter(name);
if (!required && null == value) {
value = defaultValue;
}
map.put(name, type.getConverter().apply(value));
}
map.put(name, type.getConverter().apply(value));
}
}
}
return map;
}
public Map<String, Object> getRequestBodyMap(HttpServletRequest request) {
ObjectMapper mapper = new ObjectMapper();
try {
String jsonString = IoUtil.read(request.getInputStream(), Charsets.UTF_8);
if (StringUtils.isBlank(jsonString)) {
return Collections.emptyMap();
}
Map<String, Object> resultMap = new HashMap<>();
JsonNode rootNode = mapper.readTree(jsonString);
if (!rootNode.isContainerNode()) {
return Collections.emptyMap();
}
Iterator<Entry<String, JsonNode>> fields = rootNode.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> entry = fields.next();
JsonNode jsonNode = entry.getValue();
Object value = mapper.convertValue(jsonNode, Object.class);
resultMap.put(entry.getKey(), value);
}
return resultMap;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package com.gitee.sqlrest.core.exec.engine;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.persistence.entity.ApiContextEntity;
import java.util.List;
import java.util.Map;
public interface ApiExecutorEngine {
Object execute(List<ApiContextEntity> scripts, Map<String, Object> params);
Object execute(List<ApiContextEntity> scripts, Map<String, Object> params, NamingStrategyEnum strategy);
}
package com.gitee.sqlrest.core.exec.engine.impl;
import cn.hutool.extra.spring.SpringUtil;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.core.dto.ScriptEditorCompletion;
import com.gitee.sqlrest.core.exec.annotation.Module;
......@@ -86,9 +87,9 @@ public class ScriptExecutorService extends AbstractExecutorEngine {
}
@Override
public Object execute(List<ApiContextEntity> scripts, Map<String, Object> params) {
public Object execute(List<ApiContextEntity> scripts, Map<String, Object> params, NamingStrategyEnum strategy) {
EnvVarModule envModule = SpringUtil.getBean(EnvVarModule.class);
DbVarModule dbModule = new DbVarModule(dataSource, productType, params);
DbVarModule dbModule = new DbVarModule(dataSource, productType, params, strategy);
List<Object> results = new ArrayList<>();
for (ApiContextEntity entity : scripts) {
......
......@@ -2,6 +2,7 @@ package com.gitee.sqlrest.core.exec.engine.impl;
import cn.hutool.core.util.NumberUtil;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.core.exec.engine.AbstractExecutorEngine;
import com.gitee.sqlrest.core.util.SqlJdbcUtils;
......@@ -25,7 +26,7 @@ public class SqlExecutorService extends AbstractExecutorEngine {
}
@Override
public Object execute(List<ApiContextEntity> scripts, Map<String, Object> params) {
public Object execute(List<ApiContextEntity> scripts, Map<String, Object> params, NamingStrategyEnum strategy) {
List<Object> dataList = new ArrayList<>();
Configuration cfg = new Configuration();
try (Connection connection = this.dataSource.getConnection()) {
......@@ -40,7 +41,7 @@ public class SqlExecutorService extends AbstractExecutorEngine {
int size = (null == params.get(Constants.PARAM_PAGE_SIZE))
? 10
: NumberUtil.parseInt(params.get(Constants.PARAM_PAGE_SIZE).toString());
dataList.add(SqlJdbcUtils.execute(connection, sqlMeta, page, size));
dataList.add(SqlJdbcUtils.execute(connection, sqlMeta, strategy, page, size));
}
connection.commit();
return dataList;
......
......@@ -2,9 +2,11 @@ package com.gitee.sqlrest.core.exec.module;
import cn.hutool.core.util.NumberUtil;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.core.exec.annotation.Comment;
import com.gitee.sqlrest.core.exec.annotation.Module;
import com.gitee.sqlrest.core.util.ConvertUtils;
import com.gitee.sqlrest.template.Configuration;
import com.gitee.sqlrest.template.SqlMeta;
import com.gitee.sqlrest.template.SqlTemplate;
......@@ -15,7 +17,9 @@ import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
......@@ -37,11 +41,26 @@ public class DbVarModule {
private JdbcTemplate jdbcTemplate;
private ProductTypeEnum productType;
private Map<String, Object> params;
private Function<String, String> converter;
public DbVarModule(DataSource dataSource, ProductTypeEnum productType, Map<String, Object> params) {
public DbVarModule(DataSource dataSource, ProductTypeEnum productType, Map<String, Object> params,
NamingStrategyEnum strategy) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.productType = productType;
this.params = params;
if (null == strategy) {
strategy = NamingStrategyEnum.NONE;
}
this.converter = strategy.getFunction();
}
private Map<String, Object> build(Map<String, Object> row) {
return ConvertUtils.to(row, converter);
}
private List<Map<String, Object>> build(List<Map<String, Object>> rows) {
return rows.stream().map(this::build).collect(Collectors.toList());
}
@Comment("查询所有的数据列表")
......@@ -49,7 +68,7 @@ public class DbVarModule {
log.info("Enter selectAll() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params);
return jdbcTemplate.queryForList(sqlMeta.getSql(), sqlMeta.getParameter().toArray());
return build(jdbcTemplate.queryForList(sqlMeta.getSql(), sqlMeta.getParameter().toArray()));
}
@Comment("count所有数据的总数")
......@@ -67,7 +86,7 @@ public class DbVarModule {
log.info("Enter selectOne() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params);
return jdbcTemplate
return build(jdbcTemplate
.query(sqlMeta.getSql(), new ResultSetExtractor<Map<String, Object>>() {
private ColumnMapRowMapper mapper = new ColumnMapRowMapper();
......@@ -79,7 +98,7 @@ public class DbVarModule {
return null;
}
},
sqlMeta.getParameter().toArray());
sqlMeta.getParameter().toArray()));
}
@Comment("分页查询数据列表")
......@@ -98,7 +117,7 @@ public class DbVarModule {
: NumberUtil.parseInt(params.get(Constants.PARAM_PAGE_SIZE).toString());
parameters.add(((page - 1) * size) < 0 ? 0 : (page - 1) * size);
parameters.add(size);
return jdbcTemplate.queryForList(pageSql, parameters.toArray());
return build(jdbcTemplate.queryForList(pageSql, parameters.toArray()));
}
@Comment("执行insert操作,返回插入主键")
......@@ -115,7 +134,7 @@ public class DbVarModule {
return ps;
},
keyHolder);
return keyHolder.getKeys();
return build(keyHolder.getKeys());
}
@Comment("执行update操作,返回受影响行数")
......
......@@ -5,6 +5,8 @@ import cn.hutool.core.exceptions.ExceptionUtil;
import com.gitee.sqlrest.common.dto.PageResult;
import com.gitee.sqlrest.common.dto.ParamValue;
import com.gitee.sqlrest.common.dto.ResultEntity;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.common.enums.OnOffEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import com.gitee.sqlrest.common.exception.CommonException;
......@@ -15,6 +17,8 @@ import com.gitee.sqlrest.core.dto.ApiAssignmentDetailResponse;
import com.gitee.sqlrest.core.dto.ApiAssignmentSaveRequest;
import com.gitee.sqlrest.core.dto.ApiDebugExecuteRequest;
import com.gitee.sqlrest.core.dto.AssignmentSearchRequest;
import com.gitee.sqlrest.core.dto.DataTypeFormatMapValue;
import com.gitee.sqlrest.core.dto.NameValueRemarkResponse;
import com.gitee.sqlrest.core.dto.ScriptEditorCompletion;
import com.gitee.sqlrest.core.dto.SqlParamParseResponse;
import com.gitee.sqlrest.core.exec.ApiExecuteService;
......@@ -35,8 +39,10 @@ import com.gitee.sqlrest.template.SqlTemplate;
import com.google.common.base.Charsets;
import com.zaxxer.hikari.HikariDataSource;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
......@@ -50,6 +56,7 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
......@@ -144,29 +151,34 @@ public class ApiAssignmentService {
}
}
if (null == request.getNamingStrategy()) {
request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE);
}
File driverPath = driverLoadService.getVersionDriverFile(dataSourceEntity.getType(), dataSourceEntity.getVersion());
ResultEntity entity;
try {
HikariDataSource dataSource = DataSourceUtils.getHikariDataSource(dataSourceEntity, driverPath.getAbsolutePath());
Object result = ApiExecutorEngineFactory
.getExecutor(request.getEngine(), dataSource, dataSourceEntity.getType())
.execute(scripts, params);
.execute(scripts, params, request.getNamingStrategy());
if (result instanceof Collection) {
Collection r = (Collection) result;
result = scripts.size() == 1 ? r.stream().findFirst().get() : r;
}
entity = ResultEntity.success(result);
response.setStatus(HttpServletResponse.SC_OK);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
entity = ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, ExceptionUtil.getMessage(e));
}
String json = JacksonUtils.toJsonStr(entity, request.getFormatMap(), request.getNamingStrategy());
try {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(Charsets.UTF_8.name());
response.getWriter().append(json);
response.getWriter().append(JacksonUtils.toJsonStr(entity, request.getFormatMap().stream()
.collect(Collectors.toMap(DataTypeFormatMapValue::getKey, DataTypeFormatMapValue::getValue, (a, b) -> a))));
} catch (Exception e) {
throw new RuntimeException(e);
}
......@@ -183,6 +195,10 @@ public class ApiAssignmentService {
if (CollectionUtils.isEmpty(request.getContextList())) {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "contextList");
}
if (null == request.getNamingStrategy()) {
request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE);
}
List<ApiContextEntity> contextList = getContextListEntity(request.getContextList());
ApiAssignmentEntity assignmentEntity = new ApiAssignmentEntity();
......@@ -199,6 +215,9 @@ public class ApiAssignmentService {
assignmentEntity.setEngine(request.getEngine());
assignmentEntity.setStatus(false);
assignmentEntity.setContextList(contextList);
assignmentEntity.setResponseFormat(request.getFormatMap().stream()
.collect(Collectors.toMap(DataTypeFormatMapValue::getKey, DataTypeFormatMapValue::getValue, (a, b) -> a)));
assignmentEntity.setNamingStrategy(request.getNamingStrategy());
assignmentEntity.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false));
assignmentEntity.setFlowGrade(request.getFlowGrade());
assignmentEntity.setFlowCount(request.getFlowCount());
......@@ -222,6 +241,10 @@ public class ApiAssignmentService {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "sqlTextList");
}
if (null == request.getNamingStrategy()) {
request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE);
}
List<ApiContextEntity> contextList = getContextListEntity(request.getContextList());
ApiAssignmentEntity assignmentEntity = new ApiAssignmentEntity();
......@@ -239,6 +262,9 @@ public class ApiAssignmentService {
assignmentEntity.setStatus(false);
assignmentEntity.setEngine(request.getEngine());
assignmentEntity.setContextList(contextList);
assignmentEntity.setResponseFormat(request.getFormatMap().stream()
.collect(Collectors.toMap(DataTypeFormatMapValue::getKey, DataTypeFormatMapValue::getValue, (a, b) -> a)));
assignmentEntity.setNamingStrategy(request.getNamingStrategy());
assignmentEntity.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false));
assignmentEntity.setFlowGrade(request.getFlowGrade());
assignmentEntity.setFlowCount(request.getFlowCount());
......@@ -255,15 +281,43 @@ public class ApiAssignmentService {
ApiAssignmentDetailResponse response = new ApiAssignmentDetailResponse();
BeanUtil.copyProperties(assignmentEntity, response);
response.setSqlList(assignmentEntity.getContextList());
List<DataTypeFormatMapValue> formatMap = new ArrayList<>();
for (Map.Entry<DataTypeFormatEnum, String> entry : assignmentEntity.getResponseFormat().entrySet()) {
formatMap.add(
DataTypeFormatMapValue.builder()
.key(entry.getKey())
.value(entry.getValue())
.remark(entry.getKey().getClassName())
.build());
}
response.setFormatMap(formatMap);
return response;
}
public ResultEntity testAssignment(Long id, HttpServletRequest request, HttpServletResponse response) {
public void testAssignment(Long id, HttpServletRequest request, HttpServletResponse response) {
ApiAssignmentEntity assignmentEntity = apiAssignmentDao.getById(id, true);
if (null == assignmentEntity) {
throw new CommonException(ResponseErrorCode.ERROR_RESOURCE_NOT_EXISTS, "id=" + id);
}
return apiExecuteService.execute(assignmentEntity, request, response);
String json;
ResultEntity result = apiExecuteService.execute(assignmentEntity, request);
if (0 != result.getCode()) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
json = JacksonUtils.toJsonStr(ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR));
} else {
response.setStatus(HttpServletResponse.SC_OK);
json = JacksonUtils.toJsonStr(result, assignmentEntity.getResponseFormat());
}
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(Charsets.UTF_8.name());
try {
response.getWriter().append(json);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void deleteAssignment(Long id) {
......
......@@ -3,7 +3,6 @@ package com.gitee.sqlrest.core.servlet;
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.enums.NamingStrategyEnum;
import com.gitee.sqlrest.common.exception.ResponseErrorCode;
import com.gitee.sqlrest.core.exec.ApiExecuteService;
import com.gitee.sqlrest.core.util.JacksonUtils;
......@@ -11,7 +10,6 @@ import com.gitee.sqlrest.persistence.dao.ApiAssignmentDao;
import com.gitee.sqlrest.persistence.entity.ApiAssignmentEntity;
import com.google.common.base.Charsets;
import java.io.IOException;
import java.util.Collections;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
......@@ -34,21 +32,19 @@ public class ApiServletService {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(Charsets.UTF_8.name());
String path = request.getRequestURI().substring(Constants.API_PATH_PREFIX.length() + 2);
String json = null;
ResultEntity result = ResultEntity.success();
ApiAssignmentEntity apiConfigEntity = apiAssignmentDao.getByUk(method, path);
if (null == apiConfigEntity || !apiConfigEntity.getStatus()) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
String message = String.format("/%s/%s[%s]", Constants.API_PATH_PREFIX, path, method.name());
ResultEntity result = ResultEntity.failed(ResponseErrorCode.ERROR_PATH_NOT_EXISTS, message);
json = JacksonUtils.toJsonStr(result, Collections.emptyMap(), null);
result = ResultEntity.failed(ResponseErrorCode.ERROR_PATH_NOT_EXISTS, message);
} else {
ResultEntity result = apiExecuteService.execute(apiConfigEntity, request, response);
if (0 != result.getCode()) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
json = JacksonUtils.toJsonStr(result, Collections.emptyMap(), NamingStrategyEnum.UPPER_CAMEL_CASE);
result = apiExecuteService.execute(apiConfigEntity, request);
}
if (0 != result.getCode()) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
String json = JacksonUtils.toJsonStr(result, apiConfigEntity.getResponseFormat());
response.getWriter().append(json);
}
......
package com.gitee.sqlrest.core.servlet;
import com.gitee.sqlrest.cache.HazelcastCacheFactory;
import com.gitee.sqlrest.cache.CacheFactory;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.dto.AccessToken;
import com.gitee.sqlrest.common.enums.DurationTimeEnum;
......@@ -14,7 +14,6 @@ import java.util.Map;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
......@@ -26,7 +25,7 @@ public class ClientTokenService {
@Resource
private AppClientDao appClientDao;
@Resource
private HazelcastCacheFactory hazelcastCacheFactory;
private CacheFactory cacheFactory;
@EventListener(ApplicationReadyEvent.class)
public void init() {
......@@ -52,7 +51,7 @@ public class ClientTokenService {
}
}
Map tokenClientMap = hazelcastCacheFactory.getCacheMap(Constants.CACHE_KEY_TOKEN_CLIENT);
Map tokenClientMap = cacheFactory.getCacheMap(Constants.CACHE_KEY_TOKEN_CLIENT);
tokenClientMap.put(appClient.getAccessToken(), clientToken);
}
}
......@@ -73,7 +72,7 @@ public class ClientTokenService {
.realName(appClient.getName())
.appKey(clientId)
.accessToken(token)
.createTimestamp(System.currentTimeMillis()/1000)
.createTimestamp(System.currentTimeMillis() / 1000)
.expireSeconds(Constants.CLIENT_TOKEN_DURATION_SECONDS)
.build();
if (DurationTimeEnum.TIME_VALUE.equals(appClient.getExpireDuration())) {
......@@ -93,7 +92,7 @@ public class ClientTokenService {
appClientDao.updateTokenByAppKey(clientId, token);
}
Map tokenClientMap = hazelcastCacheFactory.getCacheMap(Constants.CACHE_KEY_TOKEN_CLIENT);
Map tokenClientMap = cacheFactory.getCacheMap(Constants.CACHE_KEY_TOKEN_CLIENT);
tokenClientMap.put(token, clientToken);
return clientToken;
......@@ -103,7 +102,7 @@ public class ClientTokenService {
if (StringUtils.isBlank(tokenStr)) {
return null;
}
Map<String, AccessToken> tokenClientMap = hazelcastCacheFactory
Map<String, AccessToken> tokenClientMap = cacheFactory
.getCacheMap(Constants.CACHE_KEY_TOKEN_CLIENT);
AccessToken clientToken = tokenClientMap.get(tokenStr);
if (null == clientToken) {
......
package com.gitee.sqlrest.core.util;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
public class ConvertUtils {
public static Map<String, Object> to(Map<String, Object> row) {
return row;
}
public static Map<String, Object> to(Map<String, Object> row, Function<String, String> converter) {
if (null == converter) {
return row;
}
Map<String, Object> ret = new LinkedHashMap<>();
row.forEach((key, val) -> ret.put(converter.apply(key), val));
return ret;
}
}
package com.gitee.sqlrest.core.util;
import cn.hutool.core.util.ClassLoaderUtil;
import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.common.model.JarFileClassLoader;
import com.gitee.sqlrest.common.model.SimpleDataSource;
import com.gitee.sqlrest.persistence.entity.DataSourceEntity;
......@@ -60,18 +61,14 @@ public final class DataSourceUtils {
HikariDataSource ds = new HikariDataSource();
ds.setPoolName("The_JDBC_Connection");
ds.setJdbcUrl(properties.getUrl());
if (properties.getDriver().contains("oracle")) {
ds.setConnectionTestQuery("SELECT 'Hello' from DUAL");
if (ProductTypeEnum.ORACLE == properties.getType()) {
ds.setConnectionTestQuery(properties.getType().getTestSql());
// https://blog.csdn.net/qq_20960159/article/details/78593936
System.getProperties().setProperty("oracle.jdbc.J2EE13Compliant", "true");
// Oracle在通过jdbc连接的时候需要添加一个参数来设置是否获取注释
parameters.put("remarksReporting", "true");
} else if (properties.getDriver().contains("db2")) {
ds.setConnectionTestQuery("SELECT 1 FROM SYSIBM.SYSDUMMY1");
} else if (properties.getDriver().contains("mongodb")) {
ds.setConnectionTestQuery("use admin;");
} else if (!ds.getJdbcUrl().contains("jdbc:jest://")) {
ds.setConnectionTestQuery("SELECT 1");
} else if (StringUtils.isNotBlank(properties.getType().getTestSql())) {
ds.setConnectionTestQuery(properties.getType().getTestSql());
}
ds.setMaximumPoolSize(MAX_THREAD_COUNT);
ds.setMinimumIdle(MAX_THREAD_COUNT);
......
......@@ -3,12 +3,9 @@ package com.gitee.sqlrest.core.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.core.serdes.DateTimeSerDesFactory;
import java.util.Collections;
import java.util.Map;
......@@ -16,20 +13,13 @@ import java.util.Map;
public final class JacksonUtils {
public static String toJsonStr(Object obj) {
return toJsonStr(obj, Collections.emptyMap(), null);
return toJsonStr(obj, Collections.emptyMap());
}
public static String toJsonStr(Object obj, Map<DataTypeFormatEnum, String> formatMap, NamingStrategyEnum namingStrategy) {
public static String toJsonStr(Object obj, Map<DataTypeFormatEnum, String> formatMap) {
// https://www.jianshu.com/p/1368547350c6
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(createSerializeModule(formatMap));
if (null != namingStrategy) {
PropertyNamingStrategy strategy = createPropertyNamingStrategy(namingStrategy);
if (null != strategy) {
objectMapper.setPropertyNamingStrategy(strategy);
}
}
try {
return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
......@@ -37,20 +27,6 @@ public final class JacksonUtils {
}
}
private static PropertyNamingStrategy createPropertyNamingStrategy(NamingStrategyEnum namingStrategy) {
if (namingStrategy == NamingStrategyEnum.LOWER_CAMEL_CASE) {
return PropertyNamingStrategies.LOWER_CAMEL_CASE;
} else if (namingStrategy == NamingStrategyEnum.UPPER_CAMEL_CASE) {
return PropertyNamingStrategies.UPPER_CAMEL_CASE;
} else if (namingStrategy == NamingStrategyEnum.SNAKE_CASE) {
return PropertyNamingStrategies.SNAKE_CASE;
} else if (namingStrategy == NamingStrategyEnum.LOWER_CASE) {
return PropertyNamingStrategies.LOWER_CASE;
} else {
return null;
}
}
private static Module createSerializeModule(Map<DataTypeFormatEnum, String> formatMap) {
Map<DataTypeFormatEnum, String> finalFormatMap = (null == formatMap) ? Collections.emptyMap() : formatMap;
SimpleModule module = new SimpleModule();
......
package com.gitee.sqlrest.core.util;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.template.SqlMeta;
import java.sql.Connection;
import java.sql.PreparedStatement;
......@@ -9,6 +10,7 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
......@@ -16,7 +18,8 @@ import lombok.extern.slf4j.Slf4j;
@UtilityClass
public class SqlJdbcUtils {
public static Object execute(Connection connection, SqlMeta sqlMeta, int page, int size) throws SQLException {
public static Object execute(Connection connection, SqlMeta sqlMeta, NamingStrategyEnum strategy, int page, int size)
throws SQLException {
List<Object> paramValues = sqlMeta.getParameter();
PreparedStatement statement = connection.prepareStatement(sqlMeta.getSql());
statement.setQueryTimeout(300);
......@@ -25,6 +28,7 @@ public class SqlJdbcUtils {
statement.setObject(i, paramValues.get(i - 1));
}
log.info("ExecuteSQL:{}\n{}", sqlMeta.getSql(), paramValues);
Function<String, String> converter = (null == strategy) ? Function.identity() : strategy.getFunction();
if (statement.execute()) {
int skipNumber = size * (page - 1);
try (ResultSet rs = statement.getResultSet()) {
......@@ -45,7 +49,7 @@ public class SqlJdbcUtils {
}
}
if (skipNumber <= 0) {
list.add(row);
list.add(ConvertUtils.to(row, converter));
if (list.size() >= size) {
break;
}
......
package com.gitee.sqlrest.core;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.sqlrest.core.util.JacksonUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Test;
public class JacksonUtilsTest {
@Test
public void testToJsonStr001() {
Map<String, Object> result = new HashMap<>();
result.put("user_name", "test");
result.put("user_age", 23);
result.put("user_sex", 1);
String json = JacksonUtils.toJsonStr(result, Collections.emptyMap());
System.out.println(json);
}
@Test
public void testJsonStrToMap() throws JsonProcessingException {
String jsonString = "{\"user_sex\":1,\"user_name\":\"test\",\"user_age\":23}";
Map<String, Object> resultMap = new HashMap<>();
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonString);
Iterator<Entry<String, JsonNode>> fields = rootNode.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> entry = fields.next();
JsonNode jsonNode = entry.getValue();
Object value = mapper.convertValue(jsonNode, Object.class);
resultMap.put(entry.getKey(), value);
}
System.out.println(resultMap);
}
}
......@@ -13,6 +13,17 @@ spring:
validation-query: SELECT 1
test-on-borrow: true
sqlrest:
cache:
hazelcast:
enabled: true
redis:
enabled: false
host: 127.0.0.1
port: 6379
password: 123456
database: 0
mybatis:
configuration:
lazy-loading-enabled: true
......@@ -41,4 +52,4 @@ eureka:
datasource:
driver:
base-path: ${APP_DRIVERS_PATH}
base-path: ${APP_DRIVERS_PATH}
\ No newline at end of file
......@@ -46,6 +46,17 @@ spring:
allowed-methods: '*'
allowed-headers: "*"
sqlrest:
cache:
hazelcast:
enabled: true
redis:
enabled: false
host: 127.0.0.1
port: 6379
password: 123456
database: 0
mybatis:
configuration:
lazy-loading-enabled: true
......
......@@ -151,14 +151,14 @@
<template slot-scope="scope">
<el-input v-model="scope.row.name"
type="string"
:disabled=isOnlyShowDetail> </el-input>
:disabled="isOnlyShowDetail"> </el-input>
</template>
</el-table-column>
<el-table-column label="参数类型"
min-width="25%">
<template slot-scope="scope">
<el-select v-model="scope.row.type"
:disabled=isOnlyShowDetail>
:disabled="isOnlyShowDetail">
<el-option label='整型'
value='LONG'></el-option>
<el-option label='浮点型'
......@@ -176,7 +176,7 @@
min-width="25%">
<template slot-scope="scope">
<el-select v-model="scope.row.isArray"
:disabled=isOnlyShowDetail>
:disabled="isOnlyShowDetail">
<el-option label='是'
:value=true></el-option>
<el-option label='否'
......@@ -188,7 +188,7 @@
min-width="25%">
<template slot-scope="scope">
<el-select v-model="scope.row.required"
:disabled=isOnlyShowDetail>
:disabled="isOnlyShowDetail">
<el-option label='是'
:value=true></el-option>
<el-option label='否'
......@@ -201,7 +201,7 @@
<template slot-scope="scope">
<el-input v-model="scope.row.defaultValue"
type="string"
:disabled=isOnlyShowDetail></el-input>
:disabled="isOnlyShowDetail"></el-input>
</template>
</el-table-column>
<el-table-column label="描述"
......@@ -209,7 +209,7 @@
<template slot-scope="scope">
<el-input v-model="scope.row.remark"
type="string"
:disabled=isOnlyShowDetail></el-input>
:disabled="isOnlyShowDetail"></el-input>
</template>
</el-table-column>
<el-table-column label="操作"
......@@ -223,7 +223,7 @@
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="必要配置>>"
<el-tab-pane label="接口配置>>"
name="detail">
<el-row>
<el-col :span="12">
......@@ -233,7 +233,7 @@
:required=true
prop="path">
<el-input v-model="createParam.path"
:disabled=isOnlyShowDetail>
:disabled="isOnlyShowDetail">
<template slot="prepend">{{gatewayApiPrefix}}</template>
</el-input>
</el-form-item>
......@@ -245,7 +245,7 @@
:required=true
prop="method">
<el-select v-model="createParam.method"
:disabled=isOnlyShowDetail>
:disabled="isOnlyShowDetail">
<el-option label="GET"
value="GET"></el-option>
<el-option label="PUT"
......@@ -267,7 +267,7 @@
<el-input v-model="createParam.name"
auto-complete="off"
style="width:75%"
:disabled=isOnlyShowDetail></el-input>
:disabled="isOnlyShowDetail"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
......@@ -277,7 +277,7 @@
:required=true
prop="contentType">
<el-select v-model="createParam.contentType"
:disabled=isOnlyShowDetail>
:disabled="isOnlyShowDetail">
<el-option v-for="(item,index) in contentTypes"
:key="index"
:label="item"
......@@ -295,7 +295,7 @@
prop="module">
<el-select v-model="createParam.module"
placeholder="请选择"
:disabled=isOnlyShowDetail>
:disabled="isOnlyShowDetail">
<el-option v-for="(item,index) in moduleList"
:key="index"
:label="`[${item.id}]${item.name}`"
......@@ -311,7 +311,7 @@
prop="group">
<el-select v-model="createParam.group"
placeholder="请选择"
:disabled=isOnlyShowDetail>
:disabled="isOnlyShowDetail">
<el-option v-for="(item,index) in groupList"
:key="index"
:label="`[${item.id}]${item.name}`"
......@@ -333,6 +333,46 @@
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane label="出参格式>>"
name="outputParams">
<el-row>
<el-col :span="12">
<div>
<el-form-item label="命名策略"
label-width="80px"
prop="description"
style="width:100%">
<el-select v-model="createParam.namingStrategy"
placeholder="请选择"
:disabled="isOnlyShowDetail">
<el-option v-for="(item,index) in responseNamingStrategy"
:key="index"
:label="`[${item.key}]${item.value}`"
:value="`${item.key}`"></el-option>
</el-select>
</el-form-item>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="数据格式"
label-width="80px"
prop="formatMap"
style="width:100%">
<div v-for="item in createParam.formatMap"
:key="item.key"
v-bind="item">
{{item.remark}}:
<el-input type="text"
:key="item.key"
v-model="item.value"
:value="item.value"> </el-input>
</div>
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane label="流量控制"
name="flowControl">
<el-row>
......@@ -344,14 +384,14 @@
:inactive-value="false"
active-text="开启"
inactive-text="关闭"
:disabled=isOnlyShowDetail>
: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
:disabled="isOnlyShowDetail"
border>
<el-radio :label="1">QPS</el-radio>
<el-radio :label="0">并发线程数</el-radio>
......@@ -361,7 +401,7 @@
<el-input-number v-model="createParam.flowCount"
size="small"
:step="1"
:disabled=isOnlyShowDetail
:disabled="isOnlyShowDetail"
step-strictly></el-input-number>
</el-form-item>
</div>
......@@ -444,7 +484,7 @@
min-width="25%">
<template slot-scope="scope">
<el-select v-model="scope.row.isArray"
disabled="true">
:disabled="true">
<el-option label='是'
:value=true></el-option>
<el-option label='否'
......@@ -456,7 +496,7 @@
min-width="25%">
<template slot-scope="scope">
<el-select v-model="scope.row.required"
disabled="true">
:disabled="true">
<el-option label='是'
:value=true></el-option>
<el-option label='否'
......@@ -468,7 +508,7 @@
min-width="25%">
<template slot-scope="scope">
<el-input v-model="scope.row.remark"
disabled="true"
:disabled="true"
type="string"></el-input>
</template>
</el-table-column>
......@@ -544,6 +584,8 @@ export default {
sqls: [],
script: '',
open: false,
namingStrategy: 'CAMEL_CASE',
formatMap: null,
flowStatus: false,
flowGrade: 1,
flowCount: 5
......@@ -564,6 +606,8 @@ export default {
inputParams: [],
debugParams: [],
debugResponse: "",
responseNamingStrategy: [],
responseTypeFormat: [],
rules: {
name: [
{
......@@ -656,6 +700,8 @@ export default {
engine: detail.engine,
sqls: [],
script: "",
namingStrategy: detail.namingStrategy,
formatMap: detail.formatMap,
flowStatus: detail.flowStatus,
flowGrade: detail.flowGrade,
flowCount: detail.flowCount
......@@ -762,6 +808,28 @@ export default {
}
});
},
loadResponseNamingStrategy: function () {
this.$http.get(
"/sqlrest/manager/api/v1/assignment/response-naming-strategy"
).then(res => {
if (0 === res.data.code) {
this.responseNamingStrategy = res.data.data;
console.log(this.responseNamingStrategy)
}
});
},
loadResponseTypeFormat: function () {
this.$http.get(
"/sqlrest/manager/api/v1/assignment/response-type-format"
).then(res => {
if (0 === res.data.code) {
this.responseTypeFormat = res.data.data;
if (!this.createParam.formatMap) {
this.createParam.formatMap = res.data.data;
}
}
});
},
loadTreeData: function () {
if (this.createParam.dataSourceId && this.createParam.dataSourceId > 0 && this.showTree) {
this.treeData = []
......@@ -976,6 +1044,7 @@ export default {
this.inputParams.push(
{
name: item.name,
location: 'FORM_DATA',
type: "STRING",
isArray: item.isArray,
required: true,
......@@ -1001,6 +1070,7 @@ export default {
this.inputParams.push(
{
name: "",
location: 'FORM_DATA',
type: "STRING",
isArray: false,
required: true,
......@@ -1017,6 +1087,7 @@ export default {
{
name: "apiPageNum",
type: "LONG",
location: 'FORM_DATA',
isArray: false,
required: true,
defaultValue: "1",
......@@ -1030,6 +1101,7 @@ export default {
{
name: "apiPageSize",
type: "LONG",
location: 'FORM_DATA',
isArray: false,
required: true,
defaultValue: "10",
......@@ -1099,6 +1171,8 @@ export default {
contentType: this.createParam.contentType,
path: this.createParam.path,
open: this.createParam.open,
namingStrategy: this.createParam.namingStrategy,
formatMap: this.createParam.formatMap,
flowStatus: this.createParam.flowStatus,
flowGrade: this.createParam.flowGrade,
flowCount: this.createParam.flowCount,
......@@ -1137,6 +1211,8 @@ export default {
contentType: this.createParam.contentType,
path: this.createParam.path,
open: this.createParam.open,
namingStrategy: this.createParam.namingStrategy,
formatMap: this.createParam.formatMap,
flowStatus: this.createParam.flowStatus,
flowGrade: this.createParam.flowGrade,
flowCount: this.createParam.flowCount,
......@@ -1222,6 +1298,8 @@ export default {
data: JSON.stringify({
dataSourceId: this.createParam.dataSourceId,
engine: this.createParam.engine,
namingStrategy: this.createParam.namingStrategy,
formatMap: this.createParam.formatMap,
contextList: sqls,
paramValues: this.debugParams
})
......@@ -1246,6 +1324,8 @@ export default {
this.loadGateway();
this.loadKeywordHints();
this.loadTreeData();
this.loadResponseNamingStrategy();
this.loadResponseTypeFormat();
},
}
</script>
......
......@@ -24,12 +24,6 @@
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
<version>1.19.4</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
......
......@@ -3,13 +3,19 @@ package com.gitee.sqlrest.manager.controller;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.dto.PageResult;
import com.gitee.sqlrest.common.dto.ResultEntity;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.core.dto.ApiAssignmentBaseResponse;
import com.gitee.sqlrest.core.dto.ApiAssignmentSaveRequest;
import com.gitee.sqlrest.core.dto.ApiDebugExecuteRequest;
import com.gitee.sqlrest.core.dto.AssignmentSearchRequest;
import com.gitee.sqlrest.core.dto.NameValueBaseResponse;
import com.gitee.sqlrest.core.dto.NameValueRemarkResponse;
import com.gitee.sqlrest.core.service.ApiAssignmentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.Arrays;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
......@@ -38,6 +44,37 @@ public class ApiAssignmentController {
return ResultEntity.success(apiAssignmentService.completions());
}
@ApiOperation(value = "响应属性命名策略")
@GetMapping(value = "/response-naming-strategy", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultEntity responseNamingStrategy() {
return ResultEntity.success(
Arrays.stream(NamingStrategyEnum.values())
.map(
e ->
NameValueBaseResponse.builder()
.key(e)
.value(e.getDescription())
.build()
).collect(Collectors.toList())
);
}
@ApiOperation(value = "响应数据类型格式")
@GetMapping(value = "/response-type-format", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultEntity responseTypeFormat() {
return ResultEntity.success(
Arrays.stream(DataTypeFormatEnum.values())
.map(
e ->
NameValueRemarkResponse.builder()
.key(e)
.value(e.getDefault())
.remark(e.getClassName())
.build()
).collect(Collectors.toList())
);
}
@ApiOperation(value = "获取SQL中的入参列表")
@PostMapping(value = "/parse", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultEntity parse(@RequestParam("sql") String sql) {
......@@ -72,8 +109,8 @@ public class ApiAssignmentController {
@ApiOperation(value = "测试API执行")
@PostMapping(value = "/test/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultEntity test(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response) {
return apiAssignmentService.testAssignment(id, request, response);
public void test(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response) {
apiAssignmentService.testAssignment(id, request, response);
}
@ApiOperation(value = "删除API配置")
......
......@@ -19,6 +19,17 @@ spring:
table: SQLREST_SCHEMA_HISTORY
enabled: true
sqlrest:
cache:
hazelcast:
enabled: true
redis:
enabled: false
host: 127.0.0.1
port: 6379
password: 123456
database: 0
mybatis:
configuration:
lazy-loading-enabled: true
......
ALTER TABLE `SQLREST_API_ASSIGNMENT`
ADD COLUMN `response_format` tinytext NULL comment '响应格式配置' AFTER `engine`,
ADD COLUMN `naming_strategy` varchar(16) NOT NULL DEFAULT 'NONE' comment '命名策略' AFTER `response_format` ;
UPDATE SQLREST_API_ASSIGNMENT set response_format = '{"LOCAL_DATE":"yyyy-MM-dd","DATE":"yyyy-MM-dd","TIMESTAMP":"yyyy-MM-dd HH:mm","LOCAL_DATE_TIME":"yyyy-MM-dd HH:mm","TIME":"HH:mm:ss","BIG_DECIMAL":"6"}' where response_format is null;
<!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.b00ebac3d2add7487e4a6432cef8d975.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.255d24ba50ec0408e7ae.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
<!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.3cc3f3ced0962b332bb5c7f66f5a4311.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.038d1629b6d567190efe.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
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,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:"f553862d2c4a87a9b53f",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.255d24ba50ec0408e7ae.js.map
\ No newline at end of file
!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,a){for(var d,f,i,u=0,b=[];u<r.length;u++)f=r[u],t[f]&&b.push(t[f][0]),t[f]=0;for(d in c)Object.prototype.hasOwnProperty.call(c,d)&&(e[d]=c[d]);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:"04668914d5dbd2646823",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 d=setTimeout(f,12e4);function f(){a.onerror=a.onload=null,clearTimeout(d);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return a.onerror=a.onload=f,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.038d1629b6d567190efe.js.map
\ No newline at end of file
{"version":3,"sources":["webpack:///webpack/bootstrap adb620d4ba80680191bb"],"names":["parentJsonpFunction","window","chunkIds","moreModules","executeModules","moduleId","chunkId","result","i","resolves","length","installedChunks","push","Object","prototype","hasOwnProperty","call","modules","shift","__webpack_require__","s","installedModules","22","exports","module","l","e","installedChunkData","Promise","resolve","promise","reject","head","document","getElementsByTagName","script","createElement","type","charset","async","timeout","nc","setAttribute","src","p","0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","setTimeout","onScriptComplete","onerror","onload","clearTimeout","chunk","Error","undefined","appendChild","m","c","d","name","getter","o","defineProperty","configurable","enumerable","get","n","__esModule","object","property","oe","err","console","error"],"mappings":"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","file":"static/js/manifest.255d24ba50ec0408e7ae.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t22: 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId) {\n \t\tvar installedChunkData = installedChunks[chunkId];\n \t\tif(installedChunkData === 0) {\n \t\t\treturn new Promise(function(resolve) { resolve(); });\n \t\t}\n\n \t\t// a Promise means \"currently loading\".\n \t\tif(installedChunkData) {\n \t\t\treturn installedChunkData[2];\n \t\t}\n\n \t\t// setup Promise in chunk cache\n \t\tvar promise = new Promise(function(resolve, reject) {\n \t\t\tinstalledChunkData = installedChunks[chunkId] = [resolve, reject];\n \t\t});\n \t\tinstalledChunkData[2] = promise;\n\n \t\t// start chunk loading\n \t\tvar head = document.getElementsByTagName('head')[0];\n \t\tvar script = document.createElement('script');\n \t\tscript.type = \"text/javascript\";\n \t\tscript.charset = 'utf-8';\n \t\tscript.async = true;\n \t\tscript.timeout = 120000;\n\n \t\tif (__webpack_require__.nc) {\n \t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n \t\t}\n \t\tscript.src = __webpack_require__.p + \"static/js/\" + chunkId + \".\" + {\"0\":\"f553862d2c4a87a9b53f\",\"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\"}[chunkId] + \".js\";\n \t\tvar timeout = setTimeout(onScriptComplete, 120000);\n \t\tscript.onerror = script.onload = onScriptComplete;\n \t\tfunction onScriptComplete() {\n \t\t\t// avoid mem leaks in IE.\n \t\t\tscript.onerror = script.onload = null;\n \t\t\tclearTimeout(timeout);\n \t\t\tvar chunk = installedChunks[chunkId];\n \t\t\tif(chunk !== 0) {\n \t\t\t\tif(chunk) {\n \t\t\t\t\tchunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));\n \t\t\t\t}\n \t\t\t\tinstalledChunks[chunkId] = undefined;\n \t\t\t}\n \t\t};\n \t\thead.appendChild(script);\n\n \t\treturn promise;\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap adb620d4ba80680191bb"],"sourceRoot":""}
\ No newline at end of file
{"version":3,"sources":["webpack:///webpack/bootstrap e81ad5f15653e7ef6e65"],"names":["parentJsonpFunction","window","chunkIds","moreModules","executeModules","moduleId","chunkId","result","i","resolves","length","installedChunks","push","Object","prototype","hasOwnProperty","call","modules","shift","__webpack_require__","s","installedModules","22","exports","module","l","e","installedChunkData","Promise","resolve","promise","reject","head","document","getElementsByTagName","script","createElement","type","charset","async","timeout","nc","setAttribute","src","p","0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","setTimeout","onScriptComplete","onerror","onload","clearTimeout","chunk","Error","undefined","appendChild","m","c","d","name","getter","o","defineProperty","configurable","enumerable","get","n","__esModule","object","property","oe","err","console","error"],"mappings":"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","file":"static/js/manifest.038d1629b6d567190efe.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t22: 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId) {\n \t\tvar installedChunkData = installedChunks[chunkId];\n \t\tif(installedChunkData === 0) {\n \t\t\treturn new Promise(function(resolve) { resolve(); });\n \t\t}\n\n \t\t// a Promise means \"currently loading\".\n \t\tif(installedChunkData) {\n \t\t\treturn installedChunkData[2];\n \t\t}\n\n \t\t// setup Promise in chunk cache\n \t\tvar promise = new Promise(function(resolve, reject) {\n \t\t\tinstalledChunkData = installedChunks[chunkId] = [resolve, reject];\n \t\t});\n \t\tinstalledChunkData[2] = promise;\n\n \t\t// start chunk loading\n \t\tvar head = document.getElementsByTagName('head')[0];\n \t\tvar script = document.createElement('script');\n \t\tscript.type = \"text/javascript\";\n \t\tscript.charset = 'utf-8';\n \t\tscript.async = true;\n \t\tscript.timeout = 120000;\n\n \t\tif (__webpack_require__.nc) {\n \t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n \t\t}\n \t\tscript.src = __webpack_require__.p + \"static/js/\" + chunkId + \".\" + {\"0\":\"04668914d5dbd2646823\",\"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\"}[chunkId] + \".js\";\n \t\tvar timeout = setTimeout(onScriptComplete, 120000);\n \t\tscript.onerror = script.onload = onScriptComplete;\n \t\tfunction onScriptComplete() {\n \t\t\t// avoid mem leaks in IE.\n \t\t\tscript.onerror = script.onload = null;\n \t\t\tclearTimeout(timeout);\n \t\t\tvar chunk = installedChunks[chunkId];\n \t\t\tif(chunk !== 0) {\n \t\t\t\tif(chunk) {\n \t\t\t\t\tchunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));\n \t\t\t\t}\n \t\t\t\tinstalledChunks[chunkId] = undefined;\n \t\t\t}\n \t\t};\n \t\thead.appendChild(script);\n\n \t\treturn promise;\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap e81ad5f15653e7ef6e65"],"sourceRoot":""}
\ No newline at end of file
......@@ -6,12 +6,15 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import com.gitee.sqlrest.common.enums.OnOffEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.persistence.handler.FormatMapHandler;
import com.gitee.sqlrest.persistence.handler.ListParamHandler;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
......@@ -64,6 +67,12 @@ public class ApiAssignmentEntity {
@TableField(value = "engine", typeHandler = EnumTypeHandler.class)
private ExecuteEngineEnum engine;
@TableField(value = "response_format", typeHandler = FormatMapHandler.class)
private Map<DataTypeFormatEnum, String> responseFormat;
@TableField(value = "naming_strategy", typeHandler = EnumTypeHandler.class)
private NamingStrategyEnum namingStrategy;
@TableField(value = "flow_status")
private Boolean flowStatus;
......
package com.gitee.sqlrest.persistence.handler;
import com.fasterxml.jackson.core.type.TypeReference;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.persistence.util.JsonUtils;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
public class FormatMapHandler extends BaseTypeHandler<Map<DataTypeFormatEnum, String>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Map<DataTypeFormatEnum, String> value,
JdbcType jdbcType) throws SQLException {
ps.setString(i, map2string(value));
}
@Override
public Map<DataTypeFormatEnum, String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return string2map(rs.getString(columnName));
}
@Override
public Map<DataTypeFormatEnum, String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return string2map(rs.getString(columnIndex));
}
@Override
public Map<DataTypeFormatEnum, String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return string2map(cs.getString(columnIndex));
}
private String map2string(Map<DataTypeFormatEnum, String> map) {
if (map == null || map.isEmpty()) {
return null;
}
return JsonUtils.toJsonString(map);
}
private Map<DataTypeFormatEnum, String> string2map(String str) {
if (str == null || str.isEmpty()) {
return new HashMap<>(2);
}
return JsonUtils.toBeanType(str, new TypeReference<Map<DataTypeFormatEnum, String>>() {
});
}
}
package com.gitee.sqlrest.persistence.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collections;
......@@ -40,6 +41,19 @@ public class JsonUtils {
return null;
}
public static <T> T toBeanType(String jsonString, TypeReference<T> clazz) {
if (null != jsonString) {
try {
return jacksonMapper.readValue(jsonString, clazz);
} catch (JsonProcessingException e) {
String className = clazz.getType().getTypeName();
log.error(" parse json [{}] to class [{}] error:{}", jsonString, className, e);
throw new RuntimeException("parse json string to object error:" + e.getMessage());
}
}
return null;
}
public static <T> List<T> toBeanList(String jsonString, Class<T> clazz) {
if (null != jsonString) {
try {
......
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