Commit 52100f08 by inrgihc

第一次代码提交

parents
target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
node_modules/
dist/
### VSCode NodeJS
.DS_Store
node_modules/
/dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
NOTHING
\ No newline at end of file
# SQLREST
> 将数据库的SQL生成RESTful的http接口的工具
## 一、工具介绍
### 1、功能介绍
一句话, sqlrest工具提供快速构建RESTful的API接口工具,包括SQl方式和脚本方式。功能包括:
- SQL方式构建RESTful接口
> 提供类似mybatis的动态SQL语法方式构建接口。
- 脚本方式构建RESTful接口
> 基于magic-script脚本的语法方式构建复杂场景下的接口。
- 支持接口的token安全认证功能
> 执行器支持生成token及token认证。
- 支持生成在线接口文档功能
> 基于swagger-ui提供生成在线接口文档功能。
### 2、支持的数据库
- 甲骨文的Oracle
- 微软的Microsoft SQLServer
- MySQL
- MariaDB
- PostgreSQL
- Greenplum(需使用PostgreSQL类型)
- IBM的DB2
- Sybase数据库
- 国产达梦数据库DMDB
- 国产人大金仓数据库Kingbase8
- 国产翰高数据库HighGo
- 国产神通数据库Oscar
- 国产南大通用数据库GBase8a
- Apache Hive
- SQLite3
- OpenGuass
- ClickHouse
### 3、模块结构功能
```
└── sqlrest
├── sqlrest-common // sqlrest通用定义模块
├── sqlrest-template // sqlrest的SQL内容模板模块
├── sqlrest-script // sqlrest的接口脚本解析模块
├── sqlrest-cache // sqlrest执行器缓存模块
├── sqlrest-persistence // sqlrest的数据库持久化模块
├── sqlrest-core // sqlrest-core的接口实现模块
├── sqlrest-gateway // Gateway网关节点
├── sqlrest-executor // Executor接口执行节点
├── sqlrest-manager // Manager管理节点
├── sqlrest-manager-ui // 基于Vue2的Manager前段WEB交互页面
├── sqlrest-dist // 基于maven-assembly-plugin插件的项目打包模块
```
## 二、编译打包
本工具纯Java语言开发,代码中的依赖全部来自于开源项目。
### 1、编译打包
- 环境要求:
**JDK**:>=1.8 (建议用JDK 1.8)
**maven**:>=3.6
> Maven 仓库默认在国外, 国内使用难免很慢,可以更换为阿里云的仓库。 参考教程: [配置阿里云的仓库教程](https://www.runoob.com/maven/maven-repositories.html)
- 编译命令:
**(1) windows下:**
```
双击build.cmd脚本文件即可编译打包
```
**(2) Linux下:**
```
git clone https://gitee.com/inrgihc/sqlrest.git
cd sqlrest/
sh ./build.sh
```
**(3) Docker下:**
```
git clone https://gitee.com/inrgihc/sqlrest.git
cd sqlrest/
sh ./docker-maven-build.sh
```
### 2、安装部署
(1) 当编译打包完成后,会在sqlrest/target/目录下生成sqlrest-relase-x.x.x.tar.gz的打包文件,将文件拷贝到已安装JRE的部署机器上解压即可。
(2) 基于docker-compose提供linux联网环境下的**一键安装**,安装命令见 [发行版链接地址](https://gitee.com/inrgihc/sqlrest/releases)
(3) 物理机方式部署
- 步骤1:准备好一个MySQL5.7+的数据库,假设连接地址如下:
```
# mysql的host地址
MYSQLDB_HOST=192.168.31.57
# mysql的端口号
MYSQLDB_PORT=3306
# mysql的库名
MYSQLDB_NAME=sqlrest
# mysql的账号
MYSQLDB_USERNAME=root
# mysql的密码
MYSQLDB_PASSWORD=123456
```
- 步骤2:修改sqlrest-relase-x.x.x/conf/config.ini配置文件
```
# manager节点的host地址,如果gateway与executor节点与manager不在同一台机器时需要配置manger节点的IP地址
MANAGER_HOST=localhost
# manager的端口号
MANAGER_PORT=8090
# executor的端口号
EXECUTOR_PORT=8092
# gateway的端口号
GATEWAY_PORT=8091
# mysql的host地址
MYSQLDB_HOST=192.168.31.57
# mysql的端口号
MYSQLDB_PORT=3306
# mysql的库名
MYSQLDB_NAME=sqlrest
# mysql的账号
MYSQLDB_USERNAME=root
# mysql的密码
MYSQLDB_PASSWORD=123456
```
- 步骤3:如果为多主机节点部署,需要将sqlrest-relase-x.x.x分发到其他主机节点上;如果为单机(单节点)部署可直接忽略本步骤。
- 步骤4:启动服务
> windows下,需按照如下顺序双击如下脚本启动对应的服务
启动manager服务:bin/manager_startup.cmd
启动executor服务:bin/executor_startup.cmd
启动gateway服务:bin/gateway_startup.cmd
> linux下,需按照如下顺序双击如下脚本启动对应的服务
启动manager服务:sh bin/sqlrestctl.sh start manager
启动executor服务:sh bin/sqlrestctl.sh start executor
启动gateway服务:sh bin/sqlrestctl.sh start gateway
## 三、使用教程
### 1、部分系统截图
![001.png](docs/images/001.PNG)
![002.png](docs/images/002.PNG)
![003.png](docs/images/003.PNG)
![004.png](docs/images/004.PNG)
## 四、问题反馈
如果您看到并使用了本工具,或您觉得本工具对您有价值,请为此项目**点个赞**,以表示对本项目的支持,多谢!如果您在使用时遇到了bug,欢迎在issue中反馈。
#!/bin/sh
set -e
SQLREST_VERSION=1.0.0
BUILD_DOCKER_DIR="$( cd "$( dirname "$0" )" && pwd )"
PROJECT_ROOT_DIR=$( dirname "$BUILD_DOCKER_DIR")
DOCKER_SQLREST_DIR=$BUILD_DOCKER_DIR/sqlrest
# build project
cd $PROJECT_ROOT_DIR && sh docker-maven-build.sh && cd -
# copy files
cd $BUILD_DOCKER_DIR \
&& tar zxvf $PROJECT_ROOT_DIR/target/sqlrest-release-${SQLREST_VERSION}.tar.gz -C /tmp \
&& cp -r /tmp/sqlrest-release-${SQLREST_VERSION}/lib/* ${BUILD_DOCKER_DIR}/sqlrest/sqlrest-release/lib/ \
&& cp -r /tmp/sqlrest-release-${SQLREST_VERSION}/drivers/* ${BUILD_DOCKER_DIR}/sqlrest/sqlrest-release/drivers/ \
&& rm -rf /tmp/sqlrest-release-*
# build image
cd ${DOCKER_SQLREST_DIR} && tar zcvf sqlrest-release.tar.gz sqlrest-release/
docker build -f Dockerfile-manager -t inrgihc/sqlrest-manager:${SQLREST_VERSION} .
docker build -f Dockerfile-executor -t inrgihc/sqlrest-executor:${SQLREST_VERSION} .
docker build -f Dockerfile-gateway -t inrgihc/sqlrest-gateway:${SQLREST_VERSION} .
rm -f sqlrest-release.tar.gz && rm -rf sqlrest-release/lib/* && rm -rf sqlrest-release/drivers/*
# clean project
cd $PROJECT_ROOT_DIR && sh docker-maven-clean.sh && cd -
# login and push docker image
docker login -u inrgihc
docker push inrgihc/sqlrest-manager:${SQLREST_VERSION}
docker push inrgihc/sqlrest-executor:${SQLREST_VERSION}
docker push inrgihc/sqlrest-gateway:${SQLREST_VERSION}
# SQLREST基于docker-compose的一键部署脚本
**要求**: 准备一个能够安装docker的linux操作系统
## 一、安装docker及docker-compose
```
[root@localhost install]# ls -l
总用量 12
-rw-r--r-- 1 root root 625 2月 11 22:24 docker-compose.yml
-rw-r--r-- 1 root root 787 2月 11 20:54 docker_install.sh
-rw-r--r-- 1 root root 378 2月 11 22:38 README.md
[root@localhost install]# sh docker_install.sh
```
## 二、一键部署dbswitch
```
[root@localhost install]# ls -l
总用量 12
-rw-r--r-- 1 root root 625 2月 11 22:24 docker-compose.yml
-rw-r--r-- 1 root root 787 2月 11 20:54 docker_install.sh
-rw-r--r-- 1 root root 378 2月 11 22:38 README.md
[root@localhost install]# docker-compose up -d
```
## 三、常用操作命令
- 1. 一键创建并启动容器服务:
```
docker-compose up -d
```
- 2. 销毁容器服务:
```
docker-compose down
```
- 3. 停止容器:
```
docker-compose stop
```
- 4. 重启容器:
```
docker-compose restart
```
- 5. 启动容器:
```
docker-compose start
```
services:
mysqldb:
container_name: sqlrest_mysqldb
image: mysql:5.7
network_mode: host
volumes:
- "/data/mysql:/var/lib/mysql"
environment:
MYSQL_DATABASE: sqlrest
MYSQL_USER: tangyibo
MYSQL_PASSWORD: 123456
MYSQL_ROOT_PASSWORD: 123456
MYSQL_ROOT_HOST: '%'
healthcheck:
test: ["CMD", "mysql", "-uroot", "-p123456" ,"-e"," select 1 "]
interval: 10s
timeout: 3s
retries: 60
start_period: 30s
manager:
container_name: sqlrest_manager
image: inrgihc/sqlrest-manager:1.0.0
network_mode: host
environment:
MYSQLDB_HOST: localhost
MYSQLDB_PORT: 3306
MYSQLDB_USERNAME: tangyibo
MYSQLDB_PASSWORD: 123456
MYSQLDB_NAME: sqlrest
MANAGER_HOST: localhost
MANAGER_PORT: 8090
EXECUTOR_PORT: 8092
GATEWAY_PORT: 8091
volumes:
- /tmp:/tmp
ports:
- 8090:8090
depends_on:
mysqldb:
condition: service_healthy
executor:
container_name: sqlrest_executor
image: inrgihc/sqlrest-executor:1.0.0
network_mode: host
environment:
MYSQLDB_HOST: localhost
MYSQLDB_PORT: 3306
MYSQLDB_USERNAME: tangyibo
MYSQLDB_PASSWORD: 123456
MYSQLDB_NAME: sqlrest
MANAGER_HOST: localhost
MANAGER_PORT: 8090
EXECUTOR_PORT: 8092
GATEWAY_PORT: 8091
volumes:
- /tmp:/tmp
ports:
- 8092:8092
depends_on:
mysqldb:
condition: service_healthy
gateway:
container_name: sqlrest_gateway
image: inrgihc/sqlrest-gateway:1.0.0
network_mode: host
environment:
MYSQLDB_HOST: localhost
MYSQLDB_PORT: 3306
MYSQLDB_USERNAME: tangyibo
MYSQLDB_PASSWORD: 123456
MYSQLDB_NAME: sqlrest
MANAGER_HOST: localhost
MANAGER_PORT: 8090
EXECUTOR_PORT: 8092
GATEWAY_PORT: 8091
volumes:
- /tmp:/tmp
ports:
- 8091:8091
depends_on:
mysqldb:
condition: service_healthy
#!/bin/bash
set -e
curl -sSL https://get.docker.com/ | sh
docker --version
mkdir -p /etc/docker/
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors":[
"https://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com",
"https://dhyjbe13.mirror.aliyuncs.com"
],
"insecure-registries": ["127.0.0.1/8"],
"max-concurrent-downloads":10,
"log-driver":"json-file",
"log-level":"warn",
"log-opts":{
"max-size":"10m",
"max-file":"3"
},
"data-root":"/var/lib/docker"
}
EOF
service docker restart
curl -L https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose
docker-compose --version
FROM openjdk:8-jre-alpine
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ADD sqlrest-release.tar.gz /
EXPOSE 9088
USER root
WORKDIR /sqlrest-release
RUN chmod u+x /sqlrest-release/bin/startup.sh
CMD ["/sqlrest-release/bin/startup.sh","executor"]
FROM openjdk:8-jre-alpine
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ADD sqlrest-release.tar.gz /
EXPOSE 9088
USER root
WORKDIR /sqlrest-release
RUN chmod u+x /sqlrest-release/bin/startup.sh
CMD ["/sqlrest-release/bin/startup.sh","gateway"]
FROM openjdk:8-jre-alpine
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ADD sqlrest-release.tar.gz /
EXPOSE 9088
USER root
WORKDIR /sqlrest-release
RUN chmod u+x /sqlrest-release/bin/startup.sh
CMD ["/sqlrest-release/bin/startup.sh","manager"]
#!/bin/sh
#
# Author : tang
# Date :2024-03-06
#
#############################################
module=$1
APP_HOME="${BASH_SOURCE-$0}"
APP_HOME="$(dirname "${APP_HOME}")"
APP_HOME="$(cd "${APP_HOME}"; pwd)"
APP_HOME="$(cd "$(dirname ${APP_HOME})"; pwd)"
APP_BIN_PATH=$APP_HOME/bin
APP_CONF_PATH=$APP_HOME/conf
APP_LIB_COMMON_PATH=$APP_HOME/lib/common
APP_LIB_EXECUTOR_PATH=$APP_HOME/lib/executor
APP_LIB_GATEWAY_PATH=$APP_HOME/lib/gateway
APP_LIB_MANAGER_PATH=$APP_HOME/lib/manager
APP_PID_FILE="${APP_HOME}/run/${module}.pid"
APP_RUN_LOG="${APP_HOME}/run/run_${module}.log"
echo "Begin start $module......"
echo "Base Directory:${APP_HOME}"
export APP_DRIVERS_PATH=$APP_HOME/drivers
# JVM参数可以在这里设置
JVMFLAGS="-server -Xms1024m -Xmx1024m -Xmn1024m -XX:+DisableExplicitGC -Djava.awt.headless=true -Dfile.encoding=UTF-8 "
if [ "$JAVA_HOME" != "" ]; then
JAVA="$JAVA_HOME/bin/java"
else
JAVA=java
fi
# 配置classpath和启动类
CLASSPATH=$APP_CONF_PATH
APP_MAIN_CLASS='com.gitee.sqlrest.manager.ManagerApplication'
if [ "$module" = "manager" ]; then
CLASSPATH="$APP_CONF_PATH/manager:$APP_LIB_COMMON_PATH/*:$APP_HOME/lib/webmvc/*:$APP_HOME/lib/manager/*"
APP_MAIN_CLASS='com.gitee.sqlrest.manager.ManagerApplication'
elif [ "$module" = "executor" ]; then
CLASSPATH="$APP_CONF_PATH/executor:$APP_LIB_COMMON_PATH/*:$APP_HOME/lib/webmvc/*:$APP_HOME/lib/executor/*"
APP_MAIN_CLASS='com.gitee.sqlrest.executor.ExecutorApplication'
elif [ "$module" = "gateway" ]; then
CLASSPATH="$APP_CONF_PATH/gateway:$APP_LIB_COMMON_PATH/*:$APP_HOME/lib/webflux/*:$APP_HOME/lib/gateway/*"
APP_MAIN_CLASS='ccom.gitee.sqlrest.gateway.GatewayApplication'
else
echo "Error: No module named '$module' was found."
exit 1
fi
# 执行命令
[ -d "${APP_HOME}/run" ] || mkdir -p "${APP_HOME}/run"
echo "d ${APP_HOME} && $JAVA -cp $CLASSPATH $JVMFLAGS $APP_MAIN_CLASS"
cd ${APP_HOME} && $JAVA -cp $CLASSPATH $JVMFLAGS $APP_MAIN_CLASS
echo "Finish start $module !"
server:
port: ${EXECUTOR_PORT}
spring:
application:
name: sqlrest-executor
main:
allow-bean-definition-overriding: false
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${MYSQLDB_HOST}:${MYSQLDB_PORT}/${MYSQLDB_NAME}?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF8&autoReconnect=true&useSSL=false&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=30000
username: ${MYSQLDB_USERNAME}
password: ${MYSQLDB_PASSWORD}
validation-query: SELECT 1
test-on-borrow: true
mybatis:
configuration:
lazy-loading-enabled: true
aggressive-lazy-loading: false
map-underscore-to-camel-case: true
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
config: classpath:logback-executor.xml
eureka:
instance:
prefer-ip-address: true
secure-port-enabled: false
non-secure-port-enabled: true
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 10
client:
healthcheck:
enabled: true
registry-fetch-interval-seconds: 5
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://${MANAGER_HOST}:${MANAGER_PORT}/eureka/
datasource:
driver:
base-path: ${APP_DRIVERS_PATH}
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod=" 5 seconds">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="./logs" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_HOME}/executor_server.log</File>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/executor_server_%d{yyyy-MM-dd}.log.%i.gz</FileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>512MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
server:
port: ${GATEWAY_PORT}
spring:
application:
name: sqlrest-gateway
main:
web-application-type: reactive
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${MYSQLDB_HOST}:${MYSQLDB_PORT}/${MYSQLDB_NAME}?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF8&autoReconnect=true&useSSL=false&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=30000
username: ${MYSQLDB_USERNAME}
password: ${MYSQLDB_PASSWORD}
validation-query: SELECT 1
test-on-borrow: true
cloud:
gateway:
routes:
- id: api_executor_route
uri: lb://sqlrest-executor
predicates:
- Path=/api/**
- id: api_token_executor_route
uri: lb://sqlrest-executor
predicates:
- Path=/token/generate
- id: api_doc_executor_route
uri: lb://sqlrest-executor
predicates:
- Path=/apidoc/**
- id: user_manager_route
uri: lb://sqlrest-manager
predicates:
- Path=/user/**
- id: manager_route
uri: lb://sqlrest-manager
predicates:
- Path=/sqlrest/manager/**
- id: eureka_manager_route
uri: lb://sqlrest-manager
predicates:
- Path=/dashboard/**
globalcors:
cors-configurations:
'[/**]':
allowed-origins: '*'
allowed-methods: '*'
allowed-headers: "*"
mybatis:
configuration:
lazy-loading-enabled: true
aggressive-lazy-loading: false
map-underscore-to-camel-case: true
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
config: classpath:logback-gateway.xml
eureka:
instance:
prefer-ip-address: true
secure-port-enabled: false
non-secure-port-enabled: true
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 10
client:
healthcheck:
enabled: true
registry-fetch-interval-seconds: 5
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://${MANAGER_HOST}:${MANAGER_PORT}/eureka/
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod=" 5 seconds">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="./logs" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_HOME}/gateway_server.log</File>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/gateway_server_%d{yyyy-MM-dd}.log.%i.gz</FileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>512MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
server:
port: ${MANAGER_PORT}
spring:
application:
name: sqlrest-manager
mvc:
throw-exception-if-no-handler-found: false
static-path-pattern: /**
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${MYSQLDB_HOST}:${MYSQLDB_PORT}/${MYSQLDB_NAME}?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF8&autoReconnect=true&useSSL=false&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=30000
username: ${MYSQLDB_USERNAME}
password: ${MYSQLDB_PASSWORD}
validation-query: SELECT 1
test-on-borrow: true
flyway:
locations: classpath:db/migration
baseline-on-migrate: true
table: SQLREST_SCHEMA_HISTORY
enabled: true
mybatis:
configuration:
lazy-loading-enabled: true
aggressive-lazy-loading: false
map-underscore-to-camel-case: true
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
config: classpath:logback-manager.xml
eureka:
dashboard:
enabled: false
path: /dashboard
instance:
prefer-ip-address: true
secure-port-enabled: false
non-secure-port-enabled: true
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 10
client:
registry-fetch-interval-seconds: 5
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://${MANAGER_HOST}:${MANAGER_PORT}/eureka/
datasource:
driver:
base-path: ${APP_DRIVERS_PATH}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod=" 5 seconds">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="./logs" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_HOME}/manager_server.log</File>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/manager_server_%d{yyyy-MM-dd}.log.%i.gz</FileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>512MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@echo off
echo "Clean Project ..."
call mvn clean -f pom.xml
echo "Build Project ..."
call mvn package -f pom.xml -D"maven.test.skip=true"
:exit
pause
\ No newline at end of file
#!/bin/sh
mvn clean package -Dmaven.test.skip=true
#!/bin/sh
docker run -it --rm \
--name my-maven-project \
-v ~/.m2:/opt/maven/localRepository \
-v "$PWD":/usr/src/mymaven \
-w /usr/src/mymaven \
inrgihc/maven-aliyun:3.6.3-jdk-8 mvn clean package
#!/bin/sh
docker run -it --rm \
--name my-maven-project \
-v ~/.m2:/opt/maven/localRepository \
-v "$PWD":/usr/src/mymaven \
-w /usr/src/mymaven \
inrgihc/maven-aliyun:3.6.3-jdk-8 mvn clean
```
$ curl -s -XPOST -d 'clientId=test&secret=test' 'http://127.0.0.1:8092/token/generate'
{
"code":0,
"message":"success",
"data":{
"realName":"测试",
"appKey":"test",
"accessToken":"fc99c78b19c49c861f119dd8959ab3d4",
"expireSeconds":7200
}
}
$ curl -s -XGET -H 'Authorization:Bearer fc99c78b19c49c861f119dd8959ab3d4' 'http://127.0.0.1:8092/api/test?id=1'
{
"code":0,
"data":[
],
"message":"success"
}
```
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.sqlrest</groupId>
<artifactId>sqlrest-parent</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<maven.test.skip>true</maven.test.skip>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.5.6</spring-boot.version>
<spring-cloud.version>2020.0.4</spring-cloud.version>
</properties>
<modules>
<module>sqlrest-common</module>
<module>sqlrest-script</module>
<module>sqlrest-template</module>
<module>sqlrest-persistence</module>
<module>sqlrest-core</module>
<module>sqlrest-cache</module>
<module>sqlrest-executor</module>
<module>sqlrest-gateway</module>
<module>sqlrest-manager</module>
<module>sqlrest-dist</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-all</artifactId>
<version>4.2.8</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-eureka-one</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.5</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.4.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.0.8</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<excludes>
<exclude>**/*.xml</exclude>
<exclude>**/*.yml</exclude>
<exclude>**/*.properties</exclude>
</excludes>
</configuration>
</plugin>
<!-- 将依赖的jar包拷贝到target目录下 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target</outputDirectory>
<excludeTransitive>false</excludeTransitive>
<stripVersion>false</stripVersion>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sqlrest-parent</artifactId>
<groupId>com.gitee.sqlrest</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sqlrest-cache</artifactId>
<dependencies>
<dependency>
<groupId>com.gitee.sqlrest</groupId>
<artifactId>sqlrest-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-all</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-eureka-one</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
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.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class HazelcastCacheFactory {
@Resource
private HazelcastInstance hazelcastInstance;
public <T> IMap<String, T> getCacheMap(String key) {
return hazelcastInstance.getMap(key);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sqlrest-parent</artifactId>
<groupId>com.gitee.sqlrest</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sqlrest-common</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.gitee.sqlrest.common.consts;
public abstract class Constants {
public static final String API_PATH_PREFIX = "api";
public static final String MANGER_API_PREFIX = "/sqlrest/manager/api";
public static final String MANGER_API_V1 = MANGER_API_PREFIX + "/v1";
public static final String PARAM_PAGE_NUMBER = "apiPageNum";
public static final String PARAM_PAGE_SIZE = "apiPageSize";
public static final String GATEWAY_APPLICATION_NAME = "sqlrest-gateway";
public static final String CACHE_KEY_TOKEN_CLIENT = "token_client";
public static final Long CLIENT_TOKEN_DURATION_SECONDS = 7200L;
}
package com.gitee.sqlrest.common.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("TOKEN信息")
public class AccessToken implements Serializable {
@ApiModelProperty("实际名称")
private String realName;
@ApiModelProperty("唯一标识")
private String appKey;
@ApiModelProperty("token字符串")
private String accessToken;
@ApiModelProperty("有效时间(单位秒)")
private Long expireSeconds;
}
package com.gitee.sqlrest.common.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DateCount {
private String ofDate;
private Long total;
private Long success;
}
package com.gitee.sqlrest.common.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("ID名称")
public class IdWithName implements Serializable {
@ApiModelProperty("ID编号")
private Long id;
@ApiModelProperty("名称")
private String name;
}
package com.gitee.sqlrest.common.dto;
import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("参数信息")
public class ItemParam {
@ApiModelProperty("参数名")
private String name;
@ApiModelProperty("参数类型")
private ParamTypeEnum type;
@ApiModelProperty("是否为数组")
private Boolean isArray;
@ApiModelProperty("是否必填")
private Boolean required;
@ApiModelProperty("默认值")
private String defaultValue;
@ApiModelProperty("参数描述")
private String remark;
}
package com.gitee.sqlrest.common.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("统计数量")
public class NameCount implements Serializable {
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("数量")
private Long count;
}
package com.gitee.sqlrest.common.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel(description = "分页结果")
@NoArgsConstructor
@Data
public class PageResult<E> {
@ApiModelProperty("状态码")
private Integer code = 0;
@ApiModelProperty("状态描述")
private String message = "success";
@ApiModelProperty("分页信息")
private Pagination pagination;
@ApiModelProperty("数据")
private List<E> data;
@ApiModel(description = "分页结果")
@NoArgsConstructor
@Data
public static class Pagination {
@ApiModelProperty("页码")
private int page;
@ApiModelProperty("记录总数")
private int total;
@ApiModelProperty("每页大小")
private int size;
}
}
package com.gitee.sqlrest.common.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("参数信息")
public class ParamValue extends ItemParam {
@ApiModelProperty("参数值")
private String value;
}
package com.gitee.sqlrest.common.dto;
import java.util.List;
import java.util.function.Function;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProductContext {
private int id;
private String quote;
private String name;
private String driver;
private int defaultPort;
private String testSql;
private String urlPrefix;
private String[] tplUrls;
private String urlSample;
private String sqlSchemaList;
private List<String> retSchemaList;
private Function<String, Pair<String, String>> adapter;
private String pageSql;
}
package com.gitee.sqlrest.common.dto;
import com.gitee.sqlrest.common.exception.ResponseErrorCode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
@ApiModel(description = "响应结果")
@AllArgsConstructor
@Data
public class ResultEntity<T> {
private static final String SUCCESS = "success";
@ApiModelProperty("状态码")
private Integer code;
@ApiModelProperty("状态描述")
private String message;
@ApiModelProperty("数据")
private T data;
public static <T> ResultEntity success() {
return new ResultEntity(0, SUCCESS, null);
}
public static <T> ResultEntity success(T data) {
return new ResultEntity<>(0, SUCCESS, data);
}
public static ResultEntity failed(ResponseErrorCode code) {
return new ResultEntity(code.getCode(), code.getMessage(), null);
}
public static ResultEntity failed(ResponseErrorCode code, String message) {
return new ResultEntity(code.getCode(), code.getMessage() + ":" + message, null);
}
}
package com.gitee.sqlrest.common.enums;
import lombok.Getter;
@Getter
public enum DurationTimeEnum {
FOR_EVER(-1),
ONLY_ONCE(0),
TIME_VALUE(1),
;
private long value;
DurationTimeEnum(long value) {
this.value = value;
}
}
package com.gitee.sqlrest.common.enums;
public enum ExecuteEngineEnum {
SQL, SCRIPT,
;
}
package com.gitee.sqlrest.common.enums;
import lombok.Getter;
@Getter
public enum ExpireTimeEnum {
EXPIRE_FOR_EVER(DurationTimeEnum.FOR_EVER, -1l, "无期"),
EXPIRE_ONLY_ONCE(DurationTimeEnum.ONLY_ONCE, 0l, "一次"),
EXPIRE_05_MIN(DurationTimeEnum.TIME_VALUE, 5 * 60l, "5分钟"),
EXPIRE_30_MIN(DurationTimeEnum.TIME_VALUE, 30 * 60l, "30分钟"),
EXPIRE_01_HOUR(DurationTimeEnum.TIME_VALUE, 1 * 3600l, "1小时"),
EXPIRE_12_HOUR(DurationTimeEnum.TIME_VALUE, 12 * 3600l, "12小时"),
EXPIRE_01_DAY(DurationTimeEnum.TIME_VALUE, 24 * 3600l, "1天"),
EXPIRE_15_DAY(DurationTimeEnum.TIME_VALUE, 15 * 24 * 3600l, "15天"),
EXPIRE_01_MOUTH(DurationTimeEnum.TIME_VALUE, 30 * 24 * 3600l, "1个月"),
EXPIRE_UNKNOWN(DurationTimeEnum.TIME_VALUE, Long.MAX_VALUE, "未知"),
;
private DurationTimeEnum duration;
private long value;
private String description;
ExpireTimeEnum(DurationTimeEnum duration, long value, String description) {
this.duration = duration;
this.value = value;
this.description = description;
}
public static ExpireTimeEnum from(DurationTimeEnum duration, long expireAt) {
for (ExpireTimeEnum expireTimeEnum : values()) {
if (expireTimeEnum.getDuration().equals(duration)) {
if (expireAt == expireTimeEnum.getValue()) {
return expireTimeEnum;
}
}
}
return EXPIRE_UNKNOWN;
}
}
package com.gitee.sqlrest.common.enums;
public enum HttpMethodEnum {
GET, HEAD, PUT, POST, DELETE,
;
public static boolean exists(String method) {
for (HttpMethodEnum methodEnum : values()) {
if (methodEnum.name().equals(method)) {
return true;
}
}
return false;
}
}
package com.gitee.sqlrest.common.enums;
public enum OnOffEnum {
ON, OFF;
}
package com.gitee.sqlrest.common.enums;
import java.util.function.Function;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
@Getter
public enum ParamTypeEnum {
LONG("整型", "number", (String str) -> StringUtils.isNotBlank(str) ? Long.valueOf(str) : str),
DOUBLE("浮点型", "number", (String str) -> StringUtils.isNotBlank(str) ? Double.valueOf(str) : str),
STRING("字符串", "string", (String str) -> str),
DATE("日期", "string", (String str) -> str),
TIME("时间", "string", (String str) -> str),
;
private String name;
private String jsType;
private Function<String, Object> converter;
ParamTypeEnum(String name, String jsType, Function<String, Object> converter) {
this.name = name;
this.jsType = jsType;
this.converter = converter;
}
}
package com.gitee.sqlrest.common.enums;
public enum WhiteBlackEnum {
WHITE, BLACK;
}
package com.gitee.sqlrest.common.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class CommonException extends RuntimeException {
private ResponseErrorCode code;
private String message;
}
package com.gitee.sqlrest.common.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ResponseErrorCode {
SUCCESS(0, "success"),
ERROR_INTERNAL_ERROR(1, "internal error"),
ERROR_INVALID_ARGUMENT(2, "invalid arguments"),
ERROR_RESOURCE_NOT_EXISTS(3, "resource not exists"),
ERROR_RESOURCE_ALREADY_EXISTS(4, "resource already exists"),
ERROR_RESOURCE_ALREADY_USED(5, "resource already been used"),
ERROR_USER_NOT_EXISTS(7, "user not exists"),
ERROR_USER_PASSWORD_WRONG(8, "invalid password"),
ERROR_INVALID_JDBC_URL(9, "invalid jdbc url format"),
ERROR_CANNOT_CONNECT_REMOTE(10, "remote address not reach"),
ERROR_EDIT_ALREADY_PUBLISHED(11, "can not edit already publish(online)"),
ERROR_CLIENT_FORBIDDEN(403, "client is forbidden"),
ERROR_ACCESS_FORBIDDEN(403, "access forbidden"),
ERROR_TOKEN_EXPIRED(401, "token is expired"),
ERROR_PATH_NOT_EXISTS(404, "path not exists"),
;
private int code;
private String message;
}
package com.gitee.sqlrest.common.model;
import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
public class JarFileClassLoader extends URLClassLoader {
public JarFileClassLoader(String path, ClassLoader parent) {
this(new String[]{path}, parent);
}
public JarFileClassLoader(String[] paths, ClassLoader parent) {
super(getURLs(paths), parent);
}
private static URL[] getURLs(String[] paths) {
if (null == paths || 0 == paths.length) {
throw new IllegalArgumentException("jar file path is empty.");
}
List<String> dirs = new ArrayList<>();
for (String path : paths) {
dirs.add(path);
collectDirs(path, dirs);
}
List<URL> urls = new ArrayList<>();
for (String path : dirs) {
urls.addAll(doGetURLs(path));
}
if (urls.isEmpty()) {
throw new RuntimeException("No jar file found from path :"
+ Arrays.stream(paths).collect(Collectors.joining(",")) + "!");
}
return urls.toArray(new URL[0]);
}
private static void collectDirs(String path, List<String> collector) {
if (StringUtils.isEmpty(path)) {
return;
}
File current = new File(path);
if (!current.exists() || !current.isDirectory()) {
return;
}
for (File child : current.listFiles()) {
if (!child.isDirectory()) {
continue;
}
collector.add(child.getAbsolutePath());
collectDirs(child.getAbsolutePath(), collector);
}
}
private static List<URL> doGetURLs(final String path) {
File jarPath = new File(path);
if (!jarPath.exists() || !jarPath.isDirectory()) {
return Collections.emptyList();
}
FileFilter jarFilter = name -> name.getName().endsWith(".jar");
File[] allJars = new File(path).listFiles(jarFilter);
List<URL> jarURLs = new ArrayList<>(allJars.length);
for (int i = 0; i < allJars.length; i++) {
try {
jarURLs.add(allJars[i].toURI().toURL());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return jarURLs;
}
}
package com.gitee.sqlrest.common.model;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Objects;
import java.util.Properties;
import java.util.logging.Logger;
import javax.sql.DataSource;
import lombok.Getter;
@Getter
public class SimpleDataSource implements DataSource {
private final ClassLoader classLoader;
private final String jdbcUrl;
private final String driverClassName;
private final Properties properties;
public SimpleDataSource(ClassLoader cl, String jdbcUrl, String driverClassName, String username,
String password, Properties properties) {
this.classLoader = Objects.requireNonNull(cl, "parameter invalid for empty class loader");
this.jdbcUrl = Objects.requireNonNull(jdbcUrl, "parameter invalid for empty jdbc url");
this.driverClassName = Objects.requireNonNull(driverClassName, "parameter invalid for empty driver class name");
this.properties = Objects.requireNonNull(properties, "parameter invalid for properties ");
if (username != null) {
this.properties.put("user", properties.getProperty("user", username));
}
if (password != null) {
this.properties.put("password", properties.getProperty("password", password));
}
}
@Override
public Connection getConnection() throws SQLException {
return doGetConnection(properties);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
final Properties cloned = (Properties) properties.clone();
if (username != null) {
cloned.put("user", username);
if (cloned.containsKey("username")) {
cloned.put("username", username);
}
}
if (password != null) {
cloned.put("password", password);
}
return doGetConnection(cloned);
}
private Connection doGetConnection(Properties properties) throws SQLException {
Driver driver = null;
try {
Class<?> driverType = Class.forName(driverClassName, true, classLoader);
driver = (Driver) driverType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new SQLException("Invalid driver class name [" + driverClassName + "]. Cause: " + e);
}
Connection connection = driver.connect(jdbcUrl, properties);
if (null == connection) {
throw new SQLException(
"Maybe invalid driver class name [" + driverClassName + "] or url [" + jdbcUrl + "]");
}
return connection;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
throw new SQLFeatureNotSupportedException();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
DriverManager.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
return DriverManager.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
throw new SQLFeatureNotSupportedException();
}
}
package com.gitee.sqlrest.common.util;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public final class CacheUtils {
// 缓存时间 2 hours
public static final long CACHE_DURATION_SECONDS = 7200L;
private static Cache<String, Object> loadingCache = CacheBuilder.newBuilder()
/*设置缓存容器的初始容量大小为10*/
.initialCapacity(10)
/*设置缓存容器的最大容量大小为1000*/
.maximumSize(1000)
/*设置记录缓存命中率*/
.recordStats()
/*设置并发级别为8,智并发基本值可以同事些缓存的线程数*/
.concurrencyLevel(8)
/*设置过期时间为15分钟*/
.expireAfterAccess(CACHE_DURATION_SECONDS, TimeUnit.SECONDS)
.build();
public static void put(String key, Object value) {
loadingCache.put(key, value);
}
public static Object get(String key) {
return loadingCache.getIfPresent(key);
}
public static void remove(String key) {
loadingCache.invalidate(key);
}
public static void clear() {
loadingCache.invalidateAll();
}
public static Map<String, Object> getAll() {
return loadingCache.asMap();
}
public static Collection<Object> getAllValue() {
return loadingCache.asMap().values();
}
}
\ No newline at end of file
package com.gitee.sqlrest.common.util;
import cn.hutool.crypto.digest.BCrypt;
/**
* 密码工具类
*/
public final class PasswordUtils {
public static String encryptPassword(String password, String credentialsSalt) {
return BCrypt.hashpw(password, credentialsSalt);
}
public static void main(String[] args) {
String password = "123456";
String credentialsSalt = "$2a$10$eUanVjvzV27BBxAb4zuBCu";
String newPassword = encryptPassword(password, credentialsSalt);
System.out.println(newPassword);
System.out.println(credentialsSalt);
}
}
package com.gitee.sqlrest.common.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.URLUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Paths;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
/**
* 获取项目的版本号工具类
*/
@Slf4j
@UtilityClass
public final class PomVersionUtils {
private static final String PREFIX = "version=";
public static String getProjectVersion() {
Class<?> clazz = PomVersionUtils.class;
String resourcePath = clazz.getResource("").toString();
if (resourcePath.startsWith("file:")) {
return getProjectVersionFromFile(resourcePath);
} else if (resourcePath.startsWith("jar:")) {
return getProjectVersionFromJar(clazz);
} else {
return null;
}
}
private static String getProjectVersionFromFile(String classPath) {
String basePath = classPath.substring(0, classPath.indexOf("/classes/"));
basePath = URLUtil.decode(FileUtil.normalize(basePath));
File propertiesFile = Paths.get(basePath, "maven-archiver", "pom.properties").toFile();
if (propertiesFile.exists()) {
return extractPomVersion(FileUtil.getInputStream(propertiesFile));
}
return null;
}
private static String getProjectVersionFromJar(Class<?> clazz) {
ProtectionDomain protectionDomain = clazz.getProtectionDomain();
CodeSource codeSource = protectionDomain.getCodeSource();
try (JarFile jarFile = new JarFile(codeSource.getLocation().getPath())) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().startsWith("META-INF/maven/") && entry.getName().endsWith("/pom.properties")) {
return extractPomVersion(jarFile.getInputStream(entry));
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static String extractPomVersion(InputStream inputStream) {
String line;
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
while ((line = bufferedReader.readLine()) != null) {
if (line.startsWith(PREFIX)) {
return line.substring(PREFIX.length());
}
}
} catch (IOException e) {
}
return null;
}
public static void main(String[] args) {
System.out.println(getProjectVersion());
}
}
package com.gitee.sqlrest.common.util;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
* 获取Servlet服务器的HTTP参数相关工具类
*/
@Slf4j
public final class ServletUtils {
public static String getDomain(HttpServletRequest request) {
StringBuffer url = request.getRequestURL();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
}
public static String getOrigin(HttpServletRequest request) {
return request.getHeader("Origin");
}
public static String getPathUri(HttpServletRequest request) {
return request.getRequestURI();
}
public static String getUserAgent(HttpServletRequest request) {
return request.getHeader("user-agent");
}
/**
* 获取IP地址
* <p>
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* </p>
* <p>
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中 第一个非unknown的有效IP字符串,则为真实IP地址.
* </p>
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = "0.0.0.0";
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
log.error("get client IP address error: ", e);
}
return ip;
}
}
package com.gitee.sqlrest.common.util;
import java.security.MessageDigest;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
* Token工具类
*/
@Slf4j
public final class TokenUtils {
private static final char[] hexCode = "0123456789abcdefgh".toCharArray();
public static String getRequestToken(HttpServletRequest httpRequest) {
// 从header中获取token
String authorization = httpRequest.getHeader("Authorization");
if (!StringUtils.isEmpty(authorization)) {
String[] splitString = authorization.split(" ");
if (splitString.length == 2 && "Bearer".equalsIgnoreCase(splitString[0])) {
return splitString[1];
}
}
// 如果header中不存在token,则从参数中获取token
if (StringUtils.isEmpty(authorization)) {
return httpRequest.getParameter("token");
}
return null;
}
public static String generateValue() {
return generateValue(UUID.randomUUID().toString());
}
protected static String generateValue(String param) {
try {
MessageDigest algorithm = MessageDigest.getInstance("MD5");
algorithm.reset();
algorithm.update(param.getBytes());
byte[] messageDigest = algorithm.digest();
StringBuilder r = new StringBuilder(messageDigest.length * 2);
for (byte b : messageDigest) {
r.append(hexCode[(b >> 4) & 0xF]);
r.append(hexCode[(b & 0xF)]);
}
return r.toString();
} catch (Exception e) {
throw new RuntimeException("Generate Token String failed: " + e.toString());
}
}
}
package com.gitee.sqlrest.common.util;
import java.util.UUID;
import lombok.experimental.UtilityClass;
/**
* UUID工具类
*/
@UtilityClass
public final class UuidUtils {
public static String generateUuid() {
return UUID.randomUUID().toString().replace("-", "");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sqlrest-parent</artifactId>
<groupId>com.gitee.sqlrest</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sqlrest-core</artifactId>
<dependencies>
<dependency>
<groupId>com.gitee.sqlrest</groupId>
<artifactId>sqlrest-template</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.gitee.sqlrest</groupId>
<artifactId>sqlrest-script</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.gitee.sqlrest</groupId>
<artifactId>sqlrest-persistence</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.gitee.sqlrest</groupId>
<artifactId>sqlrest-cache</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.gitee.sqlrest.core.driver;
import cn.hutool.core.io.FileUtil;
import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import com.gitee.sqlrest.core.dto.DatabaseTypeDriverResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class DriverLoadService {
private Map<ProductTypeEnum, Map<String, File>> drivers = new EnumMap<>(ProductTypeEnum.class);
@Value("${datasource.driver.base-path}")
private String driversBasePath;
@EventListener(ApplicationReadyEvent.class)
public void loadDrivers() {
try {
doLoadDrivers();
log.info("Finish load jdbc drivers from local path: {}", driversBasePath);
} catch (Exception e) {
log.error("load drivers failed:{}", e.getMessage(), e);
throw e;
}
}
private void doLoadDrivers() {
File file = new File(driversBasePath);
File[] types = file.listFiles();
if (ArrayUtils.isEmpty(types)) {
throw new IllegalArgumentException(
"No drivers type found from path:" + driversBasePath);
}
for (File type : types) {
if (!ProductTypeEnum.exists(type.getName())) {
continue;
}
File[] driverVersions = type.listFiles();
if (ArrayUtils.isEmpty(driverVersions)) {
throw new IllegalArgumentException(
"No driver version found from path:" + type.getAbsolutePath());
}
for (File driverVersion : driverVersions) {
if (ArrayUtils.isEmpty(driverVersion.listFiles())) {
throw new IllegalArgumentException(
"No driver version jar file found from path:" + driverVersion.getAbsolutePath());
}
ProductTypeEnum typeEnum = ProductTypeEnum.of(type.getName());
Map<String, File> versionMap = drivers.computeIfAbsent(typeEnum, k -> new HashMap<>());
versionMap.put(driverVersion.getName(), driverVersion);
log.info("Load driver for {} ,version:{},path:{}",
typeEnum.getName(), driverVersion.getName(), driverVersion.getAbsolutePath());
}
}
}
public List<String> getDriverVersion(ProductTypeEnum dbTypeEnum) {
return Optional.ofNullable(drivers.get(dbTypeEnum)).orElseGet(HashMap::new)
.keySet().stream().collect(Collectors.toList());
}
public Map<String, File> getDriverVersionWithPath(ProductTypeEnum dbTypeEnum) {
return Optional.ofNullable(drivers.get(dbTypeEnum)).orElse(new HashMap<>());
}
public File getVersionDriverFile(ProductTypeEnum dbTypeEnum, String driverVersion) {
return drivers.get(dbTypeEnum).get(driverVersion);
}
public List<DatabaseTypeDriverResponse> getDrivers(ProductTypeEnum dbTypeEnum) {
List<DatabaseTypeDriverResponse> lists = new ArrayList<>();
getDriverVersionWithPath(dbTypeEnum)
.forEach(
(k, v) ->
lists.add(
DatabaseTypeDriverResponse.builder()
.driverVersion(k)
.driverClass(dbTypeEnum.getDriver())
.driverPath(v.getAbsolutePath())
.jarFiles(
FileUtil.listFileNames(v.getAbsolutePath())
)
.build()
)
);
return lists;
}
}
package com.gitee.sqlrest.core.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import com.gitee.sqlrest.common.enums.OnOffEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.sql.Timestamp;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("API配置简单详情")
public class ApiAssignmentBaseResponse {
@ApiModelProperty("ID编号")
private Long id;
@ApiModelProperty("API配置名称")
private String name;
@ApiModelProperty("API请求方法:GET, HEAD, PUT, POST, DELETE")
private HttpMethodEnum method;
@ApiModelProperty("请求路径(不带api前缀)")
private String path;
@ApiModelProperty("是否发布")
private Boolean status;
@ApiModelProperty("是否公开")
private Boolean open;
@ApiModelProperty("执行引擎")
private ExecuteEngineEnum engine;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createTime;
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp updateTime;
}
package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import com.gitee.sqlrest.persistence.entity.ApiContextEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("API配置详细详情")
public class ApiAssignmentDetailResponse extends ApiAssignmentBaseResponse {
@ApiModelProperty("分组ID")
private Long groupId;
@ApiModelProperty("模块ID")
private Long moduleId;
@ApiModelProperty("数据源ID")
private Long datasourceId;
@ApiModelProperty("描述")
private String description;
@ApiModelProperty("接口入参")
private List<ItemParam> params;
@ApiModelProperty("HTTP请求的contentType")
private String contentType;
@ApiModelProperty("SQL列表")
private List<ApiContextEntity> sqlList;
}
package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("API配置")
public class ApiAssignmentSaveRequest {
@ApiModelProperty("ID编号(保存接口使用)")
private Long id;
@ApiModelProperty("分组ID")
private Long groupId;
@ApiModelProperty("模块ID")
private Long moduleId;
@ApiModelProperty("数据源ID")
private Long datasourceId;
@ApiModelProperty("API配置名称")
private String name;
@ApiModelProperty("描述")
private String description;
@ApiModelProperty("API请求方法:GET, HEAD, PUT, POST, DELETE")
private HttpMethodEnum method;
@ApiModelProperty("HTTP请求的contentType")
private String contentType;
@ApiModelProperty("请求路径(不带api前缀)")
private String path;
@ApiModelProperty("是否公开")
private Boolean open;
@ApiModelProperty("执行引擎:SQL, SCRIPT")
private ExecuteEngineEnum engine;
@ApiModelProperty("SQL列表")
private List<String> contextList;
@ApiModelProperty("接口入参")
private List<ItemParam> params;
}
package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.dto.ParamValue;
import com.gitee.sqlrest.common.enums.ExecuteEngineEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("SQL调试执行")
public class ApiDebugExecuteRequest {
@ApiModelProperty("数据源的ID")
private Long dataSourceId;
@ApiModelProperty("执行引擎:SQL, SCRIPT")
private ExecuteEngineEnum engine;
@ApiModelProperty("SQL列表")
private List<String> contextList;
@ApiModelProperty("接口入参列表")
private List<ParamValue> paramValues;
}
package com.gitee.sqlrest.core.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.gitee.sqlrest.common.enums.DurationTimeEnum;
import com.gitee.sqlrest.common.enums.ExpireTimeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.sql.Timestamp;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("客户端应用详情")
public class AppClientDetailResponse {
@ApiModelProperty("ID编号")
private Long id;
@ApiModelProperty("客户端应用名称")
private String name;
@ApiModelProperty("客户端应用描述")
private String description;
@ApiModelProperty("应用AppKey账号")
private String appKey;
@ApiModelProperty("到期类型")
private DurationTimeEnum expireDuration;
@ApiModelProperty("到期时间")
private Long expireAt;
@ApiModelProperty("到期时间(字符串)")
private String expireAtStr;
@ApiModelProperty("过期类型")
private String expireType;
@ApiModelProperty("是否过期")
private Boolean isExpired;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createTime;
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp updateTime;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("客户端分组关联")
public class AppClientGroupRequest {
@ApiModelProperty("客户端应用ID")
private Long id;
@ApiModelProperty("分组ID列表")
private List<Long> groupIds;
}
package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.enums.ExpireTimeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("客户端应用信息")
public class AppClientSaveRequest {
@ApiModelProperty("客户端应用名称")
private String name;
@ApiModelProperty("客户端应用描述")
private String description;
@ApiModelProperty("应用AppKey账号")
private String appKey;
@ApiModelProperty("到期时间")
private ExpireTimeEnum expireTime;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("列表搜索")
public class AssignmentSearchRequest extends EntitySearchRequest {
@ApiModelProperty("分组ID")
private Long groupId;
@ApiModelProperty("模块ID")
private Long moduleId;
@ApiModelProperty("是否发布")
private Boolean publish;
@ApiModelProperty("是否公开")
private Boolean open;
}
package com.gitee.sqlrest.core.dto;
import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("数据源保存")
public class DataSourceSaveRequest {
@ApiModelProperty("ID编号")
private Long id;
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("类型")
private ProductTypeEnum type;
@ApiModelProperty("驱动版本")
private String version;
@ApiModelProperty("驱动类型")
private String driver;
@ApiModelProperty("连接JDBC-URL")
private String url;
@ApiModelProperty("账号")
private String username;
@ApiModelProperty("密码")
private String password;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
@ApiModel("数据库类型")
public class DatabaseTypeDetailResponse {
@ApiModelProperty("编号")
private Integer id;
@ApiModelProperty("数据库类型")
private String type;
@ApiModelProperty("驱动类")
private String driver;
@ApiModelProperty("连接串样例")
private String sample;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
@ApiModel("驱动版本")
public class DatabaseTypeDriverResponse {
@ApiModelProperty("驱动版本")
private String driverVersion;
@ApiModelProperty("驱动类名")
private String driverClass;
@ApiModelProperty("版本路径")
private String driverPath;
@ApiModelProperty("驱动JAR")
private List<String> jarFiles;
}
package com.gitee.sqlrest.core.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.gitee.sqlrest.common.enums.ProductTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.sql.Timestamp;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
@ApiModel("数据源详情")
public class DatasourceDetailResponse {
@ApiModelProperty("ID编号")
private Long id;
@ApiModelProperty("标题")
private String name;
@ApiModelProperty("数据库类型")
private ProductTypeEnum type;
@ApiModelProperty("驱动版本")
private String version;
@ApiModelProperty("驱动类")
private String driver;
@ApiModelProperty("URL连接串")
private String url;
@ApiModelProperty("账号名")
private String username;
@ApiModelProperty("密码")
private String password;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createTime;
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp updateTime;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("带ID的名称")
public class EntityIdNameResponse {
@ApiModelProperty("ID编号")
private Long id;
@ApiModelProperty("名称")
private String name;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@ApiModel("列表搜索")
public class EntitySearchRequest {
@ApiModelProperty("页号")
private Integer page;
@ApiModelProperty("页大小")
private Integer size;
@ApiModelProperty("关键词")
private String searchText;
}
package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@ApiModel("列信息")
@NoArgsConstructor
@AllArgsConstructor
public class MetadataColumnResponse {
@ApiModelProperty("列名")
private String name;
@ApiModelProperty("列类型")
private String type;
@ApiModelProperty("注释")
private String remarks;
}
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;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("SQL参数解析")
public class SqlParamParseResponse {
@ApiModelProperty("参数名")
private String name;
@ApiModelProperty("是否为数组")
private Boolean isArray;
}
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.
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.
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.
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.
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.
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 diff is collapsed. Click to expand it.
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