[update] 添加流量控制

This commit is contained in:
wujiawei
2026-01-30 16:58:47 +08:00
parent 991e44638b
commit 570b19f46c
16 changed files with 521 additions and 25 deletions

View File

@@ -1,9 +1,10 @@
package org.framework.lazy.cloud.network.heartbeat.client;
import org.framework.lazy.cloud.network.heartbeat.protocol.log.ProxyLog;
import org.springframework.context.annotation.ComponentScan;
import org.wu.framework.lazy.orm.core.stereotype.LazyScan;
@ComponentScan(basePackages = "org.framework.lazy.cloud.network.heartbeat.client")
@LazyScan(scanBasePackages = "org.framework.lazy.cloud.network.heartbeat.client.infrastructure.entity")
@LazyScan(scanBasePackages = "org.framework.lazy.cloud.network.heartbeat.client.infrastructure.entity",scanClass = ProxyLog.class)
public class EnableClientAutoConfiguration {
}

View File

@@ -0,0 +1,48 @@
package org.framework.lazy.cloud.network.heartbeat.client.application;
import org.framework.lazy.cloud.network.heartbeat.client.application.command.lazy.netty.server.properties.*;
import org.framework.lazy.cloud.network.heartbeat.client.application.command.proxy.log.LazyProxyLogListCommand;
import org.framework.lazy.cloud.network.heartbeat.client.application.dto.LazyNettyServerPropertiesDTO;
import org.framework.lazy.cloud.network.heartbeat.client.application.dto.ProxyLogDTO;
import org.framework.lazy.cloud.network.heartbeat.client.domain.model.lazy.netty.server.properties.LazyNettyServerProperties;
import org.wu.framework.lazy.orm.database.lambda.domain.LazyPage;
import org.wu.framework.web.response.Result;
import java.util.List;
/**
* describe 服务端配置信息
*
* @author Jia wei Wu
* @date 2024/04/03 03:00 下午
* @see org.wu.framework.lazy.orm.core.persistence.reverse.lazy.ddd.DefaultDDDLazyApplication
**/
public interface LazyProxyLogApplication {
/**
* describe 分页查询代理日志信息
*
* @param size 每页条数
* @param current 当前页码
* @param lazyProxyLogListCommand 代理日志信息查询参数
* @return {@link Result<LazyPage<ProxyLogDTO>>} 代理日志信息分页数据传输对象
*
* @author Jia wei Wu
* @date 2024/06/10 10:00 上午
**/
Result<LazyPage<ProxyLogDTO>> findPage(int size, int current, LazyProxyLogListCommand lazyProxyLogListCommand);
/**
* describe 清空代理日志
*
* @return {@link Result<?>} 清空结果
*
* @author Jia wei Wu
* @date 2024/06/10 10:00 上午
**/
Result<?> cleanLogs();
}

View File

@@ -0,0 +1,11 @@
package org.framework.lazy.cloud.network.heartbeat.client.application;
import org.framework.lazy.cloud.network.heartbeat.client.application.dto.SysConfigDTO;
import org.wu.framework.web.response.Result;
public interface SysConfigApplication {
/**
* 获取配置
*/
Result<SysConfigDTO> getConfig();
}

View File

@@ -0,0 +1,19 @@
package org.framework.lazy.cloud.network.heartbeat.client.application.command.proxy.log;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class LazyProxyLogListCommand {
private String requestId;
private String host;
private Integer port;
private String visitorId;
}

View File

@@ -0,0 +1,46 @@
package org.framework.lazy.cloud.network.heartbeat.client.application.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* describe 代理日志信息
*
* @author Jia wei Wu
* @date 2024/06/10 11:28 上午
**/
@Data
public class ProxyLogDTO {
/**
* 请求ID
*/
@Schema(description = "请求ID",name = "requestId")
private String requestId;
/**
* 主机地址
*/
@Schema(description = "主机地址",name = "host")
private String host;;
/**
* 端口号
*/
@Schema(description = "端口号",name = "port")
private Integer port;
/**
* 访客ID
*/
@Schema(description = "访客ID",name = "visitorId")
private String visitorId;
/**
* 接收数据
*/ @Schema(description = "接收数据",name = "receiver")
private byte[] receiver;
/**
* 发送数据
*/
@Schema(description = "发送数据",name = "send")
private byte[] send;
}

View File

@@ -0,0 +1,42 @@
package org.framework.lazy.cloud.network.heartbeat.client.application.dto;
import lombok.Data;
import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties;
/**
* describe 系统配置信息
*/
@Data
public class SysConfigDTO {
/**
* 是否验证权限账号
*/
private Boolean authentication = false;
/**
* 是否允许记录代理日志
*/
private Boolean enableProxyLog = true;
/**
* 发送数据对应通道
*/
private String sendMsgQueue="wlcn-send-queue";
/**
* 接收数据对应通道
*/
private String receiverMsgQueue="wlcn-receiver-queue";
/**
* http协议代理
*/
private ProtocolProxyProperties.HttpProtocolProxy httpProtocolProxy = new ProtocolProxyProperties.HttpProtocolProxy();
/**
* socket 协议代理
*/
private ProtocolProxyProperties.SocketProtocolProxy socketProtocolProxy = new ProtocolProxyProperties.SocketProtocolProxy();
/**
* 服务端口
*/
private Integer serverPort;
}

View File

@@ -0,0 +1,56 @@
package org.framework.lazy.cloud.network.heartbeat.client.application.impl;
import jakarta.annotation.Resource;
import org.framework.lazy.cloud.network.heartbeat.client.application.LazyProxyLogApplication;
import org.framework.lazy.cloud.network.heartbeat.client.application.command.proxy.log.LazyProxyLogListCommand;
import org.framework.lazy.cloud.network.heartbeat.client.application.dto.ProxyLogDTO;
import org.framework.lazy.cloud.network.heartbeat.protocol.log.ProxyLog;
import org.wu.framework.lazy.orm.database.lambda.domain.LazyPage;
import org.wu.framework.lazy.orm.database.lambda.stream.lambda.LazyLambdaStream;
import org.wu.framework.lazy.orm.database.lambda.stream.wrapper.LazyWrappers;
import org.wu.framework.lazy.orm.web.plus.stereotype.LazyApplication;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;
import java.util.List;
@LazyApplication
public class LazyProxyLogApplicationImpl implements LazyProxyLogApplication {
@Resource
private LazyLambdaStream lazyLambdaStream;
@Override
public Result<LazyPage<ProxyLogDTO>> findPage(int size, int current, LazyProxyLogListCommand lazyProxyLogListCommand) {
LazyPage<ProxyLogDTO> lazyPage = LazyPage.of(current, size);
LazyPage<ProxyLogDTO> proxyLogDTOLazyPage = lazyLambdaStream.selectPage(
LazyWrappers.<ProxyLog>lambdaWrapper()
.notNull(ProxyLog::getRequestId)
// .eqIgnoreEmpty(ProxyLog::getHost, lazyProxyLogListCommand.getHost())
// .eqIgnoreEmpty(ProxyLog::getPort, lazyProxyLogListCommand.getPort())
.orderByDesc(ProxyLog::getCreateTime),
lazyPage,
ProxyLogDTO.class
);
return ResultFactory.successOf(proxyLogDTOLazyPage);
}
/**
* describe 清空代理日志
*
* @return {@link Result<?>} 清空结果
* @author Jia wei Wu
* @date 2024/06/10 10:00 上午
**/
@Override
public Result<?> cleanLogs() {
Integer delete = lazyLambdaStream.delete(LazyWrappers.<ProxyLog>lambdaWrapper()
.notNull(ProxyLog::getRequestId)
);
return ResultFactory.successOf();
}
}

View File

@@ -0,0 +1,45 @@
package org.framework.lazy.cloud.network.heartbeat.client.application.impl;
import jakarta.annotation.Resource;
import org.framework.lazy.cloud.network.heartbeat.client.application.SysConfigApplication;
import org.framework.lazy.cloud.network.heartbeat.client.application.dto.SysConfigDTO;
import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties;
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
import org.wu.framework.lazy.orm.web.plus.stereotype.LazyApplication;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;
@LazyApplication
public class SysConfigApplicationImpl implements SysConfigApplication {
@Resource
private ServerProperties serverProperties;
@Resource
private ProtocolProxyProperties protocolProxyProperties;
/**
* 获取配置
*/
@Override
public Result<SysConfigDTO> getConfig() {
SysConfigDTO sysConfigDTO = new SysConfigDTO();
Boolean authentication = protocolProxyProperties.getAuthentication();
Boolean enableProxyLog = protocolProxyProperties.getEnableProxyLog();
String receiverMsgQueue = protocolProxyProperties.getReceiverMsgQueue();
String sendMsgQueue = protocolProxyProperties.getSendMsgQueue();
ProtocolProxyProperties.SocketProtocolProxy socketProtocolProxy = protocolProxyProperties.getSocketProtocolProxy();
ProtocolProxyProperties.HttpProtocolProxy httpProtocolProxy = protocolProxyProperties.getHttpProtocolProxy();
sysConfigDTO.setAuthentication(authentication);
sysConfigDTO.setEnableProxyLog(enableProxyLog);
sysConfigDTO.setReceiverMsgQueue(receiverMsgQueue);
sysConfigDTO.setSendMsgQueue(sendMsgQueue);
sysConfigDTO.setSocketProtocolProxy(socketProtocolProxy);
sysConfigDTO.setHttpProtocolProxy(httpProtocolProxy);
sysConfigDTO.setServerPort(serverProperties.getPort());
return ResultFactory.successOf(sysConfigDTO);
}
}

View File

@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 属性类型
* 配置类型 DB.数据库配置 CONFIG.配置文件配置
*/
@AllArgsConstructor
@Getter

View File

@@ -0,0 +1,46 @@
package org.framework.lazy.cloud.network.heartbeat.client.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.annotation.Resource;
import org.framework.lazy.cloud.network.heartbeat.client.application.LazyProxyLogApplication;
import org.framework.lazy.cloud.network.heartbeat.client.application.command.proxy.log.LazyProxyLogListCommand;
import org.framework.lazy.cloud.network.heartbeat.client.application.dto.ProxyLogDTO;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestParam;
import org.wu.framework.lazy.orm.database.lambda.domain.LazyPage;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.spring.EasyController;
/**
* description 代理日志提供者
*
* @author 吴佳伟
* @date 2024/06/10 10:27
*/
@EasyController("/v1/api/proxy/log")
public class ProxyLogProvider {
@Resource
private LazyProxyLogApplication lazyProxyLogApplication;
@Operation(summary = "获取代理日志分页数据")
@GetMapping("/findPage")
public Result<LazyPage<ProxyLogDTO>> findPage(@Parameter(description = "分页大小") @RequestParam(defaultValue = "10", value = "size") int size,
@Parameter(description = "当前页数") @RequestParam(defaultValue = "1", value = "current") int current,
@ModelAttribute LazyProxyLogListCommand lazyProxyLogListCommand) {
return lazyProxyLogApplication.findPage(size, current, lazyProxyLogListCommand);
}
/**
* 清空日志
*/
@Operation(summary = "清空日志")
@DeleteMapping("/cleanLogs")
public Result<?> cleanLogs() {
return lazyProxyLogApplication.cleanLogs();
}
}

View File

@@ -0,0 +1,76 @@
package org.framework.lazy.cloud.network.heartbeat.client.controller;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import org.framework.lazy.cloud.network.heartbeat.client.application.SysConfigApplication;
import org.framework.lazy.cloud.network.heartbeat.client.application.dto.SysConfigDTO;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;
import org.wu.framework.web.spring.EasyController;
/**
* description 代理日志提供者
*
* @author 吴佳伟
* @date 2024/06/10 10:27
*/
@EasyController("/v1/api/system")
public class SysConfigProvider {
@Resource
private SysConfigApplication sysConfigApplication;
// 注入Spring应用上下文核心
@Resource
private ApplicationContext applicationContext;
@Operation(summary = "获取配置")
@GetMapping("/config")
public Result<SysConfigDTO> getConfig() {
return sysConfigApplication.getConfig();
}
/**
* 保存配置
*/
@Operation(summary = "保存配置")
@PostMapping("/config")
public Result<SysConfigDTO> saveConfig() {
return sysConfigApplication.getConfig();
}
/**
* 重启SpringBoot服务接口
*
* @return 重启结果
*/
@PostMapping("/restart")
public Result<String> restartServer() {
try {
Class<?> mainClass = applicationContext.getAutowireCapableBeanFactory()
.getBean(SpringApplication.class).getMainApplicationClass();
// 异步执行重启逻辑(必须异步,否则接口请求会因服务重启被中断,无返回结果)
new Thread(() -> {
// 步骤1关闭当前Spring应用优雅销毁旧容器、释放所有资源
SpringApplication.exit(applicationContext, () -> 0);
// 步骤2重新创建SpringApplication实例启动新容器核心重启操作
SpringApplication.run(mainClass, new String[]{});
}).start();
return ResultFactory.successOf("服务重启成功!");
} catch (Exception e) {
e.printStackTrace();
return ResultFactory.errorOf("服务重启失败:" + e.getMessage());
}
}
}

View File

@@ -2,7 +2,6 @@ package org.framework.lazy.cloud.network.heartbeat.protocol.context;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.nio.NioIoHandler;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import jakarta.annotation.PreDestroy;
@@ -16,8 +15,8 @@ import org.springframework.stereotype.Component;
@Component
public class NettySocketProxySocketApplicationListener implements SocketApplicationListener {
private final EventLoopGroup bossGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
private final EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup;
private final NettyTcpProxyFilter nettyTcpProxyFilter;// 通道业务处理
private final ProtocolProxyProperties protocolProxyProperties;
private ChannelFuture channelFuture;
@@ -25,6 +24,10 @@ public class NettySocketProxySocketApplicationListener implements SocketApplicat
public NettySocketProxySocketApplicationListener(NettyTcpProxyFilter nettyTcpProxyFilter, ProtocolProxyProperties protocolProxyProperties) {
this.nettyTcpProxyFilter = nettyTcpProxyFilter;
this.protocolProxyProperties = protocolProxyProperties;
ProtocolProxyProperties.SocketProtocolProxy socketProtocolProxy = protocolProxyProperties.getSocketProtocolProxy();
log.info("Socket 协议代理 启动线程数 【boss:{}|worker:{}】", socketProtocolProxy.getBossThreadNum(), socketProtocolProxy.getWorkerThreadNum());
bossGroup = new MultiThreadIoEventLoopGroup(socketProtocolProxy.getBossThreadNum(), NioIoHandler.newFactory());
workerGroup = new MultiThreadIoEventLoopGroup(socketProtocolProxy.getWorkerThreadNum(), NioIoHandler.newFactory());
}
@@ -37,19 +40,22 @@ public class NettySocketProxySocketApplicationListener implements SocketApplicat
public void doRunning() throws Exception {
ProtocolProxyProperties.SocketProtocolProxy socketProtocolProxy = protocolProxyProperties.getSocketProtocolProxy();
Integer socketProtocolProxyPort = socketProtocolProxy.getPort();
Integer readBufferSize = socketProtocolProxy.getReadBufferSize();
Integer writeBufferSize = socketProtocolProxy.getWriteBufferSize();
Integer connectTimeoutMillis = socketProtocolProxy.getConnectTimeoutMillis();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
// 给服务端channel设置属性
// 设置读缓冲区为2M
.childOption(ChannelOption.SO_RCVBUF, 2048 * 1024)
.childOption(ChannelOption.SO_RCVBUF, readBufferSize)
// 设置写缓冲区为1M
.childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)
.childOption(ChannelOption.SO_SNDBUF, writeBufferSize)
.childOption(ChannelOption.SO_KEEPALIVE, true)
// .childOption(ChannelOption.TCP_NODELAY, false)
.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 60)//连接超时时间设置为 60 秒
.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeoutMillis)//连接超时时间设置为 60 秒
// .childOption(ChannelOption.RCVBUF_ALLOCATOR, new NettyRecvByteBufAllocator(1024 * 1024))//用于Channel分配接受Buffer的分配器 默认AdaptiveRecvByteBufAllocator.DEFAULT
.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 1024 * 1024 * 2))

View File

@@ -1,16 +1,56 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.log;
import lombok.Data;
import org.wu.framework.lazy.orm.core.stereotype.*;
import java.time.LocalDateTime;
@Data
@LazyTable(tableName = "proxy_log", comment = "代理日志信息")
public class ProxyLog {
/**
* 请求ID
*/
@LazyTableFieldUUId(name = "request_id", comment = "请求ID")
private String requestId;
/**
* 主机地址
*/
@LazyTableField(name = "host", comment = "主机地址")
private String host;;
/**
* 端口号
*/
@LazyTableField(name = "port", comment = "端口号")
private Integer port;
/**
* 访客ID
*/
@LazyTableField(name = "visitor_id", comment = "访客ID")
private String visitorId;
/**
* 接收数据
*/
@LazyTableField(name = "receiver", comment = "接收数据", columnType = "BLOB")
private byte[] receiver;
/**
* 发送数据
*/
@LazyTableField(name = "send", comment = "发送数据", columnType = "BLOB")
private byte[] send;
/**
* 创建时间
*/
@LazyTableFieldCreateTime(name = "create_time", comment = "创建时间")
private LocalDateTime createTime = LocalDateTime.now();
/**
* 更新时间
*/
@LazyTableFieldUpdateTime(name = "update_time", comment = "更新时间")
private LocalDateTime updateTime;
}

View File

@@ -1,7 +1,6 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.log;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.flow.permeate.ChannelFlow;
import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties;
import org.framework.wu.framework.queue.Message;
import org.framework.wu.framework.queue.MessageQueue;
@@ -38,13 +37,20 @@ public class ProxyReceiverLog implements CommandLineRunner {
MessageQueue receiverQueue = MessageQueueFactory.getQueue(receiverMsgQueue);
// 创建监听线程
// 创建监听线程(接收数据对应通道)
Thread thread = new Thread(() -> {
while (true) {
try {
Message receive = receiverQueue.receive();
if (ObjectUtils.isNotEmpty(receive)) {
ProxyLog proxyLog = (ProxyLog) receive.getBody();
lazyLambdaStream.upsert(proxyLog);
String requestId = proxyLog.getRequestId();
lazyLambdaStream.upsertRemoveNull(proxyLog);
}
} catch (Exception e) {
log.error("异常退出代理日志接收线程:{}", e.getMessage());
e.printStackTrace();
}
}
});
@@ -55,16 +61,23 @@ public class ProxyReceiverLog implements CommandLineRunner {
MessageQueue sendQueue = MessageQueueFactory.getQueue(sendMsgQueue);
// 创建监听线程
// 创建监听线程(发送数据对应通道)
Thread sendThread = new Thread(() -> {
while (true) {
try {
Message receive = sendQueue.receive();
if (ObjectUtils.isNotEmpty(receive)) {
ProxyLog proxyLog = (ProxyLog) receive.getBody();
String requestId = proxyLog.getRequestId();
lazyLambdaStream.upsert(proxyLog);
lazyLambdaStream.upsertRemoveNull(proxyLog);
}
} catch (Exception e) {
log.error("异常退出代理日志发送线程:{}", e.getMessage());
e.printStackTrace();
}
}
});
CHANNEL_LOG_EXECUTOR.submit(sendThread::start);

View File

@@ -43,7 +43,7 @@ public class ProtocolProxyProperties {
*/
private HttpProtocolProxy httpProtocolProxy = new HttpProtocolProxy();
/**
* tcp协议代理
* socket 协议代理
*/
private SocketProtocolProxy socketProtocolProxy = new SocketProtocolProxy();
@@ -51,11 +51,58 @@ public class ProtocolProxyProperties {
@Data
public static class HttpProtocolProxy {
private Integer port = 8001;
/**
* 父类线程数
*/
private Integer bossThreadNum = 1;
/**
* 子类线程数
*/
private Integer workerThreadNum = 4;
/**
* 读缓冲区大小 (kb)
*/
private Integer readBufferSize = 2048 * 1024;
/**
* 写缓冲区大小 (kb)
*/
private Integer writeBufferSize = 1024 * 1024;
/**
* 连接超时时间设置为(毫秒)
*/
private Integer connectTimeoutMillis = 1000 * 60;
}
@Data
public static class SocketProtocolProxy {
/**
* 端口
*/
private Integer port = 9001;
/**
* 父类线程数
*/
private Integer bossThreadNum = 1;
/**
* 子类线程数
*/
private Integer workerThreadNum = 4;
/**
* 读缓冲区大小 (kb)
*/
private Integer readBufferSize = 2048 * 1024;
/**
* 写缓冲区大小 (kb)
*/
private Integer writeBufferSize = 1024 * 1024;
/**
* 连接超时时间设置为(毫秒)
*/
private Integer connectTimeoutMillis = 1000 * 60;
}
}

View File

@@ -10,10 +10,10 @@ spring:
# inet-port: 7001
# inet-host: 127.0.0.1
# inet-port: 7001
# inet-host: 1.116.249.110
# inet-port: 30560
# inet-path: wu-lazy-cloud-heartbeat-server
# client-id: socks-local-proxy # 客户端ID
inet-host: 1.116.249.110
inet-port: 30560
inet-path: wu-lazy-cloud-heartbeat-server
client-id: socks-local-proxy # 客户端ID
# app-key: a4bf4415-25aa-4007-914b-31ec77d1292f
# app-secret: 88e6d827-12e7-4a5d-93e0-92c04c2414bc
# protocol-type: tcp
@@ -29,7 +29,7 @@ spring:
---
spring:
datasource:
url: jdbc:h2:~/client_heartbeat;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=true;MODE=MySQL;CASE_INSENSITIVE_IDENTIFIERS=TRUE
url: jdbc:h2:~/client_heartbeat;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=true;MODE=MySQL;CASE_INSENSITIVE_IDENTIFIERS=TRUE;IGNORECASE=TRUE
username: sa
driver-class-name: org.h2.Driver