Commit 9090061d by inrgihc

系统参数支持可配置

parent 5c7245ac
......@@ -18,6 +18,10 @@ public abstract class Constants {
public static final int SC_TOO_MANY_REQUESTS = 429;
public static final String API_DOC_PATH_PREFIX = "/apidoc";
public static final String SYS_PARAM_KEY_API_DOC_OPEN = "apiDocOpen";
public static final String getResourceName(String method, String path) {
return String.format("/%s/%s[%s]", Constants.API_PATH_PREFIX, path, method);
}
......
......@@ -6,22 +6,24 @@ import org.apache.commons.lang3.StringUtils;
@Getter
public enum ParamTypeEnum {
LONG("整型", "number", 0L, (String str) -> StringUtils.isNotBlank(str) ? Long.valueOf(str) : str),
DOUBLE("浮点型", "number", 0D, (String str) -> StringUtils.isNotBlank(str) ? Double.valueOf(str) : str),
STRING("字符串", "string", "", (String str) -> str),
DATE("日期", "string", "", (String str) -> str),
TIME("时间", "string", "", (String str) -> str),
;
LONG("整型", "number", 0L, Long.class, (String str) -> StringUtils.isNotBlank(str) ? Long.valueOf(str) : str),
DOUBLE("浮点型", "number", 0D, Double.class, (String str) -> StringUtils.isNotBlank(str) ? Double.valueOf(str) : str),
STRING("字符串", "string", "", String.class, (String str) -> str),
DATE("日期", "string", "", String.class, (String str) -> str),
TIME("时间", "string", "", String.class, (String str) -> str),
BOOLEAN("布尔", "string", "true", Boolean.class, (String str) -> Boolean.parseBoolean(str));
private String name;
private String jsType;
private Object example;
private Class clazz;
private Function<String, Object> converter;
ParamTypeEnum(String name, String jsType, Object example, Function<String, Object> converter) {
ParamTypeEnum(String name, String jsType, Object example, Class clazz, Function<String, Object> converter) {
this.name = name;
this.jsType = jsType;
this.example = example;
this.clazz = clazz;
this.converter = converter;
}
}
......@@ -27,7 +27,7 @@ public enum ProductTypeEnum {
"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 ?, ? ")
.pageSql("select * from (%s) alias limit ? OFFSET ? ")
.build()),
/**
* MariaDB数据库类型
......@@ -46,7 +46,7 @@ public enum ProductTypeEnum {
"jdbc:mariadb://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 ?, ? ")
.pageSql("select * from (%s) alias limit ? OFFSET ? ")
.build()),
/**
* Oracle数据库类型
......@@ -238,7 +238,7 @@ public enum ProductTypeEnum {
.urlSample("jdbc:hive2://172.17.2.12:10000/default")
.sqlSchemaList("SHOW DATABASES")
.adapter(database -> Pair.of(null, database))
.pageSql("select * from (%s) alias limit ?, ? ")
.pageSql("select * from (%s) alias limit ? OFFSET ? ")
.build()),
/**
......@@ -297,7 +297,7 @@ public enum ProductTypeEnum {
.urlSample("jdbc:clickhouse://172.17.2.10:8123/default")
.sqlSchemaList("SELECT schema_name FROM information_schema.schemata ")
.adapter(database -> Pair.of(null, database))
.pageSql("select * from (%s) alias limit ?, ? ")
.pageSql("select * from (%s) alias limit ? OFFSET ? ")
.build()),
/**
......@@ -317,7 +317,7 @@ public enum ProductTypeEnum {
"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 ?, ? ")
.pageSql("select * from (%s) alias limit ? OFFSET ? ")
.build()),
/**
......@@ -337,7 +337,7 @@ public enum ProductTypeEnum {
"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 ?, ? ")
.pageSql("select * from (%s) alias limit ? OFFSET ? ")
.build()),
/**
......@@ -357,7 +357,7 @@ public enum ProductTypeEnum {
"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 ?, ? ")
.pageSql("select * from (%s) alias limit ? OFFSET ? ")
.build()),
;
......
......@@ -41,7 +41,7 @@ public class SqlExecutorService extends AbstractExecutorEngine {
int size = (null == params.get(Constants.PARAM_PAGE_SIZE))
? 10
: NumberUtil.parseInt(params.get(Constants.PARAM_PAGE_SIZE).toString());
dataList.add(SqlJdbcUtils.execute(connection, sqlMeta, strategy, page, size));
dataList.add(SqlJdbcUtils.execute(productType, connection, sqlMeta, strategy, page, size));
}
connection.commit();
return dataList;
......
......@@ -8,6 +8,7 @@ import com.gitee.sqlrest.core.serdes.datetime.LocalDateValueSerializer;
import com.gitee.sqlrest.core.serdes.datetime.TimeValueSerializer;
import com.gitee.sqlrest.core.serdes.datetime.TimestampValueSerializer;
import com.gitee.sqlrest.core.serdes.number.NumberValueSerializer;
import com.google.common.collect.ImmutableMap;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
......@@ -29,6 +30,6 @@ public final class DateTimeSerDesFactory {
}
public static Map<DataTypeFormatEnum, Function<String, StdSerializer>> getAllSerDesMap() {
return new HashMap<>(DATE_TIME_SER_MAP);
return ImmutableMap.copyOf(DATE_TIME_SER_MAP);
}
}
package com.gitee.sqlrest.core.service;
import com.gitee.sqlrest.common.exception.CommonException;
import com.gitee.sqlrest.common.exception.ResponseErrorCode;
import com.gitee.sqlrest.persistence.dao.SystemParamDao;
import com.gitee.sqlrest.persistence.entity.SystemParamEntity;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class SystemParamService {
@Resource
private SystemParamDao systemParamDao;
public Object getByParamKey(String key) {
SystemParamEntity entity = systemParamDao.getByParamKey(key);
if (null == entity) {
throw new CommonException(ResponseErrorCode.ERROR_RESOURCE_NOT_EXISTS, "NO KEY:" + key);
}
Class clazz = entity.getParamType().getClazz();
String paramValue = entity.getParamValue();
return clazz.cast(entity.getParamType().getConverter().apply(paramValue));
}
public void updateByParamKey(String key, String value) {
SystemParamEntity entity = systemParamDao.getByParamKey(key);
if (null == entity) {
throw new CommonException(ResponseErrorCode.ERROR_RESOURCE_NOT_EXISTS, "NO KEY:" + key);
}
Class clazz = entity.getParamType().getClazz();
Object paramValue = clazz.cast(entity.getParamType().getConverter().apply(value));
if (null == paramValue) {
throw new CommonException(ResponseErrorCode.ERROR_INTERNAL_ERROR, "Invalid param value:[" + value + "]");
}
systemParamDao.updateByParamKey(key, String.valueOf(paramValue));
}
}
package com.gitee.sqlrest.core.util;
import com.gitee.sqlrest.common.enums.NamingStrategyEnum;
import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.template.SqlMeta;
import java.sql.Connection;
import java.sql.PreparedStatement;
......@@ -18,19 +19,41 @@ import lombok.extern.slf4j.Slf4j;
@UtilityClass
public class SqlJdbcUtils {
public static Object execute(Connection connection, SqlMeta sqlMeta, NamingStrategyEnum strategy, int page, int size)
public static boolean isQuerySQL(String sql) {
String upperSql = sql.toUpperCase().trim();
return upperSql.startsWith("SELECT") || upperSql.startsWith("WITH");
}
public static Function<String, String> getConverter(NamingStrategyEnum strategy) {
return (null == strategy) ? Function.identity() : strategy.getFunction();
}
public static Object execute(ProductTypeEnum productType, Connection connection, SqlMeta sqlMeta,
NamingStrategyEnum strategy, int page, int size)
throws SQLException {
List<Object> paramValues = sqlMeta.getParameter();
PreparedStatement statement = connection.prepareStatement(sqlMeta.getSql());
boolean isQuerySql = isQuerySQL(sqlMeta.getSql());
String sql = isQuerySql ? productType.getPageSql(sqlMeta.getSql()) : sqlMeta.getSql();
PreparedStatement statement = connection.prepareStatement(sql);
statement.setQueryTimeout(300);
statement.setFetchSize(isMySqlConnection(connection) ? Integer.MIN_VALUE : 100);
if (isQuerySql) {
if (page <= 0) {
page = 1;
}
if (size <= 0) {
size = 10;
}
paramValues.add(size);
paramValues.add((page - 1) * size);
}
for (int i = 1; i <= paramValues.size(); i++) {
statement.setObject(i, paramValues.get(i - 1));
}
log.info("ExecuteSQL:{}\n{}", sqlMeta.getSql(), paramValues);
Function<String, String> converter = (null == strategy) ? Function.identity() : strategy.getFunction();
log.info("ExecuteSQL:{}\n{}", sql, paramValues);
Function<String, String> converter = getConverter(strategy);
if (statement.execute()) {
int skipNumber = size * (page - 1);
try (ResultSet rs = statement.getResultSet()) {
List<String> columns = new ArrayList<>();
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
......@@ -48,14 +71,7 @@ public class SqlJdbcUtils {
row.put(column, null);
}
}
if (skipNumber <= 0) {
list.add(ConvertUtils.to(row, converter));
if (list.size() >= size) {
break;
}
} else {
skipNumber--;
}
list.add(ConvertUtils.to(row, converter));
}
return list;
}
......
package com.gitee.sqlrest.executor.config;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.executor.interceptor.ExecutorInterceptor;
import com.gitee.sqlrest.persistence.dao.SystemParamDao;
import javax.annotation.Resource;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class ExecutorWebConfig implements WebMvcConfigurer {
private final String pathPattern = Constants.API_DOC_PATH_PREFIX + "/**";
@Resource
private SystemParamDao systemParamDao;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/apidoc/**").addResourceLocations("classpath:/apidoc/");
registry.addResourceHandler(pathPattern).addResourceLocations("classpath:/apidoc/");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
public void addInterceptors(InterceptorRegistry registry) {
ExecutorInterceptor interceptor = new ExecutorInterceptor(systemParamDao);
registry.addInterceptor(interceptor).addPathPatterns(pathPattern);
}
}
package com.gitee.sqlrest.executor.controller;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.core.dto.SwaggerEntity;
import com.gitee.sqlrest.core.servlet.ApiSwaggerService;
import io.swagger.annotations.Api;
......@@ -12,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
@Api(tags = {"Swagger接口文档"})
@RestController
@RequestMapping(value = "/apidoc")
@RequestMapping(value = Constants.API_DOC_PATH_PREFIX)
public class ApiSwaggerController {
@Resource
......
package com.gitee.sqlrest.executor.interceptor;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.persistence.dao.SystemParamDao;
import com.gitee.sqlrest.persistence.entity.SystemParamEntity;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class ExecutorInterceptor implements HandlerInterceptor {
private final SystemParamDao systemParamDao;
public ExecutorInterceptor(SystemParamDao systemParamDao) {
this.systemParamDao = systemParamDao;
}
private boolean isApiDocOpen() {
SystemParamEntity entity = systemParamDao.getByParamKey(Constants.SYS_PARAM_KEY_API_DOC_OPEN);
if (null == entity) {
return true;
}
Class<Boolean> clazz = entity.getParamType().getClazz();
String paramValue = entity.getParamValue();
return clazz.cast(entity.getParamType().getConverter().apply(paramValue));
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String path = request.getRequestURI();
if (path.startsWith("/apidoc")) {
return isApiDocOpen();
}
return true;
}
}
package com.gitee.sqlrest.manager.controller;
import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.dto.ResultEntity;
import com.gitee.sqlrest.core.service.SystemParamService;
import io.swagger.annotations.Api;
import javax.annotation.Resource;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = {"参数管理接口"})
@RestController
@RequestMapping(value = Constants.MANGER_API_V1 + "/param")
public class SystemParamController {
@Resource
private SystemParamService systemParamService;
@GetMapping(value = "/value/query", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultEntity getByParamKey(@RequestParam("key") String key) {
return ResultEntity.success(systemParamService.getByParamKey(key));
}
@PostMapping(value = "/value/update", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultEntity updateByParamKey(@RequestParam("key") String key,
@RequestParam("value") String value) {
systemParamService.updateByParamKey(key, value);
return ResultEntity.success();
}
}
......@@ -134,3 +134,12 @@ CREATE TABLE `SQLREST_ACCESS_RECORD`
`create_time` timestamp not null default current_timestamp comment '创建时间',
PRIMARY KEY (`id`)
) engine=InnoDB default charset=utf8 comment='客户端应用接口访问日志表';
CREATE TABLE `SQLREST_SYSTEM_PARAM` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`param_key` varchar(128) NOT NULL COMMENT '参数KEY',
`param_type` varchar(64) NOT NULL COMMENT '值类型',
`param_value` varchar(255) NOT NULL COMMENT '参数值',
PRIMARY KEY (`id`),
UNIQUE KEY `param_key` (`param_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统参数表';
......@@ -4,3 +4,6 @@ ADD COLUMN `naming_strategy` varchar(16) NOT NULL DEFAULT 'NONE' comment '命
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;
INSERT INTO `SQLREST_SYSTEM_PARAM` (`param_key`, `param_type`, `param_value`) VALUES ('apiDocOpen', 'BOOLEAN', 'true');
INSERT INTO `SQLREST_SYSTEM_PARAM` (`param_key`, `param_type`, `param_value`) VALUES ('nameOfPageNum', 'STRING', 'apiPageNum');
INSERT INTO `SQLREST_SYSTEM_PARAM` (`param_key`, `param_type`, `param_value`) VALUES ('nameOfPageSize', 'STRING', 'apiPageSize');
package com.gitee.sqlrest.persistence.dao;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gitee.sqlrest.persistence.entity.SystemParamEntity;
import com.gitee.sqlrest.persistence.mapper.SystemParamMapper;
import java.util.Objects;
import javax.annotation.Resource;
import org.springframework.stereotype.Repository;
@Repository
public class SystemParamDao {
@Resource
private SystemParamMapper systemParamMapper;
public SystemParamEntity getByParamKey(String paramKey) {
QueryWrapper<SystemParamEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(SystemParamEntity::getParamKey, paramKey);
return systemParamMapper.selectOne(queryWrapper);
}
public void updateByParamKey(String paramKey, String paramValue) {
SystemParamEntity entity = getByParamKey(paramKey);
if (Objects.nonNull(entity)) {
entity.setParamValue(paramValue);
systemParamMapper.updateById(entity);
}
}
}
package com.gitee.sqlrest.persistence.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "SQLREST_SYSTEM_PARAM", autoResultMap = true)
public class SystemParamEntity {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("param_key")
private String paramKey;
@TableField("param_type")
private ParamTypeEnum paramType;
@TableField("param_value")
private String paramValue;
}
package com.gitee.sqlrest.persistence.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gitee.sqlrest.persistence.entity.SystemParamEntity;
public interface SystemParamMapper extends BaseMapper<SystemParamEntity> {
}
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