Project reconfiguration
117
chat2db-server/chat2db-server-start/pom.xml
Normal file
@ -0,0 +1,117 @@
|
||||
<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/maven-v4_0_0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>ai.chat2db</groupId>
|
||||
<artifactId>chat2db-server-parent</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>chat2db-server-start</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>chat2db-server-start</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.chat2db</groupId>
|
||||
<artifactId>chat2db-server-web-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 需要加载的服务 -->
|
||||
<dependency>
|
||||
<groupId>ai.chat2db</groupId>
|
||||
<artifactId>chat2db-server-domain-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.chat2db</groupId>
|
||||
<artifactId>chat2db-server-domain-support</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 日志用logback -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 启动数据库 -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库版本管理 -->
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-mysql</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 登录鉴权 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- Sa-Token 整合 jwt -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-jwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 模板引擎 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.dtflys.forest</groupId>
|
||||
<artifactId>forest-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>chat2db-server-start</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- 重点 -->
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,21 @@
|
||||
package ai.chat2db.server.start;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* 启动类
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@ComponentScan(value = {"ai.chat2db.server"})
|
||||
@MapperScan("ai.chat2db.server.domain.repository.mapper")
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package ai.chat2db.server.start.config.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import ai.chat2db.server.domain.api.model.User;
|
||||
import ai.chat2db.server.domain.api.service.UserService;
|
||||
import ai.chat2db.server.tools.base.constant.SymbolConstant;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
import ai.chat2db.server.tools.common.exception.RedirectBusinessException;
|
||||
import ai.chat2db.server.tools.common.model.Context;
|
||||
import ai.chat2db.server.tools.common.model.LoginUser;
|
||||
import ai.chat2db.server.tools.common.util.ContextUtils;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.spring.SpringMVCUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.AsyncHandlerInterceptor;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import static ai.chat2db.server.tools.common.enums.ErrorEnum.NEED_LOGGED_IN;
|
||||
|
||||
/**
|
||||
* web项目配置
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class DbhubWebMvcConfigurer implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* api前缀
|
||||
*/
|
||||
private static final String API_PREFIX = "/api/";
|
||||
|
||||
/**
|
||||
* 全局放行的url
|
||||
*/
|
||||
private static final String[] FRONT_PERMIT_ALL = new String[] {"/favicon.ico", "/error", "/static/**", "/api/system"};
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
|
||||
// 所有请求尝试加入用户信息
|
||||
registry.addInterceptor(new AsyncHandlerInterceptor() {
|
||||
@Override
|
||||
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response,
|
||||
@NotNull Object handler) {
|
||||
String userIdString = (String)StpUtil.getLoginIdDefaultNull();
|
||||
// 未登录
|
||||
if (!StringUtils.isNumeric(userIdString)) {
|
||||
// TODO 这个版本默认放开登录 不管用户是否登录 都算登录,下个版本做权限
|
||||
userIdString = "1";
|
||||
//return true;
|
||||
}
|
||||
// 已经登录 查询用户信息
|
||||
Long userId = Long.parseLong(userIdString);
|
||||
User user = userService.query(userId).getData();
|
||||
if (user == null) {
|
||||
// 代表用户可能被删除了
|
||||
return true;
|
||||
}
|
||||
|
||||
ContextUtils.setContext(Context.builder()
|
||||
.loginUser(LoginUser.builder()
|
||||
.id(user.getId()).nickName(user.getNickName())
|
||||
.build())
|
||||
.build());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) throws Exception {
|
||||
// 移除登录信息
|
||||
ContextUtils.removeContext();
|
||||
}
|
||||
})
|
||||
.order(1)
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns(FRONT_PERMIT_ALL);
|
||||
|
||||
// 校验登录信息
|
||||
registry.addInterceptor(new AsyncHandlerInterceptor() {
|
||||
@Override
|
||||
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response,
|
||||
@NotNull Object handler) throws IOException {
|
||||
Context context = ContextUtils.queryContext();
|
||||
// 校验登录信息
|
||||
if (context == null) {
|
||||
log.info("访问{},{}需要登录", buildHeaderString(request), SaHolder.getRequest().getUrl());
|
||||
|
||||
String path = SaHolder.getRequest().getRequestPath();
|
||||
if (path.startsWith(API_PREFIX)) {
|
||||
response.getWriter().println(JSON.toJSONString(
|
||||
ActionResult.fail(NEED_LOGGED_IN.getCode(), NEED_LOGGED_IN.getDescription())));
|
||||
return false;
|
||||
//throw new NeedLoggedInBusinessException();
|
||||
} else {
|
||||
throw new RedirectBusinessException(
|
||||
"/login-a#/login?callback=" + SaFoxUtil.joinParam(
|
||||
SpringMVCUtil.getRequest().getRequestURI(),
|
||||
SpringMVCUtil.getRequest().getQueryString()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.order(2)
|
||||
.addPathPatterns("/**")
|
||||
// 前端需要放行的链接
|
||||
.excludePathPatterns(FRONT_PERMIT_ALL)
|
||||
// -a结尾的统一放行
|
||||
.excludePathPatterns("/**/*-a")
|
||||
// _a结尾的统一放行
|
||||
.excludePathPatterns("/**/*_a");
|
||||
}
|
||||
|
||||
private String buildHeaderString(HttpServletRequest request) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headName = headerNames.nextElement();
|
||||
stringBuilder.append(headName);
|
||||
stringBuilder.append(SymbolConstant.COLON);
|
||||
stringBuilder.append(request.getHeader(headName));
|
||||
stringBuilder.append(SymbolConstant.COMMA);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* alibaba.com Inc.
|
||||
* Copyright (c) 2004-2023 All Rights Reserved.
|
||||
*/
|
||||
package ai.chat2db.server.start.config.config;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import ai.chat2db.server.domain.support.sql.DbhubContext;
|
||||
import ai.chat2db.server.domain.support.util.JdbcJarUtils;
|
||||
import ai.chat2db.server.tools.common.config.AliDbhubProperties;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author jipengfei
|
||||
* @version : JarDownloadTask.java
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class JarDownloadTask implements CommandLineRunner {
|
||||
|
||||
@Resource
|
||||
private AliDbhubProperties aliDbhubProperties;
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
DbhubContext.JDBC_JAR_DOWNLOAD_URL_LIST = aliDbhubProperties.getJdbcJarDownLoadUrls();
|
||||
JdbcJarUtils.asyncDownload(aliDbhubProperties.getJdbcJarDownLoadUrls());
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package ai.chat2db.server.start.config.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.ResourceBundleMessageSource;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
|
||||
/**
|
||||
* @author moji
|
||||
* @version Internationalization.java, v 0.1 2022年10月10日 16:21 moji Exp $
|
||||
* @date 2022/10/10
|
||||
*/
|
||||
@Configuration
|
||||
public class InternationalizationConfig implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
public AcceptHeaderLocaleResolver localeResolver() {
|
||||
final AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
|
||||
resolver.setDefaultLocale(Locale.CHINA);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocaleChangeInterceptor localeChangeInterceptor() {
|
||||
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
|
||||
localeChangeInterceptor.setParamName("language");
|
||||
return localeChangeInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(localeChangeInterceptor());
|
||||
}
|
||||
|
||||
@Bean("messageSource")
|
||||
public MessageSource messageSource() {
|
||||
ResourceBundleMessageSource messageSource =
|
||||
new ResourceBundleMessageSource();
|
||||
messageSource.setBasenames("i18n/messages/messages");
|
||||
messageSource.setDefaultEncoding("UTF-8");
|
||||
return messageSource;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package ai.chat2db.server.start.config.interceptor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Cors跨域的拦截器,任何情况都允许跨域
|
||||
*
|
||||
* 通过CorsRegistry策略的跨域 在登录的情况下会有有问题,但是本地没有复现,可能原因是:bean 的加载顺序的问题。
|
||||
* 临时通过CorsFilter解决,后续可以研究下:CorsRegistry
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
@Component
|
||||
public class CorsFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletResponse response = (HttpServletResponse)res;
|
||||
HttpServletRequest request = (HttpServletRequest)req;
|
||||
|
||||
response.setHeader("Access-Control-Allow-Origin", request.getHeader(HttpHeaders.ORIGIN));
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
|
||||
response.setHeader("Access-Control-Max-Age", "3600");
|
||||
response.setHeader("Access-Control-Allow-Headers", "Content-Type, DBHUB, uid");
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package ai.chat2db.server.start.config.listener;
|
||||
|
||||
import ai.chat2db.server.start.config.util.SystemUtils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 自定义tomcat参数
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DbhubTomcatConnectorCustomizer implements TomcatConnectorCustomizer {
|
||||
@Override
|
||||
public void customize(Connector connector) {
|
||||
connector.addLifecycleListener(event -> {
|
||||
// 接受到关闭事件 直接退出系统,因为有时候不会退出系统
|
||||
if (LifecycleState.STOPPING == event.getLifecycle().getState()) {
|
||||
SystemUtils.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package ai.chat2db.server.start.config.listener;
|
||||
|
||||
import ai.chat2db.server.start.config.util.SystemUtils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationFailedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
* 应用启动失败的监听器
|
||||
* 应用启动失败了只是停止了tomcat 并没有停止应用 这里停止xia
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Slf4j
|
||||
public class FailedEventApplicationListener implements ApplicationListener<ApplicationFailedEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationFailedEvent event) {
|
||||
log.error("启动失败,停止应用", event.getException());
|
||||
SystemUtils.stop();
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
package ai.chat2db.server.start.config.listener;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import ai.chat2db.server.tools.base.enums.SystemEnvironmentEnum;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.DataResult;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import com.dtflys.forest.Forest;
|
||||
import com.dtflys.forest.utils.TypeReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* 用来管理启动
|
||||
* 防止启动多个
|
||||
*
|
||||
* @author zhuangjiaju
|
||||
* @date 2023/05/08
|
||||
*/
|
||||
@Slf4j
|
||||
public class ManageApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
|
||||
Integer serverPort = event.getEnvironment().getProperty("server.port", Integer.class);
|
||||
Assert.notNull(serverPort, "server.port配置信息");
|
||||
log.info("启动端口为:{}", serverPort);
|
||||
String environment = event.getEnvironment().getProperty("spring.profiles.active", String.class);
|
||||
|
||||
// 尝试访问确认应用是否已经启动
|
||||
DataResult<String> dataResult;
|
||||
try {
|
||||
dataResult = Forest.get("http://127.0.0.1:" + serverPort + "/api/system/get-version-a")
|
||||
.connectTimeout(Duration.ofMillis(50))
|
||||
.readTimeout(Duration.ofSeconds(1))
|
||||
.execute(new TypeReference<>() {});
|
||||
} catch (Exception e) {
|
||||
// 抛出异常 代表没有旧的启动 或者旧的不靠谱
|
||||
log.info("尝试访问旧的应用失败。本异常不重要,正常启动启动都会输出,请忽略。"+ e.getMessage());
|
||||
|
||||
// 尝试杀死旧的进程
|
||||
killOldIfNecessary(environment);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataResult == null || BooleanUtils.isNotTrue(dataResult.getSuccess())) {
|
||||
// 尝试杀死旧的进程
|
||||
killOldIfNecessary(environment);
|
||||
return;
|
||||
}
|
||||
|
||||
// 代表旧的进程是可以用的
|
||||
log.info("当前接口已经存在启动的应用了,本应用不在启动");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private void killOldIfNecessary(String environment) {
|
||||
ProcessHandle.allProcesses().forEach(process -> {
|
||||
String command = process.info().command().orElse(null);
|
||||
// 不是java应用
|
||||
boolean isJava = StringUtils.endsWithIgnoreCase(command, "java") || StringUtils.endsWithIgnoreCase(command,
|
||||
"java.exe");
|
||||
if (!isJava) {
|
||||
return;
|
||||
}
|
||||
String[] arguments = process.info().arguments().orElse(null);
|
||||
// 没有参数
|
||||
if (arguments == null) {
|
||||
return;
|
||||
}
|
||||
// 是否是dbhub
|
||||
boolean isDbhub = false;
|
||||
String environmentArgument = null;
|
||||
for (String argument : arguments) {
|
||||
if (StringUtils.equals("ali-dbhub-server-start.jar", argument)) {
|
||||
isDbhub = true;
|
||||
}
|
||||
if (StringUtils.startsWith(argument, "-Dspring.profiles.active=")) {
|
||||
environmentArgument = StringUtils.substringAfter(argument, "-Dspring.profiles.active=");
|
||||
}
|
||||
}
|
||||
// 不是dbhub
|
||||
if (!isDbhub) {
|
||||
return;
|
||||
}
|
||||
// 判断是否是正式环境
|
||||
if (StringUtils.equals(SystemEnvironmentEnum.RELEASE.getCode(), environment) && StringUtils.equals(
|
||||
SystemEnvironmentEnum.RELEASE.getCode(), environmentArgument)) {
|
||||
log.info("正式环境需要关闭进程");
|
||||
destroyProcess(process, command, arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断是否是测试环境
|
||||
if (StringUtils.equals(SystemEnvironmentEnum.TEST.getCode(), environment) && StringUtils.equals(
|
||||
SystemEnvironmentEnum.TEST.getCode(), environmentArgument)) {
|
||||
log.info("测试环境需要关闭进程");
|
||||
destroyProcess(process, command, arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断是否是本地环境
|
||||
boolean devDestroy = StringUtils.equals(SystemEnvironmentEnum.DEV.getCode(), environment) && (
|
||||
environmentArgument == null
|
||||
|| StringUtils.equals(SystemEnvironmentEnum.DEV.getCode(), environmentArgument));
|
||||
if (devDestroy) {
|
||||
log.info("本地环境需要关闭进程");
|
||||
destroyProcess(process, command, arguments);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void destroyProcess(ProcessHandle process, String command, String[] arguments) {
|
||||
log.info("检查到存在需要关闭的进程:{},{}", JSON.toJSONString(command), JSON.toJSONString(arguments));
|
||||
try {
|
||||
process.destroy();
|
||||
} catch (Exception e) {
|
||||
log.error("结束进程失败", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package ai.chat2db.server.start.config.listener.manage;
|
||||
|
||||
import ai.chat2db.server.tools.base.constant.EasyToolsConstant;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 管理的消息
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ManageMessage implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = EasyToolsConstant.SERIAL_VERSION_UID;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*
|
||||
* @see MessageTypeEnum
|
||||
*/
|
||||
private MessageTypeEnum messageTypeEnum;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package ai.chat2db.server.start.config.listener.manage;
|
||||
|
||||
import ai.chat2db.server.tools.base.enums.BaseEnum;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 消息类型枚举
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Getter
|
||||
public enum MessageTypeEnum implements BaseEnum<String> {
|
||||
/**
|
||||
* 检查是否正常运行
|
||||
*/
|
||||
HEARTBEAT,
|
||||
|
||||
|
||||
;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return this.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return this.name();
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package ai.chat2db.server.start.config.mybatis;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author moji
|
||||
* @version MyBatisPlusConfig.java, v 0.1 2022年09月29日 17:38 moji Exp $
|
||||
* @date 2022/09/29
|
||||
*/
|
||||
@Configuration
|
||||
public class MyBatisPlusConfig {
|
||||
|
||||
/**
|
||||
* myBatisPlus 分页插件
|
||||
*/
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
|
||||
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return mybatisPlusInterceptor;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package ai.chat2db.server.start.config.oauth;
|
||||
|
||||
import cn.dev33.satoken.log.SaLog;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* satoken 日志打印
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SaLogForSlf4j implements SaLog {
|
||||
@Override
|
||||
public void trace(String str, Object... args) {
|
||||
log.trace(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String str, Object... args) {
|
||||
log.debug(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String str, Object... args) {
|
||||
log.info(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String str, Object... args) {
|
||||
log.trace(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String str, Object... args) {
|
||||
log.error(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(String str, Object... args) {
|
||||
log.error(str, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package ai.chat2db.server.start.config.oauth;
|
||||
|
||||
import cn.dev33.satoken.jwt.StpLogicJwtForStateless;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* satoken配置
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
@Configuration
|
||||
public class SaTokenConfigure {
|
||||
@Bean
|
||||
public StpLogic ttpLogic() {
|
||||
// 登录展示用 无状态的 这样不用依赖于与redis之类的
|
||||
// 后续可以改成ehcahe 存储磁盘?
|
||||
return new StpLogicJwtForStateless();
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package ai.chat2db.server.start.config.util;
|
||||
|
||||
import ai.chat2db.server.domain.support.sql.SSHManager;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 系统工具包
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Slf4j
|
||||
public class SystemUtils {
|
||||
|
||||
/**
|
||||
* 停止当前应用
|
||||
*/
|
||||
public static void stop() {
|
||||
new Thread(() -> {
|
||||
log.info("1秒以后退出应用");
|
||||
// 1秒以后自动退出应用
|
||||
try {
|
||||
Thread.sleep(1000L);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// 直接系统退出
|
||||
log.info("开始退出系统应用");
|
||||
SSHManager.close();
|
||||
try {
|
||||
System.exit(0);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package ai.chat2db.server.start.controller.oauth;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import ai.chat2db.server.domain.api.model.User;
|
||||
import ai.chat2db.server.domain.api.service.UserService;
|
||||
import ai.chat2db.server.start.controller.oauth.request.LoginRequest;
|
||||
import ai.chat2db.server.tools.base.excption.BusinessException;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.DataResult;
|
||||
import ai.chat2db.server.tools.common.model.LoginUser;
|
||||
import ai.chat2db.server.tools.common.util.ContextUtils;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 登录授权服务
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/oauth")
|
||||
@Slf4j
|
||||
public class OauthController {
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
/**
|
||||
* 用户名密码登录
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("login_a")
|
||||
public DataResult login(@Validated @RequestBody LoginRequest request) {
|
||||
// 查询用户
|
||||
User user = userService.query(request.getUserName()).getData();
|
||||
if (user == null) {
|
||||
throw new BusinessException("当前用户不存在。");
|
||||
}
|
||||
if (!DigestUtil.bcryptCheck(request.getPassword(), user.getPassword())) {
|
||||
throw new BusinessException("您输入的密码有误。");
|
||||
}
|
||||
StpUtil.login(user.getId());
|
||||
Object token = SaHolder.getStorage().get(SaTokenConsts.JUST_CREATED_NOT_PREFIX);
|
||||
return DataResult.of(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("logout_a")
|
||||
public ActionResult logout() {
|
||||
StpUtil.logout();
|
||||
return ActionResult.isSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("user")
|
||||
public DataResult<LoginUser> user() {
|
||||
return DataResult.of(ContextUtils.getLoginUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("user_a")
|
||||
public DataResult<LoginUser> usera() {
|
||||
return DataResult.of(ContextUtils.queryLoginUser());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package ai.chat2db.server.start.controller.oauth.request;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginRequest {
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@NotNull(message = "用户名不能为空")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@NotNull(message = "密码不能为空")
|
||||
private String password;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package ai.chat2db.server.start.controller.thymeleaf;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* 模板引擎 配置
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Controller
|
||||
@Slf4j
|
||||
@Order(Integer.MIN_VALUE)
|
||||
public class ThymeleafController {
|
||||
|
||||
/**
|
||||
* 前端的模板设置
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = {"/", "/web/", "/web/**","login-a"})
|
||||
public String index() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/chat.html", method={RequestMethod.GET}, produces="text/html;charset=utf-8")
|
||||
public String chat(){
|
||||
|
||||
return "chat";
|
||||
}
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
package ai.chat2db.server.start.exception;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import ai.chat2db.server.start.exception.convertor.BindExceptionConvertor;
|
||||
import ai.chat2db.server.start.exception.convertor.BusinessExceptionConvertor;
|
||||
import ai.chat2db.server.start.exception.convertor.DefaultExceptionConvertor;
|
||||
import ai.chat2db.server.start.exception.convertor.ExceptionConvertor;
|
||||
import ai.chat2db.server.start.exception.convertor.MaxUploadSizeExceededExceptionConvertor;
|
||||
import ai.chat2db.server.start.exception.convertor.MethodArgumentNotValidExceptionConvertor;
|
||||
import ai.chat2db.server.start.exception.convertor.MethodArgumentTypeMismatchExceptionConvertor;
|
||||
import ai.chat2db.server.start.exception.convertor.ParamExceptionConvertor;
|
||||
import ai.chat2db.server.tools.base.excption.BusinessException;
|
||||
import ai.chat2db.server.tools.base.excption.SystemException;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
import ai.chat2db.server.tools.common.exception.NeedLoggedInBusinessException;
|
||||
import ai.chat2db.server.tools.common.exception.RedirectBusinessException;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.MissingRequestHeaderException;
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
import org.springframework.web.multipart.MultipartException;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* 拦截Controller异常
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
@ControllerAdvice
|
||||
@Slf4j
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class EasyControllerExceptionHandler {
|
||||
|
||||
/**
|
||||
* 所有的异常处理转换器
|
||||
*/
|
||||
public static final Map<Class<?>, ExceptionConvertor> EXCEPTION_CONVERTOR_MAP = Maps.newHashMap();
|
||||
|
||||
static {
|
||||
EXCEPTION_CONVERTOR_MAP.put(MethodArgumentNotValidException.class,
|
||||
new MethodArgumentNotValidExceptionConvertor());
|
||||
EXCEPTION_CONVERTOR_MAP.put(BindException.class, new BindExceptionConvertor());
|
||||
EXCEPTION_CONVERTOR_MAP.put(BusinessException.class, new BusinessExceptionConvertor());
|
||||
EXCEPTION_CONVERTOR_MAP.put(NeedLoggedInBusinessException.class, new BusinessExceptionConvertor());
|
||||
EXCEPTION_CONVERTOR_MAP.put(MissingServletRequestParameterException.class, new ParamExceptionConvertor());
|
||||
EXCEPTION_CONVERTOR_MAP.put(IllegalArgumentException.class, new ParamExceptionConvertor());
|
||||
EXCEPTION_CONVERTOR_MAP.put(MethodArgumentTypeMismatchException.class,
|
||||
new MethodArgumentTypeMismatchExceptionConvertor());
|
||||
EXCEPTION_CONVERTOR_MAP.put(MaxUploadSizeExceededException.class,
|
||||
new MaxUploadSizeExceededExceptionConvertor());
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认转换器
|
||||
*/
|
||||
public static ExceptionConvertor DEFAULT_EXCEPTION_CONVERTOR = new DefaultExceptionConvertor();
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*
|
||||
* @param request request
|
||||
* @param exception exception
|
||||
* @return return
|
||||
*/
|
||||
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class, IllegalArgumentException.class,
|
||||
MissingServletRequestParameterException.class, MethodArgumentTypeMismatchException.class,
|
||||
BusinessException.class, MaxUploadSizeExceededException.class, ClientAbortException.class,
|
||||
HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotAcceptableException.class,
|
||||
MultipartException.class, MissingRequestHeaderException.class, HttpMediaTypeNotSupportedException.class,
|
||||
NeedLoggedInBusinessException.class})
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
public ActionResult handleBusinessException(HttpServletRequest request, Exception exception) {
|
||||
ActionResult result = convert(exception);
|
||||
log.info("发生业务异常{}:{}", request.getRequestURI(), result, exception);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*
|
||||
* @param request request
|
||||
* @param exception exception
|
||||
* @return return
|
||||
*/
|
||||
@ExceptionHandler({RedirectBusinessException.class})
|
||||
public ModelAndView handleModelAndViewBizException(HttpServletRequest request, Exception exception) {
|
||||
ModelAndView result = translateModelAndView(exception);
|
||||
log.info("发生ModelAndView业务异常{}:{}", request.getRequestURI(), result, exception);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ModelAndView translateModelAndView(Throwable exception) {
|
||||
// 参数异常
|
||||
if (exception instanceof RedirectBusinessException) {
|
||||
RedirectBusinessException e = (RedirectBusinessException)exception;
|
||||
return dealResponseModelAndView(null, e.getMessage(), e.getRedirect(), null, null);
|
||||
}
|
||||
// 默认跳首页
|
||||
return new ModelAndView("redirect:/");
|
||||
}
|
||||
|
||||
private ModelAndView dealResponseModelAndView(String title, String errorMessage, String redirect, String href,
|
||||
String buttonText) {
|
||||
// 如果有车重定向信息 则跳转
|
||||
if (StringUtils.isNotBlank(redirect)) {
|
||||
return new ModelAndView("redirect:" + redirect);
|
||||
}
|
||||
// 默认跳首页
|
||||
return new ModelAndView("redirect:/");
|
||||
|
||||
// 同步请求
|
||||
//return ModelAndViewUtils.error(title, errorMessage,href,buttonText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统异常
|
||||
*
|
||||
* @param request request
|
||||
* @param exception exception
|
||||
* @return return
|
||||
*/
|
||||
@ExceptionHandler({SystemException.class})
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
public ActionResult handleSystemException(HttpServletRequest request, Exception exception) {
|
||||
ActionResult result = convert(exception);
|
||||
log.error("发生业务异常{}:{}", request.getRequestURI(), result, exception);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 未知异常 需要人工介入查看日志
|
||||
*
|
||||
* @param request request
|
||||
* @param exception exception
|
||||
* @return return
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
public ActionResult handledException(HttpServletRequest request, Exception exception) {
|
||||
ActionResult result = convert(exception);
|
||||
log.error("发生未知异常{}:{},请求参数:{}", request.getRequestURI(), result,
|
||||
JSON.toJSONString(request.getParameterMap()),
|
||||
exception);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ActionResult convert(Throwable exception) {
|
||||
ExceptionConvertor exceptionConvertor = EXCEPTION_CONVERTOR_MAP.get(exception.getClass());
|
||||
if (exceptionConvertor == null) {
|
||||
exceptionConvertor = DEFAULT_EXCEPTION_CONVERTOR;
|
||||
}
|
||||
return exceptionConvertor.convert(exception);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import ai.chat2db.server.tools.base.excption.CommonErrorEnum;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
|
||||
import org.springframework.validation.BindException;
|
||||
|
||||
/**
|
||||
* BindException
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public class BindExceptionConvertor implements ExceptionConvertor<BindException> {
|
||||
|
||||
@Override
|
||||
public ActionResult convert(BindException exception) {
|
||||
String message = ExceptionConvertorUtils.buildMessage(exception.getBindingResult());
|
||||
return ActionResult.fail(CommonErrorEnum.PARAM_ERROR, message);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import ai.chat2db.server.tools.base.excption.BusinessException;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
|
||||
/**
|
||||
* BusinessException
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public class BusinessExceptionConvertor implements ExceptionConvertor<BusinessException> {
|
||||
|
||||
@Override
|
||||
public ActionResult convert(BusinessException exception) {
|
||||
return ActionResult.fail(exception.getCode(), exception.getMessage());
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import ai.chat2db.server.tools.base.excption.CommonErrorEnum;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
|
||||
/**
|
||||
* 默认的异常处理
|
||||
* 直接抛出系统异常
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public class DefaultExceptionConvertor implements ExceptionConvertor<Throwable> {
|
||||
|
||||
@Override
|
||||
public ActionResult convert(Throwable exception) {
|
||||
return ActionResult.fail(CommonErrorEnum.COMMON_SYSTEM_ERROR);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
|
||||
/**
|
||||
* 异常转换器
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public interface ExceptionConvertor<T extends Throwable> {
|
||||
|
||||
/**
|
||||
* 转换异常
|
||||
*
|
||||
* @param exception
|
||||
* @return
|
||||
*/
|
||||
ActionResult convert(T exception);
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ai.chat2db.server.tools.base.constant.SymbolConstant;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.ObjectError;
|
||||
|
||||
/**
|
||||
* 转换工具类
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public class ExceptionConvertorUtils {
|
||||
|
||||
/**
|
||||
* 提取BindingResult中的错误消息
|
||||
*
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
public static String buildMessage(BindingResult result) {
|
||||
List<ObjectError> errors = result.getAllErrors();
|
||||
if (CollectionUtils.isEmpty(errors)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = 1;
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("请检查以下信息:");
|
||||
for (ObjectError e : errors) {
|
||||
msg.append(index++);
|
||||
// 得到错误消息
|
||||
msg.append(SymbolConstant.DOT);
|
||||
msg.append(e.getDefaultMessage());
|
||||
msg.append(SymbolConstant.SEMICOLON);
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import ai.chat2db.server.tools.base.excption.CommonErrorEnum;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
|
||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
|
||||
/**
|
||||
* MaxUploadSizeExceededException
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public class MaxUploadSizeExceededExceptionConvertor implements ExceptionConvertor<MaxUploadSizeExceededException> {
|
||||
|
||||
@Override
|
||||
public ActionResult convert(MaxUploadSizeExceededException exception) {
|
||||
return ActionResult.fail(CommonErrorEnum.MAX_UPLOAD_SIZE);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import ai.chat2db.server.tools.base.excption.CommonErrorEnum;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
|
||||
/**
|
||||
* MethodArgumentNotValidException
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public class MethodArgumentNotValidExceptionConvertor implements ExceptionConvertor<MethodArgumentNotValidException> {
|
||||
|
||||
@Override
|
||||
public ActionResult convert(MethodArgumentNotValidException exception) {
|
||||
String message = ExceptionConvertorUtils.buildMessage(exception.getBindingResult());
|
||||
return ActionResult.fail(CommonErrorEnum.PARAM_ERROR, message);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import ai.chat2db.server.tools.base.excption.CommonErrorEnum;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
|
||||
/**
|
||||
* MethodArgumentTypeMismatchException
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public class MethodArgumentTypeMismatchExceptionConvertor
|
||||
implements ExceptionConvertor<MethodArgumentTypeMismatchException> {
|
||||
|
||||
@Override
|
||||
public ActionResult convert(MethodArgumentTypeMismatchException exception) {
|
||||
return ActionResult.fail(CommonErrorEnum.PARAM_ERROR, "请输入正确的数据格式");
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package ai.chat2db.server.start.exception.convertor;
|
||||
|
||||
import ai.chat2db.server.tools.base.excption.CommonErrorEnum;
|
||||
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
|
||||
/**
|
||||
* 参数异常 目前包括
|
||||
* ConstraintViolationException
|
||||
* MissingServletRequestParameterException
|
||||
* IllegalArgumentException
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
public class ParamExceptionConvertor implements ExceptionConvertor<Throwable> {
|
||||
|
||||
@Override
|
||||
public ActionResult convert(Throwable exception) {
|
||||
return ActionResult.fail(CommonErrorEnum.PARAM_ERROR, exception.getMessage());
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
org.springframework.context.ApplicationListener=\
|
||||
ai.chat2db.server.start.config.listener.ManageApplicationListener,\
|
||||
ai.chat2db.server.start.config.listener.FailedEventApplicationListener
|
@ -0,0 +1,18 @@
|
||||
spring:
|
||||
datasource:
|
||||
# 配置自带数据库的相对路径
|
||||
url: jdbc:h2:~/.chat2db/db/chat2db_dev;MODE=MYSQL
|
||||
driver-class-name: org.h2.Driver
|
||||
# 用于数据库表结构版本管理
|
||||
flyway:
|
||||
locations: classpath:db/migration/dev
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2
|
||||
settings:
|
||||
trace: true
|
||||
web-allow-others: true
|
||||
# 端口号
|
||||
server:
|
||||
port: 10821
|
@ -0,0 +1,11 @@
|
||||
spring:
|
||||
datasource:
|
||||
# 配置自带数据库的相对路径
|
||||
url: jdbc:h2:~/.chat2db/db/chat2db;MODE=MYSQL
|
||||
driver-class-name: org.h2.Driver
|
||||
# 用于数据库表结构版本管理
|
||||
flyway:
|
||||
locations: classpath:db/migration/release
|
||||
# 端口号
|
||||
server:
|
||||
port: 10824
|
@ -0,0 +1,19 @@
|
||||
spring:
|
||||
datasource:
|
||||
# 配置自带数据库的相对路径
|
||||
url: jdbc:h2:~/.chat2db/db/chat2db_test;MODE=MYSQL
|
||||
driver-class-name: org.h2.Driver
|
||||
# 用于数据库表结构版本管理
|
||||
# 测试的表结构还是用dev的 ,但是有自己单独的库 确保多个客户端运行
|
||||
flyway:
|
||||
locations: classpath:db/migration/dev
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2
|
||||
settings:
|
||||
trace: true
|
||||
web-allow-others: true
|
||||
# 端口号
|
||||
server:
|
||||
port: 10824
|
@ -0,0 +1,78 @@
|
||||
spring:
|
||||
# 默认开发环境
|
||||
profiles:
|
||||
active: dev
|
||||
jpa:
|
||||
# 展示sql
|
||||
show-sql: true
|
||||
messages:
|
||||
basename: i18n/messages/messages
|
||||
encoding: UTF-8
|
||||
fallbackToSystemLocale: true
|
||||
jmx:
|
||||
enabled: false
|
||||
# thymeleaf
|
||||
thymeleaf:
|
||||
prefix: classpath:/thymeleaf/
|
||||
check-template-location: true
|
||||
suffix: .html
|
||||
servlet:
|
||||
content-type: text/html
|
||||
mode: HTML5
|
||||
# 静态文件
|
||||
mvc:
|
||||
static-path-pattern: /static/**
|
||||
web:
|
||||
resources:
|
||||
static-locations[0]: classpath:/static/
|
||||
ali:
|
||||
dbhub:
|
||||
version: 1.0.0
|
||||
jdbc-jar-downLoad-urls:
|
||||
- https://oss-chat2db.alibaba.com/lib/mysql-connector-java-8.0.30.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/mysql-connector-java-5.1.47.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/clickhouse-jdbc-0.3.2-patch8-http.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/mariadb-java-client-3.0.8.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/mssql-jdbc-11.2.1.jre17.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/oceanbase-client-2.4.2.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/postgresql-42.5.1.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/sqlite-jdbc-3.39.3.0.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/ojdbc11.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/ojdbc8-19.3.0.0.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/orai18n-19.3.0.0.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/h2-2.1.214.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/DmJdbcDriver18-8.1.2.141.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/HikariCP-4.0.3.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/redis-jdbc-driver-1.3.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/kingbase8-8.6.0.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/hive-jdbc-3.1.2-standalone.jar
|
||||
- https://oss-chat2db.alibaba.com/lib/mongo-jdbc-standalone-1.18.jar
|
||||
# flywaydb 输出执行sql的日志
|
||||
logging:
|
||||
level:
|
||||
org:
|
||||
flywaydb: debug
|
||||
# 登录功能
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
token-name: DBHUB
|
||||
timeout: 2592000
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: true
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
# jwt秘钥 部署的时候需要改掉,不然可以随便破解登录
|
||||
jwt-secret-key: jwt_dbhub
|
||||
is-write-header: true
|
||||
|
||||
chatgpt:
|
||||
apiKey: sk-xxxx
|
||||
apiHost: https://api.openai.com/
|
||||
# 可以选择GPT3或GPT35
|
||||
version: GPT35
|
||||
context:
|
||||
length: 4
|
@ -0,0 +1,13 @@
|
||||
CREATE TABLE IF NOT EXISTS `dbhub_user` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`user_name` varchar(32) NOT NULL COMMENT '用户名',
|
||||
`password` varchar(256) DEFAULT NULL COMMENT '密码',
|
||||
`nick_name` varchar(256) DEFAULT NULL COMMENT '昵称',
|
||||
`email` varchar(256) DEFAULT NULL COMMENT '邮箱',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据源连接表'
|
||||
;
|
||||
|
||||
INSERT INTO `dbhub_user` (`user_name`,`password`,`nick_name`) VALUES ('dbhub','$2a$10$yElafjDHPoPHSaCo6cjJGuWmtXWNVz/cOOOtDg99eNfvUfalzfane','管理员');
|
@ -0,0 +1,44 @@
|
||||
CREATE TABLE IF NOT EXISTS `data_source` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
|
||||
`alias` varchar(128) DEFAULT NULL COMMENT '别名',
|
||||
`url` varchar(1024) DEFAULT NULL COMMENT '连接地址',
|
||||
`user_name` varchar(128) DEFAULT NULL COMMENT '用户名',
|
||||
`password` varchar(256) DEFAULT NULL COMMENT '密码',
|
||||
`type` varchar(32) DEFAULT NULL COMMENT '数据库类型',
|
||||
`env_type` varchar(32) DEFAULT NULL COMMENT '环境类型',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='数据源连接表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `operation_log` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`data_source_id` bigint(20) unsigned NOT NULL COMMENT '数据源连接ID',
|
||||
`database_name` varchar(128) DEFAULT NULL COMMENT 'db名称',
|
||||
`type` varchar(32) NOT NULL COMMENT '数据库类型',
|
||||
`ddl` text DEFAULT NULL COMMENT 'ddl内容',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='我的执行记录表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `operation_saved` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`data_source_id` bigint(20) unsigned NOT NULL COMMENT '数据源连接ID',
|
||||
`database_name` varchar(128) DEFAULT NULL COMMENT 'db名称',
|
||||
`name` varchar(128) DEFAULT NULL COMMENT '保存名称',
|
||||
`type` varchar(32) NOT NULL COMMENT '数据库类型',
|
||||
`status` varchar(32) NOT NULL COMMENT 'ddl语句状态:DRAFT/RELEASE',
|
||||
`ddl` text DEFAULT NULL COMMENT 'ddl内容',
|
||||
`tab_opened` text DEFAULT NULL COMMENT '是否在tab中被打开,y表示打开,n表示未打开',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='我的保存表'
|
||||
;
|
||||
|
@ -0,0 +1,11 @@
|
||||
CREATE TABLE IF NOT EXISTS `system_config` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`code` varchar(32) NOT NULL COMMENT '配置项编码',
|
||||
`content` varchar(256) DEFAULT NULL COMMENT '配置项内容',
|
||||
`summary` varchar(256) DEFAULT NULL COMMENT '配置项说明',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置中心表'
|
||||
;
|
||||
create UNIQUE INDEX uk_code on system_config(code) ;
|
@ -0,0 +1 @@
|
||||
ALTER TABLE `operation_saved` ADD COLUMN `db_schema_name` varchar(128) NULL COMMENT 'schema名称';
|
@ -0,0 +1,9 @@
|
||||
ALTER TABLE `data_source` ADD COLUMN `host` varchar(128) NULL COMMENT 'host地址';
|
||||
ALTER TABLE `data_source` ADD COLUMN `port` varchar(128) NULL COMMENT '端口';
|
||||
ALTER TABLE `data_source` ADD COLUMN `ssh` varchar(1024) NULL COMMENT 'ssh配置信息json';
|
||||
ALTER TABLE `data_source` ADD COLUMN `ssl` varchar(1024) NULL COMMENT 'ssl配置信息json';
|
||||
ALTER TABLE `data_source` ADD COLUMN `sid` varchar(32) NULL COMMENT 'sid';
|
||||
ALTER TABLE `data_source` ADD COLUMN `driver` varchar(128) NULL COMMENT '驱动信息';
|
||||
ALTER TABLE `data_source` ADD COLUMN `jdbc` varchar(128) NULL COMMENT 'jdbc版本';
|
||||
ALTER TABLE `data_source` ADD COLUMN `extend_info` varchar(4096) NULL COMMENT '自定义扩展字段json';
|
||||
create INDEX idx_user_id on data_source(user_id) ;
|
@ -0,0 +1,39 @@
|
||||
CREATE TABLE IF NOT EXISTS `dashboard` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`name` varchar(128) DEFAULT NULL COMMENT '报表名称',
|
||||
`description` varchar(128) DEFAULT NULL COMMENT '报表描述',
|
||||
`schema` text DEFAULT NULL COMMENT '报表布局信息',
|
||||
`deleted` text DEFAULT NULL COMMENT '是否被删除,y表示删除,n表示未删除',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='自定义报表表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `chart` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`name` varchar(128) DEFAULT NULL COMMENT '图表名称',
|
||||
`description` varchar(128) DEFAULT NULL COMMENT '图表描述',
|
||||
`schema` text DEFAULT NULL COMMENT '图表信息',
|
||||
`data_source_id` bigint(20) unsigned DEFAULT NULL COMMENT '数据源连接ID',
|
||||
`type` varchar(32) DEFAULT NULL COMMENT '数据库类型',
|
||||
`database_name` varchar(128) DEFAULT NULL COMMENT 'db名称',
|
||||
`ddl` text DEFAULT NULL COMMENT 'ddl内容',
|
||||
`deleted` text DEFAULT NULL COMMENT '是否被删除,y表示删除,n表示未删除',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='自定义报表表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `dashboard_chart_relation` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`dashboard_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '报表id',
|
||||
`chart_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '图表id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='自定义报表表'
|
||||
;
|
@ -0,0 +1,70 @@
|
||||
CREATE TABLE IF NOT EXISTS `data_source` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
|
||||
`alias` varchar(128) DEFAULT NULL COMMENT '别名',
|
||||
`url` varchar(1024) DEFAULT NULL COMMENT '连接地址',
|
||||
`user_name` varchar(128) DEFAULT NULL COMMENT '用户名',
|
||||
`password` varchar(256) DEFAULT NULL COMMENT '密码',
|
||||
`type` varchar(32) DEFAULT NULL COMMENT '数据库类型',
|
||||
`env_type` varchar(32) DEFAULT NULL COMMENT '环境类型',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='数据源连接表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `operation_log` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`data_source_id` bigint(20) unsigned NOT NULL COMMENT '数据源连接ID',
|
||||
`database_name` varchar(128) DEFAULT NULL COMMENT 'db名称',
|
||||
`type` varchar(32) NOT NULL COMMENT '数据库类型',
|
||||
`ddl` text DEFAULT NULL COMMENT 'ddl内容',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='我的执行记录表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `operation_saved` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`data_source_id` bigint(20) unsigned NOT NULL COMMENT '数据源连接ID',
|
||||
`database_name` varchar(128) DEFAULT NULL COMMENT 'db名称',
|
||||
`name` varchar(128) DEFAULT NULL COMMENT '保存名称',
|
||||
`type` varchar(32) NOT NULL COMMENT '数据库类型',
|
||||
`status` varchar(32) NOT NULL COMMENT 'ddl语句状态:DRAFT/RELEASE',
|
||||
`ddl` text DEFAULT NULL COMMENT 'ddl内容',
|
||||
`tab_opened` text DEFAULT NULL COMMENT '是否在tab中被打开,y表示打开,n表示未打开',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='我的保存表'
|
||||
;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `dbhub_user` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`user_name` varchar(32) NOT NULL COMMENT '用户名',
|
||||
`password` varchar(256) DEFAULT NULL COMMENT '密码',
|
||||
`nick_name` varchar(256) DEFAULT NULL COMMENT '昵称',
|
||||
`email` varchar(256) DEFAULT NULL COMMENT '邮箱',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据源连接表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `system_config` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`code` varchar(32) NOT NULL COMMENT '配置项编码',
|
||||
`content` varchar(256) DEFAULT NULL COMMENT '配置项内容',
|
||||
`summary` varchar(256) DEFAULT NULL COMMENT '配置项说明',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置中心表'
|
||||
;
|
||||
create UNIQUE INDEX uk_code on system_config(code) ;
|
||||
|
||||
INSERT INTO `dbhub_user` (`user_name`,`password`,`nick_name`) VALUES ('dbhub','$2a$10$yElafjDHPoPHSaCo6cjJGuWmtXWNVz/cOOOtDg99eNfvUfalzfane','管理员');
|
@ -0,0 +1,9 @@
|
||||
ALTER TABLE `data_source` ADD COLUMN `host` varchar(128) NULL COMMENT 'host地址';
|
||||
ALTER TABLE `data_source` ADD COLUMN `port` varchar(128) NULL COMMENT '端口';
|
||||
ALTER TABLE `data_source` ADD COLUMN `ssh` varchar(1024) NULL COMMENT 'ssh配置信息json';
|
||||
ALTER TABLE `data_source` ADD COLUMN `ssl` varchar(1024) NULL COMMENT 'ssl配置信息json';
|
||||
ALTER TABLE `data_source` ADD COLUMN `sid` varchar(32) NULL COMMENT 'sid';
|
||||
ALTER TABLE `data_source` ADD COLUMN `driver` varchar(128) NULL COMMENT '驱动信息';
|
||||
ALTER TABLE `data_source` ADD COLUMN `jdbc` varchar(128) NULL COMMENT 'jdbc版本';
|
||||
ALTER TABLE `data_source` ADD COLUMN `extend_info` varchar(4096) NULL COMMENT '自定义扩展字段json';
|
||||
create INDEX idx_user_id on data_source(user_id) ;
|
@ -0,0 +1,70 @@
|
||||
CREATE TABLE IF NOT EXISTS `data_source` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
|
||||
`alias` varchar(128) DEFAULT NULL COMMENT '别名',
|
||||
`url` varchar(1024) DEFAULT NULL COMMENT '连接地址',
|
||||
`user_name` varchar(128) DEFAULT NULL COMMENT '用户名',
|
||||
`password` varchar(256) DEFAULT NULL COMMENT '密码',
|
||||
`type` varchar(32) DEFAULT NULL COMMENT '数据库类型',
|
||||
`env_type` varchar(32) DEFAULT NULL COMMENT '环境类型',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='数据源连接表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `operation_log` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`data_source_id` bigint(20) unsigned NOT NULL COMMENT '数据源连接ID',
|
||||
`database_name` varchar(128) DEFAULT NULL COMMENT 'db名称',
|
||||
`type` varchar(32) NOT NULL COMMENT '数据库类型',
|
||||
`ddl` text DEFAULT NULL COMMENT 'ddl内容',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='我的执行记录表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `operation_saved` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`data_source_id` bigint(20) unsigned NOT NULL COMMENT '数据源连接ID',
|
||||
`database_name` varchar(128) DEFAULT NULL COMMENT 'db名称',
|
||||
`name` varchar(128) DEFAULT NULL COMMENT '保存名称',
|
||||
`type` varchar(32) NOT NULL COMMENT '数据库类型',
|
||||
`status` varchar(32) NOT NULL COMMENT 'ddl语句状态:DRAFT/RELEASE',
|
||||
`ddl` text DEFAULT NULL COMMENT 'ddl内容',
|
||||
`tab_opened` text DEFAULT NULL COMMENT '是否在tab中被打开,y表示打开,n表示未打开',
|
||||
`user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='我的保存表'
|
||||
;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `dbhub_user` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`user_name` varchar(32) NOT NULL COMMENT '用户名',
|
||||
`password` varchar(256) DEFAULT NULL COMMENT '密码',
|
||||
`nick_name` varchar(256) DEFAULT NULL COMMENT '昵称',
|
||||
`email` varchar(256) DEFAULT NULL COMMENT '邮箱',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据源连接表'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `system_config` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`code` varchar(32) NOT NULL COMMENT '配置项编码',
|
||||
`content` varchar(256) DEFAULT NULL COMMENT '配置项内容',
|
||||
`summary` varchar(256) DEFAULT NULL COMMENT '配置项说明',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置中心表'
|
||||
;
|
||||
create UNIQUE INDEX uk_code on system_config(code) ;
|
||||
|
||||
INSERT INTO `dbhub_user` (`user_name`,`password`,`nick_name`) VALUES ('dbhub','$2a$10$yElafjDHPoPHSaCo6cjJGuWmtXWNVz/cOOOtDg99eNfvUfalzfane','管理员');
|
@ -0,0 +1 @@
|
||||
ALTER TABLE `operation_saved` ADD COLUMN `db_schema_name` varchar(128) NULL COMMENT 'schema名称';
|
@ -0,0 +1,9 @@
|
||||
ALTER TABLE `data_source` ADD COLUMN `host` varchar(128) NULL COMMENT 'host地址';
|
||||
ALTER TABLE `data_source` ADD COLUMN `port` varchar(128) NULL COMMENT '端口';
|
||||
ALTER TABLE `data_source` ADD COLUMN `ssh` varchar(1024) NULL COMMENT 'ssh配置信息json';
|
||||
ALTER TABLE `data_source` ADD COLUMN `ssl` varchar(1024) NULL COMMENT 'ssl配置信息json';
|
||||
ALTER TABLE `data_source` ADD COLUMN `sid` varchar(32) NULL COMMENT 'sid';
|
||||
ALTER TABLE `data_source` ADD COLUMN `driver` varchar(128) NULL COMMENT '驱动信息';
|
||||
ALTER TABLE `data_source` ADD COLUMN `jdbc` varchar(128) NULL COMMENT 'jdbc版本';
|
||||
ALTER TABLE `data_source` ADD COLUMN `extend_info` varchar(4096) NULL COMMENT '自定义扩展字段json';
|
||||
create INDEX idx_user_id on data_source(user_id) ;
|
@ -0,0 +1,8 @@
|
||||
200=成功
|
||||
500=內部异常
|
||||
name=用户名
|
||||
pwd=密码
|
||||
COMMON_SYSTEM_ERROR=系统开小差啦,请尝试刷新页面或者联系管理员
|
||||
CONSOLE_CONNECT_ERROR=控制台链接错误
|
||||
DATASOURCE_CONNECT_ERROR=数据源连接错误
|
||||
DATASOURCE_TEST_ERROR=数据源测试连接错误
|
@ -0,0 +1,8 @@
|
||||
200=success
|
||||
500=unexpected exception
|
||||
name=user name
|
||||
pwd=password
|
||||
COMMON_SYSTEM_ERROR=system error, please contact the system admin
|
||||
CONSOLE_CONNECT_ERROR=create console connection error
|
||||
DATASOURCE_CONNECT_ERROR=create data source connection error
|
||||
DATASOURCE_TEST_ERROR=test data source connection error
|
@ -0,0 +1,8 @@
|
||||
200=成功
|
||||
500=內部异常
|
||||
name=用户名
|
||||
pwd=密码
|
||||
COMMON_SYSTEM_ERROR=系统开小差啦,请尝试刷新页面或者联系管理员
|
||||
CONSOLE_CONNECT_ERROR=控制台链接错误
|
||||
DATASOURCE_CONNECT_ERROR=数据源连接错误
|
||||
DATASOURCE_TEST_ERROR=数据源测试连接错误
|
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
|
||||
<property name="LOG_PATH" value="${user.home}/.chat2db/logs" />
|
||||
<property name="LOG_FILE" value="${LOG_PATH}/application.log" />
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="APPLICATION"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_FILE}</file>
|
||||
<encoder>
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<maxHistory>7</maxHistory>
|
||||
<maxFileSize>50MB</maxFileSize>
|
||||
<totalSizeCap>5GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="APPLICATION"/>
|
||||
</root>
|
||||
</configuration>
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.7 KiB |
@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/ico"
|
||||
sizes="32x32"
|
||||
href="./static/front/logo.ico"
|
||||
/>
|
||||
<title>Chat2DB</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Chat2DB 是面向开发人员的免费多平台数据库工具。多种数据库一个工具。它用于查询、创建和管理数据库,数据库可以在本地、服务器或云端。支持 MySQL、PostgreSQL、Microsoft SQL Server、Oracle、H2等,未来我们会不断完善其他非关系型数据的支持,如Redis。"
|
||||
/>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="数据库,chatgpt,chat,DB,database,后端,程序员,数据库"
|
||||
/>
|
||||
<meta property="og:title" content="Chat2DB"/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Chat2DB 是面向开发人员的免费多平台数据库工具。多种数据库一个工具。它用于查询、创建和管理数据库,数据库可以在本地、服务器或云端。支持 MySQL、PostgreSQL、Microsoft SQL Server、Oracle、H2等,未来我们会不断完善其他非关系型数据的支持,如Redis。"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<link rel="stylesheet" href="./static/front/umi.css"/>
|
||||
<script>
|
||||
window.routerBase = "/";
|
||||
|
||||
</script>
|
||||
<script>
|
||||
//! umi version: 3.5.39
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>
|
||||
console.log("run startServer");
|
||||
console.log("window===>", window.myAPI);
|
||||
if (window.myAPI) {
|
||||
window.myAPI.startServerForSpawn();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script src="./static/front/umi.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,22 @@
|
||||
package ai.chat2db.server.start.test;
|
||||
|
||||
import ai.chat2db.server.start.Application;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
/**
|
||||
* 本地环境的启动。
|
||||
* 主要为了读取本地的一些配置 比如日志输出就和其他环境不一样
|
||||
*
|
||||
* @author 是仪
|
||||
*/
|
||||
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@Slf4j
|
||||
public class TestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package ai.chat2db.server.start.test.common;
|
||||
|
||||
import ai.chat2db.server.start.Application;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
/**
|
||||
* 基础测试类
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
**/
|
||||
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@Slf4j
|
||||
public abstract class BaseTest {
|
||||
|
||||
}
|
@ -0,0 +1,242 @@
|
||||
package ai.chat2db.server.start.test.druid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.DbType;
|
||||
import com.alibaba.druid.sql.PagerUtils;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.alibaba.druid.sql.ast.SQLDataTypeImpl;
|
||||
import com.alibaba.druid.sql.ast.SQLLimit;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLNotNullConstraint;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlCharExpr;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
|
||||
import com.alibaba.druid.sql.parser.MysqlUtils;
|
||||
import com.alibaba.druid.sql.parser.SQLParserFeature;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
public class SqlUtilsTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
List<SQLStatement> sqlStatements = SQLUtils.parseStatements("select 1 from test;", DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatements);
|
||||
sqlStatements = SQLUtils.parseStatements("use xxx;select 1 from test;explain select 1 from test", DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatements);
|
||||
sqlStatements = SQLUtils.parseStatements("select 1 from1 test", DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatements);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test55() {
|
||||
List<SQLStatement> sqlStatements = SQLUtils.parseStatements("create table test(id int) comment 'xx';",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatements);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
String sql = "select * from test";
|
||||
log.info("分页:{} ----- {} --- {}", PagerUtils.count(sql, DbType.mysql),
|
||||
PagerUtils.limit(sql, DbType.mysql, 1000, 999),
|
||||
PagerUtils.limit(sql, DbType.mysql, 1000, 999, true));
|
||||
sql = "select * from test where id=1 limit 100;";
|
||||
log.info("分页:{} ----- {} --- {}", PagerUtils.count(sql, DbType.mysql),
|
||||
PagerUtils.limit(sql, DbType.mysql, 1000, 999),
|
||||
PagerUtils.limit(sql, DbType.mysql, 1000, 999, true));
|
||||
|
||||
sql = "select * from test where id=1 limit 100,10;";
|
||||
log.info("分页:{} ----- {} --- {}", PagerUtils.count(sql, DbType.mysql),
|
||||
PagerUtils.limit(sql, DbType.mysql, 1000, 999),
|
||||
PagerUtils.limit(sql, DbType.mysql, 1000, 999, true));
|
||||
|
||||
sql = "select * from test where id=1 limit 100,10;";
|
||||
log.info("分页:{} ----- {} --- {}", PagerUtils.count(sql, DbType.mysql),
|
||||
PagerUtils.limit(sql, DbType.mysql, 2, 2),
|
||||
PagerUtils.limit(sql, DbType.mysql, 2, 2, true));
|
||||
|
||||
sql = "select * from test union select * from test2";
|
||||
log.info("分页:{} ----- {} --- {}", PagerUtils.count(sql, DbType.mysql),
|
||||
PagerUtils.limit(sql, DbType.mysql, 2, 2),
|
||||
PagerUtils.limit(sql, DbType.mysql, 2, 2, true));
|
||||
|
||||
sql = "select * from test union select * from test2";
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(sql, DbType.mysql);
|
||||
SQLSelectStatement sqlSelectStatement = (SQLSelectStatement)sqlStatement;
|
||||
log.info("test{}", sqlSelectStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test56() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"create table test(id int ,name varchar(32) not null default 'xx' comment 'name',nu int auto_increment,"
|
||||
+ "index ds(id) ,primary key (id,nu)) "
|
||||
+ "comment 'xx';",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4() {
|
||||
MySqlCreateTableStatement x = new MySqlCreateTableStatement();
|
||||
x.setTableName("ff");
|
||||
x.setComment(new MySqlCharExpr(null));
|
||||
SQLColumnDefinition c = new SQLColumnDefinition();
|
||||
x.addColumn(c);
|
||||
|
||||
c.setName("name");
|
||||
SQLDataTypeImpl sqlDataType = new SQLDataTypeImpl();
|
||||
sqlDataType.setName("varchar(32)");
|
||||
c.setDataType(sqlDataType);
|
||||
c.addConstraint(new SQLNotNullConstraint());
|
||||
c.setComment(new MySqlCharExpr("xname"));
|
||||
//x.addColumn();
|
||||
log.info(x.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testreaname() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"rename table data_ops_table_test_1667268894825 to data_ops_table_test_166726889482511;",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testcomment() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"\n"
|
||||
+ "alter table data_ops_table_test_166726889482511\n"
|
||||
+ " comment '测试表33';",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dropindex() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"drop index data_ops_table_test_1667268894825_idx_date on data_ops_table_test_1667268894825;",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createindex() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"\n"
|
||||
+ "create index data_ops_table_test_1667268894825_idx_date\n"
|
||||
+ " on data_ops_table_test_1667268894825 (date desc, id asc)\n"
|
||||
+ " comment '日期索引';",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addColumn() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"alter table data_ops_table_test_1667268894825\n"
|
||||
+ " add column_5 int default de null;",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void change() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"alter table data_ops_table_test_1667268894825\n"
|
||||
+ " change number number1 bigint null comment '长整型';",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modify() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"alter table data_ops_table_test_1667268894825\n"
|
||||
+ " modify number1 bigint null comment '长整型';",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dropColumn() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"alter table data_ops_table_test_1667268894825\n"
|
||||
+ " drop column string;",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dropPrimaryKey() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"ALTER TABLE `ali_dbhub_test`.`data_ops_table_test_1671368857363` \n"
|
||||
+ "DROP PRIMARY KEY,\n"
|
||||
+ "ADD PRIMARY KEY (`date`) USING BTREE;",
|
||||
DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void coment() {
|
||||
try {
|
||||
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"comment on index DATA_OPS_TEMPLATE_TEST_1672663574919_idx_date is '日期索引xx';\n",
|
||||
DbType.h2, SQLParserFeature.PrintSQLWhileParsingFailed);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errro() {
|
||||
List<SQLStatement> sqlStatementList = SQLUtils.parseStatements(
|
||||
"alter table data_ops_table_test_1667268894825 drop column string;comment on index "
|
||||
+ "DATA_OPS_TEMPLATE_TEST_1672663574919_idx_date is '日期索引xx';\n",
|
||||
DbType.h2, SQLParserFeature.PrintSQLWhileParsingFailed);
|
||||
log.info("解析sql:{}", sqlStatementList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spilt() {
|
||||
List<String> list = MysqlUtils.splitAndRemoveComment(
|
||||
"alter table data_ops_table_test_1667268894825 drop column string;comment on index "
|
||||
+ "DATA_OPS_TEMPLATE_TEST_1672663574919_idx_date is '日期索引xx;;;';\n", DbType.h2);
|
||||
log.info("解析sql:{}", JSON.toJSONString(list));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void creattable() {
|
||||
List<SQLStatement> sqlStatementList = SQLUtils.parseStatements(
|
||||
"CREATE TABLE `data_ops_table_test_1673096155228`\n"
|
||||
+ "\t(\n"
|
||||
+ "\t `id` bigint PRIMARY KEY AUTO_INCREMENT NOT NULL COMMENT '主键自增',\n"
|
||||
+ "\t `date` datetime(3) not null COMMENT '日期',\n"
|
||||
+ "\t `number` bigint COMMENT '长整型',\n"
|
||||
+ "\t `string` VARCHAR(100) default 'DATA' COMMENT '名字',\n"
|
||||
+ "\t index data_ops_table_test_1673096155228_idx_date (date desc) comment '日期索引',\n"
|
||||
+ "\t unique data_ops_table_test_1673096155228_uk_number (number) comment '唯一索引',\n"
|
||||
+ "\t index data_ops_table_test_1673096155228_idx_number_string (number, date) comment '联合索引'\n"
|
||||
+ "\t) COMMENT ='测试表';", DbType.mysql);
|
||||
log.info("解析sql:{}", sqlStatementList);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testlimit2() {
|
||||
SQLLimit sqlLimit= SQLUtils.getLimit("select * from t_orderdetail limit 0,1",DbType.mysql);
|
||||
log.info("解析sql:{}", sqlLimit);
|
||||
sqlLimit= SQLUtils.getLimit("select * from t_orderdetail",DbType.mysql);
|
||||
log.info("解析sql:{}", sqlLimit);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package ai.chat2db.server.start.test.druid;
|
||||
|
||||
import com.alibaba.druid.DbType;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
public class SqlUtilsTest2 {
|
||||
|
||||
@Test
|
||||
public void coment() {
|
||||
SQLStatement sqlStatement = SQLUtils.parseSingleStatement(
|
||||
"comment on index myindex is '日期xxx';\n",
|
||||
DbType.h2);
|
||||
log.info("解析sql:{}", sqlStatement);
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package ai.chat2db.server.start.test.mybatis;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ai.chat2db.server.start.test.common.BaseTest;
|
||||
|
||||
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
|
||||
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
|
||||
import com.baomidou.mybatisplus.generator.config.OutputFile;
|
||||
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
|
||||
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* 生成mybatis 的mapper
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Slf4j
|
||||
public class MybatisGeneratorTest extends BaseTest {
|
||||
@Resource
|
||||
private DataSource dataSource;
|
||||
|
||||
@Test
|
||||
public void coreGenerator() {
|
||||
//doGenerator(Lists.newArrayList("data_source"));
|
||||
//doGenerator(Lists.newArrayList("operation_log"));
|
||||
//doGenerator(Lists.newArrayList("operation_saved"));
|
||||
doGenerator(Lists.newArrayList("dbhub_user"));
|
||||
}
|
||||
|
||||
private void doGenerator(List<String> tableList) {
|
||||
|
||||
// 当前项目地址 拿到的是ali-dbhub-server-start地址
|
||||
String outputDir = System.getProperty("user.dir")
|
||||
+ "/../ali-dbhub-server-domain/ali-dbhub-server-domain-repository/src/main"
|
||||
+ "/java";
|
||||
String xmlDir = System.getProperty("user.dir")
|
||||
+ "/../ali-dbhub-server-domain/ali-dbhub-server-domain-repository/src/main"
|
||||
+ "/resources/com/alibaba/dbhub/server/domain/repository";
|
||||
|
||||
// 不要生成service controller
|
||||
Map<OutputFile, String> pathInfo = new HashMap<>();
|
||||
pathInfo.put(OutputFile.service, null);
|
||||
pathInfo.put(OutputFile.serviceImpl, null);
|
||||
pathInfo.put(OutputFile.xml, xmlDir);
|
||||
pathInfo.put(OutputFile.controller, null);
|
||||
|
||||
FastAutoGenerator
|
||||
.create(new DataSourceConfig.Builder(dataSource)
|
||||
.typeConvert(new MySqlTypeConvert()))
|
||||
//全局配置
|
||||
.globalConfig(builder -> {
|
||||
// 设置作者
|
||||
builder.author("ali-dbhub")
|
||||
//执行完毕不打开文件夹
|
||||
.disableOpenDir()
|
||||
// 指定输出目录
|
||||
.outputDir(outputDir);
|
||||
})
|
||||
//包配置
|
||||
.packageConfig(builder -> {
|
||||
// 设置父包名
|
||||
builder.parent("ai.chat2db.server.domain.repository")
|
||||
//生成实体层
|
||||
.entity("entity")
|
||||
.pathInfo(pathInfo)
|
||||
//生成mapper层
|
||||
.mapper("mapper");
|
||||
})
|
||||
//策略配置
|
||||
.strategyConfig(builder -> {
|
||||
// 设置需要生成的表名
|
||||
builder.addInclude(tableList)
|
||||
//开启实体类配置
|
||||
.entityBuilder()
|
||||
.formatFileName("%sDO")
|
||||
// 覆盖文件
|
||||
.enableFileOverride()
|
||||
//.addTableFills(new Column("gmt_create", FieldFill.INSERT)) // 表字段填充
|
||||
//.addTableFills(new Column("update_time", FieldFill.INSERT_UPDATE)) // 表字段填充
|
||||
//开启lombok
|
||||
.enableLombok()
|
||||
.mapperBuilder()
|
||||
// 覆盖文件
|
||||
.enableFileOverride()
|
||||
;
|
||||
|
||||
})
|
||||
//模板配置
|
||||
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
|
||||
//执行
|
||||
.execute();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package ai.chat2db.server.start.test.sql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.Statement;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* 模板
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
@Slf4j
|
||||
public class DbhubJdbcTemplateTest {
|
||||
|
||||
private static JdbcTemplate jdbcTemplate;
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() throws Exception {
|
||||
log.info("连接mysql");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void test() throws Exception {
|
||||
|
||||
jdbcTemplate.execute("use data_ops_test");
|
||||
|
||||
Connection connection = jdbcTemplate.getDataSource().getConnection();
|
||||
Statement statement = connection.createStatement();
|
||||
boolean execute = statement.execute("select * from test_query");
|
||||
log.info("execute:{}",execute);
|
||||
|
||||
statement = connection.createStatement();
|
||||
execute = statement.execute("INSERT INTO `test_query` (name,date,number) VALUES ('姓名','2022-01-01',123);");
|
||||
log.info("execute:{}",execute);
|
||||
//Returns:
|
||||
//true if the first result is a ResultSet object; false if it is an update count or there are no results
|
||||
statement = connection.createStatement();
|
||||
execute = statement.execute("show tables");
|
||||
log.info("execute:{}",execute);
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package com.alibaba.druid.sql.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.DbType;
|
||||
|
||||
public class MysqlUtils extends SQLParserUtils {
|
||||
|
||||
public static List<String> sp(String sql, DbType dbType) {
|
||||
List<String> tables = new ArrayList<>();
|
||||
|
||||
Lexer lexer = createLexer(sql, dbType);
|
||||
lexer.nextToken();
|
||||
|
||||
|
||||
|
||||
for (; lexer.token != Token.EOF; ) {
|
||||
switch (lexer.token) {
|
||||
case SEMI:
|
||||
|
||||
System.out.println(lexer.token);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
lexer.nextToken();
|
||||
|
||||
}
|
||||
|
||||
|
||||
return new ArrayList<>(tables);
|
||||
}
|
||||
|
||||
|
||||
public static List<String> splitAndRemoveComment(String sql, DbType dbType) {
|
||||
if (dbType == null) {
|
||||
dbType = DbType.other;
|
||||
}
|
||||
|
||||
boolean containsCommentAndSemi = false;
|
||||
{
|
||||
Lexer lexer = createLexer(sql, dbType);
|
||||
lexer.config(SQLParserFeature.SkipComments, false);
|
||||
lexer.config(SQLParserFeature.KeepComments, true);
|
||||
|
||||
while (lexer.token != Token.EOF) {
|
||||
if (lexer.token == Token.LINE_COMMENT
|
||||
|| lexer.token == Token.MULTI_LINE_COMMENT
|
||||
|| lexer.token == Token.SEMI) {
|
||||
containsCommentAndSemi = true;
|
||||
break;
|
||||
}
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
if (!containsCommentAndSemi) {
|
||||
return Collections.singletonList(sql);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Lexer lexer = createLexer(sql, dbType);
|
||||
lexer.nextToken();
|
||||
|
||||
boolean script = false;
|
||||
if (dbType == DbType.odps && lexer.token == Token.VARIANT) {
|
||||
script = true;
|
||||
}
|
||||
|
||||
if (script || lexer.identifierEquals("pai") || lexer.identifierEquals("jar")) {
|
||||
return Collections.singletonList(sql);
|
||||
}
|
||||
}
|
||||
|
||||
List list = new ArrayList();
|
||||
|
||||
Lexer lexer = createLexer(sql, dbType);
|
||||
lexer.config(SQLParserFeature.SkipComments, false);
|
||||
lexer.config(SQLParserFeature.KeepComments, true);
|
||||
|
||||
boolean set = false, paiOrJar = false;
|
||||
int start = 0;
|
||||
Token token = lexer.token;
|
||||
for (; lexer.token != Token.EOF; ) {
|
||||
if (token == Token.SEMI) {
|
||||
int len = lexer.startPos - start;
|
||||
if (len > 0) {
|
||||
String lineSql = sql.substring(start, lexer.startPos);
|
||||
String splitSql = set
|
||||
? removeLeftComment(lineSql, dbType)
|
||||
: removeComment(lineSql, dbType
|
||||
).trim();
|
||||
if (!splitSql.isEmpty()) {
|
||||
list.add(splitSql);
|
||||
}
|
||||
}
|
||||
start = lexer.startPos + 1;
|
||||
set = false;
|
||||
} else if (token == Token.MULTI_LINE_COMMENT) {
|
||||
int len = lexer.startPos - start;
|
||||
if (len > 0) {
|
||||
String splitSql = removeComment(
|
||||
sql.substring(start, lexer.startPos),
|
||||
dbType
|
||||
).trim();
|
||||
if (!splitSql.isEmpty()) {
|
||||
list.add(splitSql);
|
||||
}
|
||||
}
|
||||
lexer.nextToken();
|
||||
token = lexer.token;
|
||||
start = lexer.startPos;
|
||||
continue;
|
||||
} else if (token == Token.CREATE) {
|
||||
lexer.nextToken();
|
||||
|
||||
if (lexer.token == Token.FUNCTION || lexer.identifierEquals("FUNCTION")) {
|
||||
lexer.nextToken();
|
||||
lexer.nextToken();
|
||||
if (lexer.token == Token.AS) {
|
||||
lexer.nextToken();
|
||||
if (lexer.token == Token.LITERAL_CHARS) {
|
||||
lexer.nextToken();
|
||||
token = lexer.token;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
lexer.startPos = sql.length();
|
||||
break;
|
||||
}
|
||||
|
||||
token = lexer.token;
|
||||
continue;
|
||||
} else if (set && token == Token.EQ && dbType == DbType.odps) {
|
||||
lexer.nextTokenForSet();
|
||||
token = lexer.token;
|
||||
continue;
|
||||
} else if (dbType == DbType.odps
|
||||
&& lexer.ch != '.'
|
||||
&& (lexer.identifierEquals("pai") || lexer.identifierEquals("jar"))) {
|
||||
paiOrJar = true;
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals("USING")) {
|
||||
lexer.nextToken();
|
||||
if (lexer.identifierEquals("jar")) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
}
|
||||
|
||||
if (lexer.token == Token.SET) {
|
||||
set = true;
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals("ADD") && (dbType == DbType.hive || dbType == DbType.odps)) {
|
||||
lexer.nextToken();
|
||||
if (lexer.identifierEquals("JAR")) {
|
||||
lexer.nextPath();
|
||||
}
|
||||
} else {
|
||||
lexer.nextToken();
|
||||
}
|
||||
token = lexer.token;
|
||||
}
|
||||
|
||||
if (start != sql.length() && token != Token.SEMI) {
|
||||
int end = lexer.startPos;
|
||||
if (end > sql.length()) {
|
||||
end = sql.length();
|
||||
}
|
||||
String splitSql = sql.substring(start, end).trim();
|
||||
if (!paiOrJar) {
|
||||
splitSql = removeComment(splitSql, dbType).trim();
|
||||
} else {
|
||||
if (splitSql.endsWith(";")) {
|
||||
splitSql = splitSql.substring(0, splitSql.length() - 1).trim();
|
||||
}
|
||||
}
|
||||
if (!splitSql.isEmpty()) {
|
||||
list.add(splitSql);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
</configuration>
|