Commit 5c7245ac by inrgihc

接口出参格式可配置

parent 543350cb
# SQLREST # SQLREST
![SQLREST](https://gitee.com/inrgihc/sqlrest/raw/master/sqlrest-manager-ui/src/assets/LOGO.png#pic_center)
> 将数据库的SQL生成RESTful风格的http接口的工具 > 将数据库的SQL生成RESTful风格的http接口的工具
## 一、工具介绍 ## 一、工具介绍
...@@ -33,15 +35,18 @@ ...@@ -33,15 +35,18 @@
- Greenplum(需使用PostgreSQL类型) - Greenplum(需使用PostgreSQL类型)
- IBM的DB2 - IBM的DB2
- Sybase数据库 - Sybase数据库
- 国产达梦数据库DMDB - 国产达梦数据库DM
- 国产人大金仓数据库Kingbase8 - 国产人大金仓数据库Kingbase8
- 国产翰高数据库HighGo - 国产翰高数据库HighGo
- 国产神通数据库Oscar - 国产神通数据库Oscar
- 国产南大通用数据库GBase8a - 国产南大通用数据库GBase8a
- Apache Hive - Apache Hive
- SQLite3 - SQLite3
- OpenGuass - OpenGauss
- ClickHouse - ClickHouse
- Apache Doris
- StarRocks
- OceanBase
### 3、模块结构功能 ### 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 @@ ...@@ -153,6 +153,12 @@
<version>3.0.8</version> <version>3.0.8</version>
</dependency> </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
......
...@@ -38,6 +38,12 @@ ...@@ -38,6 +38,12 @@
<groupId>com.hazelcast</groupId> <groupId>com.hazelcast</groupId>
<artifactId>hazelcast-eureka-one</artifactId> <artifactId>hazelcast-eureka-one</artifactId>
</dependency> </dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </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.core.HazelcastInstance;
import com.hazelcast.map.IMap; import java.util.Map;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component public class HazelcastCacheFactory implements CacheFactory {
public class HazelcastCacheFactory {
@Resource @Resource
private HazelcastInstance hazelcastInstance; private HazelcastInstance hazelcastInstance;
public <T> IMap<String, T> getCacheMap(String key) { @Override
public <T> Map<String, T> getCacheMap(String key) {
return hazelcastInstance.getMap(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; package com.gitee.sqlrest.common.dto;
import com.gitee.sqlrest.common.enums.ParamLocationEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum; import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
...@@ -16,6 +17,9 @@ public class ItemParam { ...@@ -16,6 +17,9 @@ public class ItemParam {
@ApiModelProperty("参数名") @ApiModelProperty("参数名")
private String name; private String name;
@ApiModelProperty("参数位置")
private ParamLocationEnum location;
@ApiModelProperty("参数类型") @ApiModelProperty("参数类型")
private ParamTypeEnum type; private ParamTypeEnum type;
......
...@@ -39,4 +39,11 @@ public enum DataTypeFormatEnum { ...@@ -39,4 +39,11 @@ public enum DataTypeFormatEnum {
public int getNumberScale() { public int getNumberScale() {
return numberScale; return numberScale;
} }
public String getDefault() {
if (numberScale > 0) {
return String.valueOf(numberScale);
}
return defaultPattern;
}
} }
package com.gitee.sqlrest.common.enums; package com.gitee.sqlrest.common.enums;
import cn.hutool.core.util.StrUtil;
import java.util.function.Function;
public enum NamingStrategyEnum { public enum NamingStrategyEnum {
LOWER_CAMEL_CASE("属性名转换为小驼峰命名"), NONE(Function.identity(), "无转换"),
UPPER_CAMEL_CASE("属性名转换为大驼峰命名"), CAMEL_CASE(StrUtil::toCamelCase, "属性名转换为驼峰命名"),
SNAKE_CASE("属性名转换为蛇形命名"), SNAKE_CASE(StrUtil::toUnderlineCase, "属性名转换为蛇形命名"),
LOWER_CASE("属性名转换为小写字母"), LOWER_CASE(String::toLowerCase, "属性名转换为小写字母"),
UPPER_CASE(String::toUpperCase, "属性名转换为大写字母"),
; ;
private Function<String, String> function;
private String description; private String description;
NamingStrategyEnum(String description) { NamingStrategyEnum(Function<String, String> function, String description) {
this.function = function;
this.description = description; this.description = description;
} }
public Function<String, String> getFunction() {
return function;
}
public String getDescription() { public String getDescription() {
return description; 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 { ...@@ -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;") "jdbc:db2://172.17.2.10:50000/testdb:driverType=4;fullyMaterializeLobData=true;fullyMaterializeInputStreams=true;progressiveStreaming=2;progresssiveLocators=2;")
.sqlSchemaList("SELECT SCHEMANAME FROM SYSCAT.SCHEMATA ") .sqlSchemaList("SELECT SCHEMANAME FROM SYSCAT.SCHEMATA ")
.adapter(database -> Pair.of(null, database)) .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()), .build()),
/** /**
...@@ -297,7 +298,68 @@ public enum ProductTypeEnum { ...@@ -297,7 +298,68 @@ public enum ProductTypeEnum {
.sqlSchemaList("SELECT schema_name FROM information_schema.schemata ") .sqlSchemaList("SELECT schema_name FROM information_schema.schemata ")
.adapter(database -> Pair.of(null, database)) .adapter(database -> Pair.of(null, database))
.pageSql("select * from (%s) alias limit ?, ? ") .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; private ProductContext context;
...@@ -325,6 +387,10 @@ public enum ProductTypeEnum { ...@@ -325,6 +387,10 @@ public enum ProductTypeEnum {
return this.context.getTplUrls(); return this.context.getTplUrls();
} }
public String getTestSql() {
return this.context.getTestSql();
}
public String getSample() { public String getSample() {
return this.context.getUrlSample(); return this.context.getUrlSample();
} }
......
...@@ -47,6 +47,12 @@ ...@@ -47,6 +47,12 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
...@@ -2,6 +2,7 @@ package com.gitee.sqlrest.core.dto; ...@@ -2,6 +2,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.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;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
...@@ -35,6 +36,12 @@ public class ApiAssignmentDetailResponse extends ApiAssignmentBaseResponse { ...@@ -35,6 +36,12 @@ public class ApiAssignmentDetailResponse extends ApiAssignmentBaseResponse {
@ApiModelProperty("SQL列表") @ApiModelProperty("SQL列表")
private List<ApiContextEntity> sqlList; private List<ApiContextEntity> sqlList;
@ApiModelProperty("接口出参数据类型转换格式")
private List<DataTypeFormatMapValue> formatMap;
@ApiModelProperty("接口出参属性命名策略")
private NamingStrategyEnum namingStrategy;
@ApiModelProperty("是否开启流量控制") @ApiModelProperty("是否开启流量控制")
private Boolean flowStatus; private Boolean flowStatus;
......
package com.gitee.sqlrest.core.dto; package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.dto.ItemParam; 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.ExecuteEngineEnum;
import com.gitee.sqlrest.common.enums.HttpMethodEnum; import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.util.List; import java.util.List;
import java.util.Map;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
...@@ -50,9 +53,15 @@ public class ApiAssignmentSaveRequest { ...@@ -50,9 +53,15 @@ public class ApiAssignmentSaveRequest {
@ApiModelProperty("SQL列表") @ApiModelProperty("SQL列表")
private List<String> contextList; private List<String> contextList;
@ApiModelProperty("接口入参") @ApiModelProperty("接口入参列表")
private List<ItemParam> params; private List<ItemParam> params;
@ApiModelProperty("接口出参数据类型转换格式")
private List<DataTypeFormatMapValue> formatMap;
@ApiModelProperty("接口出参属性命名策略")
private NamingStrategyEnum namingStrategy;
@ApiModelProperty("是否开启流量控制") @ApiModelProperty("是否开启流量控制")
private Boolean flowStatus; private Boolean flowStatus;
......
package com.gitee.sqlrest.core.dto; package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.dto.ParamValue; 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.ExecuteEngineEnum;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum; import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.util.List; import java.util.List;
import java.util.Map;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
...@@ -23,7 +21,7 @@ public class ApiDebugExecuteRequest { ...@@ -23,7 +21,7 @@ public class ApiDebugExecuteRequest {
private ExecuteEngineEnum engine; private ExecuteEngineEnum engine;
@ApiModelProperty("数据类型转换格式") @ApiModelProperty("数据类型转换格式")
private Map<DataTypeFormatEnum, String> formatMap; private List<DataTypeFormatMapValue> formatMap;
@ApiModelProperty("属性命名策略") @ApiModelProperty("属性命名策略")
private NamingStrategyEnum namingStrategy; 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; 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.ItemParam;
import com.gitee.sqlrest.common.dto.ResultEntity; 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.enums.ParamTypeEnum;
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;
...@@ -10,19 +15,24 @@ import com.gitee.sqlrest.core.util.DataSourceUtils; ...@@ -10,19 +15,24 @@ import com.gitee.sqlrest.core.util.DataSourceUtils;
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.google.common.base.Charsets;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional; import java.util.Optional;
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;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Slf4j @Slf4j
...@@ -34,57 +44,92 @@ public class ApiExecuteService { ...@@ -34,57 +44,92 @@ public class ApiExecuteService {
@Resource @Resource
private DriverLoadService driverLoadService; private DriverLoadService driverLoadService;
public ResultEntity<Object> execute(ApiAssignmentEntity config, HttpServletRequest request, public ResultEntity<Object> execute(ApiAssignmentEntity config, HttpServletRequest request) {
HttpServletResponse response) { try {
DataSourceEntity dsEntity = dataSourceDao.getById(config.getDatasourceId()); DataSourceEntity dsEntity = dataSourceDao.getById(config.getDatasourceId());
if (null == dsEntity) { if (null == dsEntity) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 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);
return ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, message); }
} Map<String, Object> paramValues = obtainParameterValues(request, config.getParams());
Map<String, Object> paramValues = obtainParameterValues(request, config.getParams()); 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()); Object result = ApiExecutorEngineFactory
Object result = ApiExecutorEngineFactory .getExecutor(config.getEngine(), dataSource, dsEntity.getType())
.getExecutor(config.getEngine(), dataSource, dsEntity.getType()) .execute(config.getContextList(), paramValues, config.getNamingStrategy());
.execute(config.getContextList(), paramValues); if (result instanceof Collection) {
if (result instanceof Collection) { Collection r = (Collection) result;
Collection r = (Collection) result; return ResultEntity.success(config.getContextList().size() == 1 ? r.stream().findFirst().get() : r);
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) { private Map<String, Object> obtainParameterValues(HttpServletRequest request, List<ItemParam> params) {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
if (null != params && params.size() > 0) { if (null != params && params.size() > 0) {
Map<String, Object> bodyMap = getRequestBodyMap(request);
for (ItemParam param : params) { for (ItemParam param : params) {
String name = param.getName(); String name = param.getName();
ParamTypeEnum type = param.getType(); ParamTypeEnum type = param.getType();
boolean isArray = Optional.ofNullable(param.getIsArray()).orElse(false); ParamLocationEnum location = param.getLocation();
Boolean required = Optional.ofNullable(param.getRequired()).orElse(false);
String defaultValue = param.getDefaultValue(); String defaultValue = param.getDefaultValue();
if (isArray) { if (location == ParamLocationEnum.REQUEST_HEADER) {
String[] values = request.getParameterValues(name); map.put(name, request.getHeader(name));
if (null != values && values.length > 0) { } else if (location == ParamLocationEnum.REQUEST_BODY) {
List list = Arrays.asList(values).stream() map.put(name, bodyMap.get(name));
.map(v -> type.getConverter().apply(v))
.collect(Collectors.toList());
map.put(name, list);
} else {
map.put(name, null);
}
} else { } else {
String value = request.getParameter(name); boolean isArray = Optional.ofNullable(param.getIsArray()).orElse(false);
if (!required && null == value) { Boolean required = Optional.ofNullable(param.getRequired()).orElse(false);
value = defaultValue; 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; 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; package com.gitee.sqlrest.core.exec.engine;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.persistence.entity.ApiContextEntity; import com.gitee.sqlrest.persistence.entity.ApiContextEntity;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public interface ApiExecutorEngine { 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; package com.gitee.sqlrest.core.exec.engine.impl;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.common.enums.ProductTypeEnum; 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;
...@@ -86,9 +87,9 @@ public class ScriptExecutorService extends AbstractExecutorEngine { ...@@ -86,9 +87,9 @@ public class ScriptExecutorService extends AbstractExecutorEngine {
} }
@Override @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); 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<>(); List<Object> results = new ArrayList<>();
for (ApiContextEntity entity : scripts) { for (ApiContextEntity entity : scripts) {
......
...@@ -2,6 +2,7 @@ package com.gitee.sqlrest.core.exec.engine.impl; ...@@ -2,6 +2,7 @@ package com.gitee.sqlrest.core.exec.engine.impl;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import com.gitee.sqlrest.common.consts.Constants; 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.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.core.exec.engine.AbstractExecutorEngine; import com.gitee.sqlrest.core.exec.engine.AbstractExecutorEngine;
import com.gitee.sqlrest.core.util.SqlJdbcUtils; import com.gitee.sqlrest.core.util.SqlJdbcUtils;
...@@ -25,7 +26,7 @@ public class SqlExecutorService extends AbstractExecutorEngine { ...@@ -25,7 +26,7 @@ public class SqlExecutorService extends AbstractExecutorEngine {
} }
@Override @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<>(); List<Object> dataList = new ArrayList<>();
Configuration cfg = new Configuration(); Configuration cfg = new Configuration();
try (Connection connection = this.dataSource.getConnection()) { try (Connection connection = this.dataSource.getConnection()) {
...@@ -40,7 +41,7 @@ public class SqlExecutorService extends AbstractExecutorEngine { ...@@ -40,7 +41,7 @@ public class SqlExecutorService extends AbstractExecutorEngine {
int size = (null == params.get(Constants.PARAM_PAGE_SIZE)) int size = (null == params.get(Constants.PARAM_PAGE_SIZE))
? 10 ? 10
: NumberUtil.parseInt(params.get(Constants.PARAM_PAGE_SIZE).toString()); : 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(); connection.commit();
return dataList; return dataList;
......
...@@ -2,9 +2,11 @@ package com.gitee.sqlrest.core.exec.module; ...@@ -2,9 +2,11 @@ package com.gitee.sqlrest.core.exec.module;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import com.gitee.sqlrest.common.consts.Constants; 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.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.core.exec.annotation.Comment; import com.gitee.sqlrest.core.exec.annotation.Comment;
import com.gitee.sqlrest.core.exec.annotation.Module; 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.Configuration;
import com.gitee.sqlrest.template.SqlMeta; import com.gitee.sqlrest.template.SqlMeta;
import com.gitee.sqlrest.template.SqlTemplate; import com.gitee.sqlrest.template.SqlTemplate;
...@@ -15,7 +17,9 @@ import java.sql.Statement; ...@@ -15,7 +17,9 @@ import java.sql.Statement;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.sql.DataSource; import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
...@@ -37,11 +41,26 @@ public class DbVarModule { ...@@ -37,11 +41,26 @@ public class DbVarModule {
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
private ProductTypeEnum productType; private ProductTypeEnum productType;
private Map<String, Object> params; 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.jdbcTemplate = new JdbcTemplate(dataSource);
this.productType = productType; this.productType = productType;
this.params = params; 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("查询所有的数据列表") @Comment("查询所有的数据列表")
...@@ -49,7 +68,7 @@ public class DbVarModule { ...@@ -49,7 +68,7 @@ public class DbVarModule {
log.info("Enter selectAll() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter selectAll() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); SqlTemplate template = cfg.getTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
return jdbcTemplate.queryForList(sqlMeta.getSql(), sqlMeta.getParameter().toArray()); return build(jdbcTemplate.queryForList(sqlMeta.getSql(), sqlMeta.getParameter().toArray()));
} }
@Comment("count所有数据的总数") @Comment("count所有数据的总数")
...@@ -67,7 +86,7 @@ public class DbVarModule { ...@@ -67,7 +86,7 @@ public class DbVarModule {
log.info("Enter selectOne() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter selectOne() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); SqlTemplate template = cfg.getTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
return jdbcTemplate return build(jdbcTemplate
.query(sqlMeta.getSql(), new ResultSetExtractor<Map<String, Object>>() { .query(sqlMeta.getSql(), new ResultSetExtractor<Map<String, Object>>() {
private ColumnMapRowMapper mapper = new ColumnMapRowMapper(); private ColumnMapRowMapper mapper = new ColumnMapRowMapper();
...@@ -79,7 +98,7 @@ public class DbVarModule { ...@@ -79,7 +98,7 @@ public class DbVarModule {
return null; return null;
} }
}, },
sqlMeta.getParameter().toArray()); sqlMeta.getParameter().toArray()));
} }
@Comment("分页查询数据列表") @Comment("分页查询数据列表")
...@@ -98,7 +117,7 @@ public class DbVarModule { ...@@ -98,7 +117,7 @@ public class DbVarModule {
: NumberUtil.parseInt(params.get(Constants.PARAM_PAGE_SIZE).toString()); : NumberUtil.parseInt(params.get(Constants.PARAM_PAGE_SIZE).toString());
parameters.add(((page - 1) * size) < 0 ? 0 : (page - 1) * size); parameters.add(((page - 1) * size) < 0 ? 0 : (page - 1) * size);
parameters.add(size); parameters.add(size);
return jdbcTemplate.queryForList(pageSql, parameters.toArray()); return build(jdbcTemplate.queryForList(pageSql, parameters.toArray()));
} }
@Comment("执行insert操作,返回插入主键") @Comment("执行insert操作,返回插入主键")
...@@ -115,7 +134,7 @@ public class DbVarModule { ...@@ -115,7 +134,7 @@ public class DbVarModule {
return ps; return ps;
}, },
keyHolder); keyHolder);
return keyHolder.getKeys(); return build(keyHolder.getKeys());
} }
@Comment("执行update操作,返回受影响行数") @Comment("执行update操作,返回受影响行数")
......
...@@ -5,6 +5,8 @@ import cn.hutool.core.exceptions.ExceptionUtil; ...@@ -5,6 +5,8 @@ import cn.hutool.core.exceptions.ExceptionUtil;
import com.gitee.sqlrest.common.dto.PageResult; 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.ResultEntity; 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.OnOffEnum;
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.CommonException;
...@@ -15,6 +17,8 @@ import com.gitee.sqlrest.core.dto.ApiAssignmentDetailResponse; ...@@ -15,6 +17,8 @@ import com.gitee.sqlrest.core.dto.ApiAssignmentDetailResponse;
import com.gitee.sqlrest.core.dto.ApiAssignmentSaveRequest; import com.gitee.sqlrest.core.dto.ApiAssignmentSaveRequest;
import com.gitee.sqlrest.core.dto.ApiDebugExecuteRequest; import com.gitee.sqlrest.core.dto.ApiDebugExecuteRequest;
import com.gitee.sqlrest.core.dto.AssignmentSearchRequest; 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.ScriptEditorCompletion;
import com.gitee.sqlrest.core.dto.SqlParamParseResponse; import com.gitee.sqlrest.core.dto.SqlParamParseResponse;
import com.gitee.sqlrest.core.exec.ApiExecuteService; import com.gitee.sqlrest.core.exec.ApiExecuteService;
...@@ -35,8 +39,10 @@ import com.gitee.sqlrest.template.SqlTemplate; ...@@ -35,8 +39,10 @@ import com.gitee.sqlrest.template.SqlTemplate;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
...@@ -50,6 +56,7 @@ import javax.annotation.Resource; ...@@ -50,6 +56,7 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -144,29 +151,34 @@ public class ApiAssignmentService { ...@@ -144,29 +151,34 @@ public class ApiAssignmentService {
} }
} }
if (null == request.getNamingStrategy()) {
request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE);
}
File driverPath = driverLoadService.getVersionDriverFile(dataSourceEntity.getType(), dataSourceEntity.getVersion()); File driverPath = driverLoadService.getVersionDriverFile(dataSourceEntity.getType(), dataSourceEntity.getVersion());
ResultEntity entity; ResultEntity entity;
try { try {
HikariDataSource dataSource = DataSourceUtils.getHikariDataSource(dataSourceEntity, driverPath.getAbsolutePath()); HikariDataSource dataSource = DataSourceUtils.getHikariDataSource(dataSourceEntity, driverPath.getAbsolutePath());
Object result = ApiExecutorEngineFactory Object result = ApiExecutorEngineFactory
.getExecutor(request.getEngine(), dataSource, dataSourceEntity.getType()) .getExecutor(request.getEngine(), dataSource, dataSourceEntity.getType())
.execute(scripts, params); .execute(scripts, params, request.getNamingStrategy());
if (result instanceof Collection) { if (result instanceof Collection) {
Collection r = (Collection) result; Collection r = (Collection) result;
result = scripts.size() == 1 ? r.stream().findFirst().get() : r; result = scripts.size() == 1 ? r.stream().findFirst().get() : r;
} }
entity = ResultEntity.success(result); entity = ResultEntity.success(result);
response.setStatus(HttpServletResponse.SC_OK);
} catch (Exception e) { } catch (Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
entity = ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, ExceptionUtil.getMessage(e)); entity = ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, ExceptionUtil.getMessage(e));
} }
String json = JacksonUtils.toJsonStr(entity, request.getFormatMap(), request.getNamingStrategy());
try { try {
response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(Charsets.UTF_8.name()); 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) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
...@@ -183,6 +195,10 @@ public class ApiAssignmentService { ...@@ -183,6 +195,10 @@ public class ApiAssignmentService {
if (CollectionUtils.isEmpty(request.getContextList())) { if (CollectionUtils.isEmpty(request.getContextList())) {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "contextList"); throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "contextList");
} }
if (null == request.getNamingStrategy()) {
request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE);
}
List<ApiContextEntity> contextList = getContextListEntity(request.getContextList()); List<ApiContextEntity> contextList = getContextListEntity(request.getContextList());
ApiAssignmentEntity assignmentEntity = new ApiAssignmentEntity(); ApiAssignmentEntity assignmentEntity = new ApiAssignmentEntity();
...@@ -199,6 +215,9 @@ public class ApiAssignmentService { ...@@ -199,6 +215,9 @@ public class ApiAssignmentService {
assignmentEntity.setEngine(request.getEngine()); assignmentEntity.setEngine(request.getEngine());
assignmentEntity.setStatus(false); assignmentEntity.setStatus(false);
assignmentEntity.setContextList(contextList); assignmentEntity.setContextList(contextList);
assignmentEntity.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.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false));
assignmentEntity.setFlowGrade(request.getFlowGrade()); assignmentEntity.setFlowGrade(request.getFlowGrade());
assignmentEntity.setFlowCount(request.getFlowCount()); assignmentEntity.setFlowCount(request.getFlowCount());
...@@ -222,6 +241,10 @@ public class ApiAssignmentService { ...@@ -222,6 +241,10 @@ public class ApiAssignmentService {
throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "sqlTextList"); throw new CommonException(ResponseErrorCode.ERROR_INVALID_ARGUMENT, "sqlTextList");
} }
if (null == request.getNamingStrategy()) {
request.setNamingStrategy(NamingStrategyEnum.CAMEL_CASE);
}
List<ApiContextEntity> contextList = getContextListEntity(request.getContextList()); List<ApiContextEntity> contextList = getContextListEntity(request.getContextList());
ApiAssignmentEntity assignmentEntity = new ApiAssignmentEntity(); ApiAssignmentEntity assignmentEntity = new ApiAssignmentEntity();
...@@ -239,6 +262,9 @@ public class ApiAssignmentService { ...@@ -239,6 +262,9 @@ public class ApiAssignmentService {
assignmentEntity.setStatus(false); assignmentEntity.setStatus(false);
assignmentEntity.setEngine(request.getEngine()); assignmentEntity.setEngine(request.getEngine());
assignmentEntity.setContextList(contextList); assignmentEntity.setContextList(contextList);
assignmentEntity.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.setFlowStatus(Optional.ofNullable(request.getFlowStatus()).orElse(false));
assignmentEntity.setFlowGrade(request.getFlowGrade()); assignmentEntity.setFlowGrade(request.getFlowGrade());
assignmentEntity.setFlowCount(request.getFlowCount()); assignmentEntity.setFlowCount(request.getFlowCount());
...@@ -255,15 +281,43 @@ public class ApiAssignmentService { ...@@ -255,15 +281,43 @@ public class ApiAssignmentService {
ApiAssignmentDetailResponse response = new ApiAssignmentDetailResponse(); ApiAssignmentDetailResponse response = new ApiAssignmentDetailResponse();
BeanUtil.copyProperties(assignmentEntity, response); BeanUtil.copyProperties(assignmentEntity, response);
response.setSqlList(assignmentEntity.getContextList()); 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; 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); ApiAssignmentEntity assignmentEntity = apiAssignmentDao.getById(id, true);
if (null == assignmentEntity) { if (null == assignmentEntity) {
throw new CommonException(ResponseErrorCode.ERROR_RESOURCE_NOT_EXISTS, "id=" + id); 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) { public void deleteAssignment(Long id) {
......
...@@ -3,7 +3,6 @@ package com.gitee.sqlrest.core.servlet; ...@@ -3,7 +3,6 @@ package com.gitee.sqlrest.core.servlet;
import com.gitee.sqlrest.common.consts.Constants; import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.dto.ResultEntity; import com.gitee.sqlrest.common.dto.ResultEntity;
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.exception.ResponseErrorCode; import com.gitee.sqlrest.common.exception.ResponseErrorCode;
import com.gitee.sqlrest.core.exec.ApiExecuteService; import com.gitee.sqlrest.core.exec.ApiExecuteService;
import com.gitee.sqlrest.core.util.JacksonUtils; import com.gitee.sqlrest.core.util.JacksonUtils;
...@@ -11,7 +10,6 @@ import com.gitee.sqlrest.persistence.dao.ApiAssignmentDao; ...@@ -11,7 +10,6 @@ import com.gitee.sqlrest.persistence.dao.ApiAssignmentDao;
import com.gitee.sqlrest.persistence.entity.ApiAssignmentEntity; import com.gitee.sqlrest.persistence.entity.ApiAssignmentEntity;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -34,21 +32,19 @@ public class ApiServletService { ...@@ -34,21 +32,19 @@ public class ApiServletService {
response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(Charsets.UTF_8.name()); response.setCharacterEncoding(Charsets.UTF_8.name());
String path = request.getRequestURI().substring(Constants.API_PATH_PREFIX.length() + 2); String path = request.getRequestURI().substring(Constants.API_PATH_PREFIX.length() + 2);
String json = null; ResultEntity result = ResultEntity.success();
ApiAssignmentEntity apiConfigEntity = apiAssignmentDao.getByUk(method, path); ApiAssignmentEntity apiConfigEntity = apiAssignmentDao.getByUk(method, path);
if (null == apiConfigEntity || !apiConfigEntity.getStatus()) { if (null == apiConfigEntity || !apiConfigEntity.getStatus()) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND); response.setStatus(HttpServletResponse.SC_NOT_FOUND);
String message = String.format("/%s/%s[%s]", Constants.API_PATH_PREFIX, path, method.name()); String message = String.format("/%s/%s[%s]", Constants.API_PATH_PREFIX, path, method.name());
ResultEntity result = ResultEntity.failed(ResponseErrorCode.ERROR_PATH_NOT_EXISTS, message); result = ResultEntity.failed(ResponseErrorCode.ERROR_PATH_NOT_EXISTS, message);
json = JacksonUtils.toJsonStr(result, Collections.emptyMap(), null);
} else { } else {
ResultEntity result = apiExecuteService.execute(apiConfigEntity, request, response); result = apiExecuteService.execute(apiConfigEntity, request);
if (0 != result.getCode()) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
json = JacksonUtils.toJsonStr(result, Collections.emptyMap(), NamingStrategyEnum.UPPER_CAMEL_CASE);
} }
if (0 != result.getCode()) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
String json = JacksonUtils.toJsonStr(result, apiConfigEntity.getResponseFormat());
response.getWriter().append(json); response.getWriter().append(json);
} }
......
package com.gitee.sqlrest.core.servlet; 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.consts.Constants;
import com.gitee.sqlrest.common.dto.AccessToken; import com.gitee.sqlrest.common.dto.AccessToken;
import com.gitee.sqlrest.common.enums.DurationTimeEnum; import com.gitee.sqlrest.common.enums.DurationTimeEnum;
...@@ -14,7 +14,6 @@ import java.util.Map; ...@@ -14,7 +14,6 @@ import java.util.Map;
import javax.annotation.Resource; import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -26,7 +25,7 @@ public class ClientTokenService { ...@@ -26,7 +25,7 @@ public class ClientTokenService {
@Resource @Resource
private AppClientDao appClientDao; private AppClientDao appClientDao;
@Resource @Resource
private HazelcastCacheFactory hazelcastCacheFactory; private CacheFactory cacheFactory;
@EventListener(ApplicationReadyEvent.class) @EventListener(ApplicationReadyEvent.class)
public void init() { public void init() {
...@@ -52,7 +51,7 @@ public class ClientTokenService { ...@@ -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); tokenClientMap.put(appClient.getAccessToken(), clientToken);
} }
} }
...@@ -73,7 +72,7 @@ public class ClientTokenService { ...@@ -73,7 +72,7 @@ public class ClientTokenService {
.realName(appClient.getName()) .realName(appClient.getName())
.appKey(clientId) .appKey(clientId)
.accessToken(token) .accessToken(token)
.createTimestamp(System.currentTimeMillis()/1000) .createTimestamp(System.currentTimeMillis() / 1000)
.expireSeconds(Constants.CLIENT_TOKEN_DURATION_SECONDS) .expireSeconds(Constants.CLIENT_TOKEN_DURATION_SECONDS)
.build(); .build();
if (DurationTimeEnum.TIME_VALUE.equals(appClient.getExpireDuration())) { if (DurationTimeEnum.TIME_VALUE.equals(appClient.getExpireDuration())) {
...@@ -93,7 +92,7 @@ public class ClientTokenService { ...@@ -93,7 +92,7 @@ public class ClientTokenService {
appClientDao.updateTokenByAppKey(clientId, token); 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); tokenClientMap.put(token, clientToken);
return clientToken; return clientToken;
...@@ -103,7 +102,7 @@ public class ClientTokenService { ...@@ -103,7 +102,7 @@ public class ClientTokenService {
if (StringUtils.isBlank(tokenStr)) { if (StringUtils.isBlank(tokenStr)) {
return null; return null;
} }
Map<String, AccessToken> tokenClientMap = hazelcastCacheFactory Map<String, AccessToken> tokenClientMap = cacheFactory
.getCacheMap(Constants.CACHE_KEY_TOKEN_CLIENT); .getCacheMap(Constants.CACHE_KEY_TOKEN_CLIENT);
AccessToken clientToken = tokenClientMap.get(tokenStr); AccessToken clientToken = tokenClientMap.get(tokenStr);
if (null == clientToken) { 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; package com.gitee.sqlrest.core.util;
import cn.hutool.core.util.ClassLoaderUtil; 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.JarFileClassLoader;
import com.gitee.sqlrest.common.model.SimpleDataSource; import com.gitee.sqlrest.common.model.SimpleDataSource;
import com.gitee.sqlrest.persistence.entity.DataSourceEntity; import com.gitee.sqlrest.persistence.entity.DataSourceEntity;
...@@ -60,18 +61,14 @@ public final class DataSourceUtils { ...@@ -60,18 +61,14 @@ public final class DataSourceUtils {
HikariDataSource ds = new HikariDataSource(); HikariDataSource ds = new HikariDataSource();
ds.setPoolName("The_JDBC_Connection"); ds.setPoolName("The_JDBC_Connection");
ds.setJdbcUrl(properties.getUrl()); ds.setJdbcUrl(properties.getUrl());
if (properties.getDriver().contains("oracle")) { if (ProductTypeEnum.ORACLE == properties.getType()) {
ds.setConnectionTestQuery("SELECT 'Hello' from DUAL"); ds.setConnectionTestQuery(properties.getType().getTestSql());
// https://blog.csdn.net/qq_20960159/article/details/78593936 // https://blog.csdn.net/qq_20960159/article/details/78593936
System.getProperties().setProperty("oracle.jdbc.J2EE13Compliant", "true"); System.getProperties().setProperty("oracle.jdbc.J2EE13Compliant", "true");
// Oracle在通过jdbc连接的时候需要添加一个参数来设置是否获取注释 // Oracle在通过jdbc连接的时候需要添加一个参数来设置是否获取注释
parameters.put("remarksReporting", "true"); parameters.put("remarksReporting", "true");
} else if (properties.getDriver().contains("db2")) { } else if (StringUtils.isNotBlank(properties.getType().getTestSql())) {
ds.setConnectionTestQuery("SELECT 1 FROM SYSIBM.SYSDUMMY1"); ds.setConnectionTestQuery(properties.getType().getTestSql());
} else if (properties.getDriver().contains("mongodb")) {
ds.setConnectionTestQuery("use admin;");
} else if (!ds.getJdbcUrl().contains("jdbc:jest://")) {
ds.setConnectionTestQuery("SELECT 1");
} }
ds.setMaximumPoolSize(MAX_THREAD_COUNT); ds.setMaximumPoolSize(MAX_THREAD_COUNT);
ds.setMinimumIdle(MAX_THREAD_COUNT); ds.setMinimumIdle(MAX_THREAD_COUNT);
......
...@@ -3,12 +3,9 @@ package com.gitee.sqlrest.core.util; ...@@ -3,12 +3,9 @@ package com.gitee.sqlrest.core.util;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper; 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.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.databind.ser.std.StdSerializer;
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.core.serdes.DateTimeSerDesFactory; import com.gitee.sqlrest.core.serdes.DateTimeSerDesFactory;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
...@@ -16,20 +13,13 @@ import java.util.Map; ...@@ -16,20 +13,13 @@ import java.util.Map;
public final class JacksonUtils { public final class JacksonUtils {
public static String toJsonStr(Object obj) { 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 // https://www.jianshu.com/p/1368547350c6
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(createSerializeModule(formatMap)); objectMapper.registerModule(createSerializeModule(formatMap));
if (null != namingStrategy) {
PropertyNamingStrategy strategy = createPropertyNamingStrategy(namingStrategy);
if (null != strategy) {
objectMapper.setPropertyNamingStrategy(strategy);
}
}
try { try {
return objectMapper.writeValueAsString(obj); return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
...@@ -37,20 +27,6 @@ public final class JacksonUtils { ...@@ -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) { private static Module createSerializeModule(Map<DataTypeFormatEnum, String> formatMap) {
Map<DataTypeFormatEnum, String> finalFormatMap = (null == formatMap) ? Collections.emptyMap() : formatMap; Map<DataTypeFormatEnum, String> finalFormatMap = (null == formatMap) ? Collections.emptyMap() : formatMap;
SimpleModule module = new SimpleModule(); SimpleModule module = new SimpleModule();
......
package com.gitee.sqlrest.core.util; package com.gitee.sqlrest.core.util;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.template.SqlMeta; import com.gitee.sqlrest.template.SqlMeta;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
...@@ -9,6 +10,7 @@ import java.util.ArrayList; ...@@ -9,6 +10,7 @@ import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -16,7 +18,8 @@ import lombok.extern.slf4j.Slf4j; ...@@ -16,7 +18,8 @@ import lombok.extern.slf4j.Slf4j;
@UtilityClass @UtilityClass
public class SqlJdbcUtils { 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(); List<Object> paramValues = sqlMeta.getParameter();
PreparedStatement statement = connection.prepareStatement(sqlMeta.getSql()); PreparedStatement statement = connection.prepareStatement(sqlMeta.getSql());
statement.setQueryTimeout(300); statement.setQueryTimeout(300);
...@@ -25,6 +28,7 @@ public class SqlJdbcUtils { ...@@ -25,6 +28,7 @@ public class SqlJdbcUtils {
statement.setObject(i, paramValues.get(i - 1)); statement.setObject(i, paramValues.get(i - 1));
} }
log.info("ExecuteSQL:{}\n{}", sqlMeta.getSql(), paramValues); log.info("ExecuteSQL:{}\n{}", sqlMeta.getSql(), paramValues);
Function<String, String> converter = (null == strategy) ? Function.identity() : strategy.getFunction();
if (statement.execute()) { if (statement.execute()) {
int skipNumber = size * (page - 1); int skipNumber = size * (page - 1);
try (ResultSet rs = statement.getResultSet()) { try (ResultSet rs = statement.getResultSet()) {
...@@ -45,7 +49,7 @@ public class SqlJdbcUtils { ...@@ -45,7 +49,7 @@ public class SqlJdbcUtils {
} }
} }
if (skipNumber <= 0) { if (skipNumber <= 0) {
list.add(row); list.add(ConvertUtils.to(row, converter));
if (list.size() >= size) { if (list.size() >= size) {
break; 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: ...@@ -13,6 +13,17 @@ spring:
validation-query: SELECT 1 validation-query: SELECT 1
test-on-borrow: true test-on-borrow: true
sqlrest:
cache:
hazelcast:
enabled: true
redis:
enabled: false
host: 127.0.0.1
port: 6379
password: 123456
database: 0
mybatis: mybatis:
configuration: configuration:
lazy-loading-enabled: true lazy-loading-enabled: true
...@@ -41,4 +52,4 @@ eureka: ...@@ -41,4 +52,4 @@ eureka:
datasource: datasource:
driver: driver:
base-path: ${APP_DRIVERS_PATH} base-path: ${APP_DRIVERS_PATH}
\ No newline at end of file
...@@ -46,6 +46,17 @@ spring: ...@@ -46,6 +46,17 @@ spring:
allowed-methods: '*' allowed-methods: '*'
allowed-headers: "*" allowed-headers: "*"
sqlrest:
cache:
hazelcast:
enabled: true
redis:
enabled: false
host: 127.0.0.1
port: 6379
password: 123456
database: 0
mybatis: mybatis:
configuration: configuration:
lazy-loading-enabled: true lazy-loading-enabled: true
......
...@@ -151,14 +151,14 @@ ...@@ -151,14 +151,14 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.name" <el-input v-model="scope.row.name"
type="string" type="string"
:disabled=isOnlyShowDetail> </el-input> :disabled="isOnlyShowDetail"> </el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="参数类型" <el-table-column label="参数类型"
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.type" <el-select v-model="scope.row.type"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
<el-option label='整型' <el-option label='整型'
value='LONG'></el-option> value='LONG'></el-option>
<el-option label='浮点型' <el-option label='浮点型'
...@@ -176,7 +176,7 @@ ...@@ -176,7 +176,7 @@
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.isArray" <el-select v-model="scope.row.isArray"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
<el-option label='是' <el-option label='是'
:value=true></el-option> :value=true></el-option>
<el-option label='否' <el-option label='否'
...@@ -188,7 +188,7 @@ ...@@ -188,7 +188,7 @@
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.required" <el-select v-model="scope.row.required"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
<el-option label='是' <el-option label='是'
:value=true></el-option> :value=true></el-option>
<el-option label='否' <el-option label='否'
...@@ -201,7 +201,7 @@ ...@@ -201,7 +201,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.defaultValue" <el-input v-model="scope.row.defaultValue"
type="string" type="string"
:disabled=isOnlyShowDetail></el-input> :disabled="isOnlyShowDetail"></el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="描述" <el-table-column label="描述"
...@@ -209,7 +209,7 @@ ...@@ -209,7 +209,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.remark" <el-input v-model="scope.row.remark"
type="string" type="string"
:disabled=isOnlyShowDetail></el-input> :disabled="isOnlyShowDetail"></el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" <el-table-column label="操作"
...@@ -223,7 +223,7 @@ ...@@ -223,7 +223,7 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="必要配置>>" <el-tab-pane label="接口配置>>"
name="detail"> name="detail">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
...@@ -233,7 +233,7 @@ ...@@ -233,7 +233,7 @@
:required=true :required=true
prop="path"> prop="path">
<el-input v-model="createParam.path" <el-input v-model="createParam.path"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
<template slot="prepend">{{gatewayApiPrefix}}</template> <template slot="prepend">{{gatewayApiPrefix}}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
...@@ -245,7 +245,7 @@ ...@@ -245,7 +245,7 @@
:required=true :required=true
prop="method"> prop="method">
<el-select v-model="createParam.method" <el-select v-model="createParam.method"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
<el-option label="GET" <el-option label="GET"
value="GET"></el-option> value="GET"></el-option>
<el-option label="PUT" <el-option label="PUT"
...@@ -267,7 +267,7 @@ ...@@ -267,7 +267,7 @@
<el-input v-model="createParam.name" <el-input v-model="createParam.name"
auto-complete="off" auto-complete="off"
style="width:75%" style="width:75%"
:disabled=isOnlyShowDetail></el-input> :disabled="isOnlyShowDetail"></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
...@@ -277,7 +277,7 @@ ...@@ -277,7 +277,7 @@
:required=true :required=true
prop="contentType"> prop="contentType">
<el-select v-model="createParam.contentType" <el-select v-model="createParam.contentType"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
<el-option v-for="(item,index) in contentTypes" <el-option v-for="(item,index) in contentTypes"
:key="index" :key="index"
:label="item" :label="item"
...@@ -295,7 +295,7 @@ ...@@ -295,7 +295,7 @@
prop="module"> prop="module">
<el-select v-model="createParam.module" <el-select v-model="createParam.module"
placeholder="请选择" placeholder="请选择"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
<el-option v-for="(item,index) in moduleList" <el-option v-for="(item,index) in moduleList"
:key="index" :key="index"
:label="`[${item.id}]${item.name}`" :label="`[${item.id}]${item.name}`"
...@@ -311,7 +311,7 @@ ...@@ -311,7 +311,7 @@
prop="group"> prop="group">
<el-select v-model="createParam.group" <el-select v-model="createParam.group"
placeholder="请选择" placeholder="请选择"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
<el-option v-for="(item,index) in groupList" <el-option v-for="(item,index) in groupList"
:key="index" :key="index"
:label="`[${item.id}]${item.name}`" :label="`[${item.id}]${item.name}`"
...@@ -333,6 +333,46 @@ ...@@ -333,6 +333,46 @@
</el-col> </el-col>
</el-row> </el-row>
</el-tab-pane> </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="流量控制" <el-tab-pane label="流量控制"
name="flowControl"> name="flowControl">
<el-row> <el-row>
...@@ -344,14 +384,14 @@ ...@@ -344,14 +384,14 @@
:inactive-value="false" :inactive-value="false"
active-text="开启" active-text="开启"
inactive-text="关闭" inactive-text="关闭"
:disabled=isOnlyShowDetail> :disabled="isOnlyShowDetail">
</el-switch> </el-switch>
</el-form-item> </el-form-item>
<div v-show="createParam.flowStatus"> <div v-show="createParam.flowStatus">
<el-form-item label="阈值类型"> <el-form-item label="阈值类型">
<el-radio-group size="small" <el-radio-group size="small"
v-model="createParam.flowGrade" v-model="createParam.flowGrade"
:disabled=isOnlyShowDetail :disabled="isOnlyShowDetail"
border> border>
<el-radio :label="1">QPS</el-radio> <el-radio :label="1">QPS</el-radio>
<el-radio :label="0">并发线程数</el-radio> <el-radio :label="0">并发线程数</el-radio>
...@@ -361,7 +401,7 @@ ...@@ -361,7 +401,7 @@
<el-input-number v-model="createParam.flowCount" <el-input-number v-model="createParam.flowCount"
size="small" size="small"
:step="1" :step="1"
:disabled=isOnlyShowDetail :disabled="isOnlyShowDetail"
step-strictly></el-input-number> step-strictly></el-input-number>
</el-form-item> </el-form-item>
</div> </div>
...@@ -444,7 +484,7 @@ ...@@ -444,7 +484,7 @@
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.isArray" <el-select v-model="scope.row.isArray"
disabled="true"> :disabled="true">
<el-option label='是' <el-option label='是'
:value=true></el-option> :value=true></el-option>
<el-option label='否' <el-option label='否'
...@@ -456,7 +496,7 @@ ...@@ -456,7 +496,7 @@
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.required" <el-select v-model="scope.row.required"
disabled="true"> :disabled="true">
<el-option label='是' <el-option label='是'
:value=true></el-option> :value=true></el-option>
<el-option label='否' <el-option label='否'
...@@ -468,7 +508,7 @@ ...@@ -468,7 +508,7 @@
min-width="25%"> min-width="25%">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.remark" <el-input v-model="scope.row.remark"
disabled="true" :disabled="true"
type="string"></el-input> type="string"></el-input>
</template> </template>
</el-table-column> </el-table-column>
...@@ -544,6 +584,8 @@ export default { ...@@ -544,6 +584,8 @@ export default {
sqls: [], sqls: [],
script: '', script: '',
open: false, open: false,
namingStrategy: 'CAMEL_CASE',
formatMap: null,
flowStatus: false, flowStatus: false,
flowGrade: 1, flowGrade: 1,
flowCount: 5 flowCount: 5
...@@ -564,6 +606,8 @@ export default { ...@@ -564,6 +606,8 @@ export default {
inputParams: [], inputParams: [],
debugParams: [], debugParams: [],
debugResponse: "", debugResponse: "",
responseNamingStrategy: [],
responseTypeFormat: [],
rules: { rules: {
name: [ name: [
{ {
...@@ -656,6 +700,8 @@ export default { ...@@ -656,6 +700,8 @@ export default {
engine: detail.engine, engine: detail.engine,
sqls: [], sqls: [],
script: "", script: "",
namingStrategy: detail.namingStrategy,
formatMap: detail.formatMap,
flowStatus: detail.flowStatus, flowStatus: detail.flowStatus,
flowGrade: detail.flowGrade, flowGrade: detail.flowGrade,
flowCount: detail.flowCount flowCount: detail.flowCount
...@@ -762,6 +808,28 @@ export default { ...@@ -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 () { loadTreeData: function () {
if (this.createParam.dataSourceId && this.createParam.dataSourceId > 0 && this.showTree) { if (this.createParam.dataSourceId && this.createParam.dataSourceId > 0 && this.showTree) {
this.treeData = [] this.treeData = []
...@@ -976,6 +1044,7 @@ export default { ...@@ -976,6 +1044,7 @@ export default {
this.inputParams.push( this.inputParams.push(
{ {
name: item.name, name: item.name,
location: 'FORM_DATA',
type: "STRING", type: "STRING",
isArray: item.isArray, isArray: item.isArray,
required: true, required: true,
...@@ -1001,6 +1070,7 @@ export default { ...@@ -1001,6 +1070,7 @@ export default {
this.inputParams.push( this.inputParams.push(
{ {
name: "", name: "",
location: 'FORM_DATA',
type: "STRING", type: "STRING",
isArray: false, isArray: false,
required: true, required: true,
...@@ -1017,6 +1087,7 @@ export default { ...@@ -1017,6 +1087,7 @@ export default {
{ {
name: "apiPageNum", name: "apiPageNum",
type: "LONG", type: "LONG",
location: 'FORM_DATA',
isArray: false, isArray: false,
required: true, required: true,
defaultValue: "1", defaultValue: "1",
...@@ -1030,6 +1101,7 @@ export default { ...@@ -1030,6 +1101,7 @@ export default {
{ {
name: "apiPageSize", name: "apiPageSize",
type: "LONG", type: "LONG",
location: 'FORM_DATA',
isArray: false, isArray: false,
required: true, required: true,
defaultValue: "10", defaultValue: "10",
...@@ -1099,6 +1171,8 @@ export default { ...@@ -1099,6 +1171,8 @@ export default {
contentType: this.createParam.contentType, contentType: this.createParam.contentType,
path: this.createParam.path, path: this.createParam.path,
open: this.createParam.open, open: this.createParam.open,
namingStrategy: this.createParam.namingStrategy,
formatMap: this.createParam.formatMap,
flowStatus: this.createParam.flowStatus, flowStatus: this.createParam.flowStatus,
flowGrade: this.createParam.flowGrade, flowGrade: this.createParam.flowGrade,
flowCount: this.createParam.flowCount, flowCount: this.createParam.flowCount,
...@@ -1137,6 +1211,8 @@ export default { ...@@ -1137,6 +1211,8 @@ export default {
contentType: this.createParam.contentType, contentType: this.createParam.contentType,
path: this.createParam.path, path: this.createParam.path,
open: this.createParam.open, open: this.createParam.open,
namingStrategy: this.createParam.namingStrategy,
formatMap: this.createParam.formatMap,
flowStatus: this.createParam.flowStatus, flowStatus: this.createParam.flowStatus,
flowGrade: this.createParam.flowGrade, flowGrade: this.createParam.flowGrade,
flowCount: this.createParam.flowCount, flowCount: this.createParam.flowCount,
...@@ -1222,6 +1298,8 @@ export default { ...@@ -1222,6 +1298,8 @@ export default {
data: JSON.stringify({ data: JSON.stringify({
dataSourceId: this.createParam.dataSourceId, dataSourceId: this.createParam.dataSourceId,
engine: this.createParam.engine, engine: this.createParam.engine,
namingStrategy: this.createParam.namingStrategy,
formatMap: this.createParam.formatMap,
contextList: sqls, contextList: sqls,
paramValues: this.debugParams paramValues: this.debugParams
}) })
...@@ -1246,6 +1324,8 @@ export default { ...@@ -1246,6 +1324,8 @@ export default {
this.loadGateway(); this.loadGateway();
this.loadKeywordHints(); this.loadKeywordHints();
this.loadTreeData(); this.loadTreeData();
this.loadResponseNamingStrategy();
this.loadResponseTypeFormat();
}, },
} }
</script> </script>
......
...@@ -24,12 +24,6 @@ ...@@ -24,12 +24,6 @@
</dependency> </dependency>
<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> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency> </dependency>
......
...@@ -3,13 +3,19 @@ package com.gitee.sqlrest.manager.controller; ...@@ -3,13 +3,19 @@ package com.gitee.sqlrest.manager.controller;
import com.gitee.sqlrest.common.consts.Constants; import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.dto.PageResult; import com.gitee.sqlrest.common.dto.PageResult;
import com.gitee.sqlrest.common.dto.ResultEntity; 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.ApiAssignmentBaseResponse;
import com.gitee.sqlrest.core.dto.ApiAssignmentSaveRequest; import com.gitee.sqlrest.core.dto.ApiAssignmentSaveRequest;
import com.gitee.sqlrest.core.dto.ApiDebugExecuteRequest; import com.gitee.sqlrest.core.dto.ApiDebugExecuteRequest;
import com.gitee.sqlrest.core.dto.AssignmentSearchRequest; 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 com.gitee.sqlrest.core.service.ApiAssignmentService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import java.util.Arrays;
import java.util.stream.Collectors;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
...@@ -38,6 +44,37 @@ public class ApiAssignmentController { ...@@ -38,6 +44,37 @@ public class ApiAssignmentController {
return ResultEntity.success(apiAssignmentService.completions()); 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中的入参列表") @ApiOperation(value = "获取SQL中的入参列表")
@PostMapping(value = "/parse", produces = MediaType.APPLICATION_JSON_VALUE) @PostMapping(value = "/parse", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultEntity parse(@RequestParam("sql") String sql) { public ResultEntity parse(@RequestParam("sql") String sql) {
...@@ -72,8 +109,8 @@ public class ApiAssignmentController { ...@@ -72,8 +109,8 @@ public class ApiAssignmentController {
@ApiOperation(value = "测试API执行") @ApiOperation(value = "测试API执行")
@PostMapping(value = "/test/{id}", produces = MediaType.APPLICATION_JSON_VALUE) @PostMapping(value = "/test/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultEntity test(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response) { public void test(@PathVariable("id") Long id, HttpServletRequest request, HttpServletResponse response) {
return apiAssignmentService.testAssignment(id, request, response); apiAssignmentService.testAssignment(id, request, response);
} }
@ApiOperation(value = "删除API配置") @ApiOperation(value = "删除API配置")
......
...@@ -19,6 +19,17 @@ spring: ...@@ -19,6 +19,17 @@ spring:
table: SQLREST_SCHEMA_HISTORY table: SQLREST_SCHEMA_HISTORY
enabled: true enabled: true
sqlrest:
cache:
hazelcast:
enabled: true
redis:
enabled: false
host: 127.0.0.1
port: 6379
password: 123456
database: 0
mybatis: mybatis:
configuration: configuration:
lazy-loading-enabled: true 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> <!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 \ 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}}([]); !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.255d24ba50ec0408e7ae.js.map //# sourceMappingURL=manifest.038d1629b6d567190efe.js.map
\ No newline at end of file \ 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":"aACA,IAAAA,EAAAC,OAAA,aACAA,OAAA,sBAAAC,EAAAC,EAAAC,GAIA,IADA,IAAAC,EAAAC,EAAAC,EAAAC,EAAA,EAAAC,KACQD,EAAAN,EAAAQ,OAAoBF,IAC5BF,EAAAJ,EAAAM,GACAG,EAAAL,IACAG,EAAAG,KAAAD,EAAAL,GAAA,IAEAK,EAAAL,GAAA,EAEA,IAAAD,KAAAF,EACAU,OAAAC,UAAAC,eAAAC,KAAAb,EAAAE,KACAY,EAAAZ,GAAAF,EAAAE,IAIA,IADAL,KAAAE,EAAAC,EAAAC,GACAK,EAAAC,QACAD,EAAAS,OAAAT,GAEA,GAAAL,EACA,IAAAI,EAAA,EAAYA,EAAAJ,EAAAM,OAA2BF,IACvCD,EAAAY,IAAAC,EAAAhB,EAAAI,IAGA,OAAAD,GAIA,IAAAc,KAGAV,GACAW,GAAA,GAIA,SAAAH,EAAAd,GAGA,GAAAgB,EAAAhB,GACA,OAAAgB,EAAAhB,GAAAkB,QAGA,IAAAC,EAAAH,EAAAhB,IACAG,EAAAH,EACAoB,GAAA,EACAF,YAUA,OANAN,EAAAZ,GAAAW,KAAAQ,EAAAD,QAAAC,IAAAD,QAAAJ,GAGAK,EAAAC,GAAA,EAGAD,EAAAD,QAKAJ,EAAAO,EAAA,SAAApB,GACA,IAAAqB,EAAAhB,EAAAL,GACA,OAAAqB,EACA,WAAAC,QAAA,SAAAC,GAA0CA,MAI1C,GAAAF,EACA,OAAAA,EAAA,GAIA,IAAAG,EAAA,IAAAF,QAAA,SAAAC,EAAAE,GACAJ,EAAAhB,EAAAL,IAAAuB,EAAAE,KAEAJ,EAAA,GAAAG,EAGA,IAAAE,EAAAC,SAAAC,qBAAA,WACAC,EAAAF,SAAAG,cAAA,UACAD,EAAAE,KAAA,kBACAF,EAAAG,QAAA,QACAH,EAAAI,OAAA,EACAJ,EAAAK,QAAA,KAEArB,EAAAsB,IACAN,EAAAO,aAAA,QAAAvB,EAAAsB,IAEAN,EAAAQ,IAAAxB,EAAAyB,EAAA,aAAAtC,EAAA,KAAwEuC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,wBAAsiB1D,GAAA,MAC9mB,IAAAkC,EAAAyB,WAAAC,EAAA,MAEA,SAAAA,IAEA/B,EAAAgC,QAAAhC,EAAAiC,OAAA,KACAC,aAAA7B,GACA,IAAA8B,EAAA3D,EAAAL,GACA,IAAAgE,IACAA,GACAA,EAAA,OAAAC,MAAA,iBAAAjE,EAAA,aAEAK,EAAAL,QAAAkE,GAKA,OAfArC,EAAAgC,QAAAhC,EAAAiC,OAAAF,EAaAlC,EAAAyC,YAAAtC,GAEAL,GAIAX,EAAAuD,EAAAzD,EAGAE,EAAAwD,EAAAtD,EAGAF,EAAAyD,EAAA,SAAArD,EAAAsD,EAAAC,GACA3D,EAAA4D,EAAAxD,EAAAsD,IACAhE,OAAAmE,eAAAzD,EAAAsD,GACAI,cAAA,EACAC,YAAA,EACAC,IAAAL,KAMA3D,EAAAiE,EAAA,SAAA5D,GACA,IAAAsD,EAAAtD,KAAA6D,WACA,WAA2B,OAAA7D,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAL,EAAAyD,EAAAE,EAAA,IAAAA,GACAA,GAIA3D,EAAA4D,EAAA,SAAAO,EAAAC,GAAsD,OAAA1E,OAAAC,UAAAC,eAAAC,KAAAsE,EAAAC,IAGtDpE,EAAAyB,EAAA,IAGAzB,EAAAqE,GAAA,SAAAC,GAA8D,MAApBC,QAAAC,MAAAF,GAAoBA","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":""} {"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":"aACA,IAAAA,EAAAC,OAAA,aACAA,OAAA,sBAAAC,EAAAC,EAAAC,GAIA,IADA,IAAAC,EAAAC,EAAAC,EAAAC,EAAA,EAAAC,KACQD,EAAAN,EAAAQ,OAAoBF,IAC5BF,EAAAJ,EAAAM,GACAG,EAAAL,IACAG,EAAAG,KAAAD,EAAAL,GAAA,IAEAK,EAAAL,GAAA,EAEA,IAAAD,KAAAF,EACAU,OAAAC,UAAAC,eAAAC,KAAAb,EAAAE,KACAY,EAAAZ,GAAAF,EAAAE,IAIA,IADAL,KAAAE,EAAAC,EAAAC,GACAK,EAAAC,QACAD,EAAAS,OAAAT,GAEA,GAAAL,EACA,IAAAI,EAAA,EAAYA,EAAAJ,EAAAM,OAA2BF,IACvCD,EAAAY,IAAAC,EAAAhB,EAAAI,IAGA,OAAAD,GAIA,IAAAc,KAGAV,GACAW,GAAA,GAIA,SAAAH,EAAAd,GAGA,GAAAgB,EAAAhB,GACA,OAAAgB,EAAAhB,GAAAkB,QAGA,IAAAC,EAAAH,EAAAhB,IACAG,EAAAH,EACAoB,GAAA,EACAF,YAUA,OANAN,EAAAZ,GAAAW,KAAAQ,EAAAD,QAAAC,IAAAD,QAAAJ,GAGAK,EAAAC,GAAA,EAGAD,EAAAD,QAKAJ,EAAAO,EAAA,SAAApB,GACA,IAAAqB,EAAAhB,EAAAL,GACA,OAAAqB,EACA,WAAAC,QAAA,SAAAC,GAA0CA,MAI1C,GAAAF,EACA,OAAAA,EAAA,GAIA,IAAAG,EAAA,IAAAF,QAAA,SAAAC,EAAAE,GACAJ,EAAAhB,EAAAL,IAAAuB,EAAAE,KAEAJ,EAAA,GAAAG,EAGA,IAAAE,EAAAC,SAAAC,qBAAA,WACAC,EAAAF,SAAAG,cAAA,UACAD,EAAAE,KAAA,kBACAF,EAAAG,QAAA,QACAH,EAAAI,OAAA,EACAJ,EAAAK,QAAA,KAEArB,EAAAsB,IACAN,EAAAO,aAAA,QAAAvB,EAAAsB,IAEAN,EAAAQ,IAAAxB,EAAAyB,EAAA,aAAAtC,EAAA,KAAwEuC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,wBAAsiB1D,GAAA,MAC9mB,IAAAkC,EAAAyB,WAAAC,EAAA,MAEA,SAAAA,IAEA/B,EAAAgC,QAAAhC,EAAAiC,OAAA,KACAC,aAAA7B,GACA,IAAA8B,EAAA3D,EAAAL,GACA,IAAAgE,IACAA,GACAA,EAAA,OAAAC,MAAA,iBAAAjE,EAAA,aAEAK,EAAAL,QAAAkE,GAKA,OAfArC,EAAAgC,QAAAhC,EAAAiC,OAAAF,EAaAlC,EAAAyC,YAAAtC,GAEAL,GAIAX,EAAAuD,EAAAzD,EAGAE,EAAAwD,EAAAtD,EAGAF,EAAAyD,EAAA,SAAArD,EAAAsD,EAAAC,GACA3D,EAAA4D,EAAAxD,EAAAsD,IACAhE,OAAAmE,eAAAzD,EAAAsD,GACAI,cAAA,EACAC,YAAA,EACAC,IAAAL,KAMA3D,EAAAiE,EAAA,SAAA5D,GACA,IAAAsD,EAAAtD,KAAA6D,WACA,WAA2B,OAAA7D,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAL,EAAAyD,EAAAE,EAAA,IAAAA,GACAA,GAIA3D,EAAA4D,EAAA,SAAAO,EAAAC,GAAsD,OAAA1E,OAAAC,UAAAC,eAAAC,KAAAsE,EAAAC,IAGtDpE,EAAAyB,EAAA,IAGAzB,EAAAqE,GAAA,SAAAC,GAA8D,MAApBC,QAAAC,MAAAF,GAAoBA","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 \ No newline at end of file
...@@ -6,12 +6,15 @@ import com.baomidou.mybatisplus.annotation.TableField; ...@@ -6,12 +6,15 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; 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.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;
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 com.gitee.sqlrest.persistence.handler.ListParamHandler;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.List; import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
...@@ -64,6 +67,12 @@ public class ApiAssignmentEntity { ...@@ -64,6 +67,12 @@ public class ApiAssignmentEntity {
@TableField(value = "engine", typeHandler = EnumTypeHandler.class) @TableField(value = "engine", typeHandler = EnumTypeHandler.class)
private ExecuteEngineEnum engine; 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") @TableField(value = "flow_status")
private Boolean flowStatus; 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; package com.gitee.sqlrest.persistence.util;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collections; import java.util.Collections;
...@@ -40,6 +41,19 @@ public class JsonUtils { ...@@ -40,6 +41,19 @@ public class JsonUtils {
return null; 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) { public static <T> List<T> toBeanList(String jsonString, Class<T> clazz) {
if (null != jsonString) { if (null != jsonString) {
try { 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