mirror of
https://github.com/CodePhiliaX/Chat2DB.git
synced 2025-09-22 12:35:11 +08:00
db-data-export
This commit is contained in:
@ -2,6 +2,7 @@ package ai.chat2db.server.web.api.controller.rdb;
|
||||
|
||||
import ai.chat2db.server.domain.api.param.MetaDataQueryParam;
|
||||
import ai.chat2db.server.domain.api.param.datasource.DatabaseCreateParam;
|
||||
import ai.chat2db.server.domain.api.param.datasource.DatabaseExportDataParam;
|
||||
import ai.chat2db.server.domain.api.param.datasource.DatabaseExportParam;
|
||||
import ai.chat2db.server.domain.api.param.datasource.DatabaseQueryAllParam;
|
||||
import ai.chat2db.server.domain.api.service.DatabaseService;
|
||||
@ -13,7 +14,10 @@ import ai.chat2db.server.web.api.controller.data.source.request.DataSourceBaseRe
|
||||
import ai.chat2db.server.web.api.controller.data.source.vo.DatabaseVO;
|
||||
import ai.chat2db.server.web.api.controller.rdb.converter.DatabaseConverter;
|
||||
import ai.chat2db.server.web.api.controller.rdb.converter.RdbWebConverter;
|
||||
import ai.chat2db.server.web.api.controller.rdb.data.export.strategy.ExportDBDataStrategy;
|
||||
import ai.chat2db.server.web.api.controller.rdb.factory.ExportDBDataStrategyFactory;
|
||||
import ai.chat2db.server.web.api.controller.rdb.request.DatabaseCreateRequest;
|
||||
import ai.chat2db.server.web.api.controller.rdb.request.DatabaseExportDataRequest;
|
||||
import ai.chat2db.server.web.api.controller.rdb.request.DatabaseExportRequest;
|
||||
import ai.chat2db.server.web.api.controller.rdb.request.UpdateDatabaseRequest;
|
||||
import ai.chat2db.server.web.api.controller.rdb.vo.MetaSchemaVO;
|
||||
@ -27,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -123,4 +128,19 @@ public class DatabaseController {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/export_data")
|
||||
public void exportData(@Valid @RequestBody DatabaseExportDataRequest request, HttpServletResponse response) {
|
||||
Class<?> targetClass = ExportDBDataStrategyFactory.get(request.getExportType());
|
||||
response.setCharacterEncoding("utf-8");
|
||||
DatabaseExportDataParam param = databaseConverter.request2param(request);
|
||||
try {
|
||||
Constructor<?> constructor = targetClass.getDeclaredConstructor();
|
||||
ExportDBDataStrategy service = (ExportDBDataStrategy) constructor.newInstance();
|
||||
service.doExport(param, response);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package ai.chat2db.server.web.api.controller.rdb.converter;
|
||||
|
||||
import ai.chat2db.server.domain.api.param.datasource.DatabaseExportDataParam;
|
||||
import ai.chat2db.server.domain.api.param.datasource.DatabaseExportParam;
|
||||
import ai.chat2db.server.web.api.controller.rdb.request.DatabaseCreateRequest;
|
||||
import ai.chat2db.server.web.api.controller.rdb.request.DatabaseExportDataRequest;
|
||||
import ai.chat2db.server.web.api.controller.rdb.request.DatabaseExportRequest;
|
||||
import ai.chat2db.spi.model.Database;
|
||||
import org.mapstruct.Mapper;
|
||||
@ -12,4 +14,6 @@ public abstract class DatabaseConverter {
|
||||
public abstract Database request2param(DatabaseCreateRequest request);
|
||||
|
||||
public abstract DatabaseExportParam request2param(DatabaseExportRequest request);
|
||||
|
||||
public abstract DatabaseExportDataParam request2param(DatabaseExportDataRequest request);
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package ai.chat2db.server.web.api.controller.rdb.data.export.strategy;
|
||||
|
||||
import ai.chat2db.server.domain.api.enums.ExportFileSuffix;
|
||||
import ai.chat2db.spi.util.ResultSetUtils;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.support.ExcelTypeEnum;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ExportDBData2CsvStrategy extends ExportDBDataStrategy {
|
||||
|
||||
public ExportDBData2CsvStrategy() {
|
||||
suffix = ExportFileSuffix.CSV.getSuffix();
|
||||
contentType = "application/zip";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteArrayOutputStream exportData(Connection connection, String databaseName, String schemaName, String tableName) throws SQLException {
|
||||
String sql;
|
||||
if (Objects.isNull(schemaName)) {
|
||||
sql = String.format("select * from %s", tableName);
|
||||
} else {
|
||||
sql = String.format("select * from %s.%s", schemaName, tableName);
|
||||
}
|
||||
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
|
||||
try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
List<List<String>> headList = ResultSetUtils.getRsHeader(resultSet)
|
||||
.stream()
|
||||
.map(Collections::singletonList)
|
||||
.collect(Collectors.toList());
|
||||
int columnCount = metaData.getColumnCount();
|
||||
List<List<Object>> dataList = new ArrayList<>();
|
||||
while (resultSet.next()) {
|
||||
List<Object> row = new ArrayList<>();
|
||||
for (int i = 1; i <= columnCount; i++) {
|
||||
row.add(resultSet.getString(i));
|
||||
}
|
||||
dataList.add(row);
|
||||
}
|
||||
EasyExcel.write(byteOut).excelType(ExcelTypeEnum.CSV).sheet(tableName).head(headList).doWrite(dataList);
|
||||
}
|
||||
return byteOut;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package ai.chat2db.server.web.api.controller.rdb.data.export.strategy;
|
||||
|
||||
import ai.chat2db.server.domain.api.enums.ExportFileSuffix;
|
||||
import ai.chat2db.spi.util.ResultSetUtils;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ExportDBData2ExcelStrategy extends ExportDBDataStrategy {
|
||||
|
||||
public ExportDBData2ExcelStrategy() {
|
||||
suffix = ExportFileSuffix.EXCEL.getSuffix();
|
||||
contentType = "application/zip";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteArrayOutputStream exportData(Connection connection, String databaseName, String schemaName, String tableName) throws SQLException {
|
||||
String sql;
|
||||
if (Objects.isNull(schemaName)) {
|
||||
sql = String.format("select * from %s", tableName);
|
||||
} else {
|
||||
sql = String.format("select * from %s.%s", schemaName, tableName);
|
||||
}
|
||||
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
|
||||
try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
List<List<String>> headList = ResultSetUtils.getRsHeader(resultSet)
|
||||
.stream()
|
||||
.map(Collections::singletonList)
|
||||
.collect(Collectors.toList());
|
||||
List<List<Object>> dataList = new ArrayList<>();
|
||||
while (resultSet.next()) {
|
||||
List<Object> row = new ArrayList<>();
|
||||
for (int i = 1; i <= columnCount; i++) {
|
||||
row.add(resultSet.getString(i));
|
||||
}
|
||||
dataList.add(row);
|
||||
}
|
||||
EasyExcel.write(byteOut).sheet(tableName).head(headList).doWrite(dataList);
|
||||
}
|
||||
return byteOut;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package ai.chat2db.server.web.api.controller.rdb.data.export.strategy;
|
||||
|
||||
import ai.chat2db.server.domain.api.enums.ExportFileSuffix;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
public class ExportDBData2JsonStrategy extends ExportDBDataStrategy {
|
||||
|
||||
public ExportDBData2JsonStrategy() {
|
||||
suffix = ExportFileSuffix.JSON.getSuffix();
|
||||
contentType = "application/zip";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteArrayOutputStream exportData(Connection connection, String databaseName, String schemaName, String tableName) throws SQLException {
|
||||
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
|
||||
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOut, StandardCharsets.UTF_8))) {
|
||||
String sql;
|
||||
if (Objects.isNull(schemaName)) {
|
||||
sql = String.format("SELECT * FROM %s", tableName);
|
||||
} else {
|
||||
sql = String.format("SELECT * FROM %s.%s", schemaName, tableName);
|
||||
}
|
||||
try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
List<Map<String, Object>> data = new ArrayList<>();
|
||||
|
||||
while (resultSet.next()) {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
for (int i = 1; i <= columnCount; i++) {
|
||||
row.put(metaData.getColumnName(i), resultSet.getObject(i));
|
||||
}
|
||||
data.add(row);
|
||||
}
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
String jsonString = objectMapper.writeValueAsString(data);
|
||||
writer.println(jsonString);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return byteOut;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package ai.chat2db.server.web.api.controller.rdb.data.export.strategy;
|
||||
|
||||
import ai.chat2db.server.domain.api.enums.ExportFileSuffix;
|
||||
import ai.chat2db.spi.sql.Chat2DBContext;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author: zgq
|
||||
* @date: 2024年03月24日 12:50
|
||||
*/
|
||||
public class ExportDBData2SqlStrategy extends ExportDBDataStrategy {
|
||||
|
||||
public ExportDBData2SqlStrategy() {
|
||||
suffix = ExportFileSuffix.SQL.getSuffix();
|
||||
contentType = "application/zip";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteArrayOutputStream exportData(Connection connection, String databaseName, String schemaName, String tableName) throws SQLException {
|
||||
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
|
||||
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOut, StandardCharsets.UTF_8))) {
|
||||
String sql = Chat2DBContext.getDBManage().exportDatabaseData(connection, databaseName, schemaName, tableName);
|
||||
writer.println(sql);
|
||||
}
|
||||
return byteOut;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package ai.chat2db.server.web.api.controller.rdb.data.export.strategy;
|
||||
|
||||
import ai.chat2db.server.domain.api.enums.ExportFileSuffix;
|
||||
import ai.chat2db.server.domain.api.param.datasource.DatabaseExportDataParam;
|
||||
import ai.chat2db.spi.sql.Chat2DBContext;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* @author: zgq
|
||||
* @date: 2024年03月24日 12:46
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public abstract class ExportDBDataStrategy {
|
||||
|
||||
public String suffix;
|
||||
public String contentType;
|
||||
|
||||
public void doExport(DatabaseExportDataParam param, HttpServletResponse response) {
|
||||
String databaseName = param.getDatabaseName();
|
||||
String schemaName = param.getSchemaName();
|
||||
setResponseHeaders(param, response);
|
||||
try (ServletOutputStream outputStream = response.getOutputStream();
|
||||
ZipOutputStream zipOut = new ZipOutputStream(outputStream);
|
||||
Connection connection = Chat2DBContext.getConnection();) {
|
||||
List<String> tableNames = Chat2DBContext.getMetaData().tableNames(connection, databaseName, schemaName, null);
|
||||
tableNames.addAll(Chat2DBContext.getMetaData().viewNames(connection, databaseName, schemaName));
|
||||
for (String tableName : tableNames) {
|
||||
String fileName = tableName + getSuffix();
|
||||
zipOut.putNextEntry(new ZipEntry(fileName));
|
||||
ByteArrayOutputStream byteOut = exportData(connection, databaseName, schemaName, tableName);
|
||||
byteOut.writeTo(zipOut);
|
||||
zipOut.closeEntry();
|
||||
byteOut.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setResponseHeaders(DatabaseExportDataParam param, HttpServletResponse response) {
|
||||
response.setContentType(contentType);
|
||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + getFileName(param) + ExportFileSuffix.ZIP.getSuffix());
|
||||
}
|
||||
|
||||
protected String getFileName(DatabaseExportDataParam param) {
|
||||
return Objects.isNull(param.getSchemaName()) ? param.getDatabaseName() : param.getSchemaName();
|
||||
}
|
||||
|
||||
protected abstract ByteArrayOutputStream exportData(Connection connection, String databaseName, String schemaName, String tableName) throws SQLException;
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package ai.chat2db.server.web.api.controller.rdb.factory;
|
||||
|
||||
import ai.chat2db.server.domain.api.enums.ExportTypeEnum;
|
||||
import ai.chat2db.server.web.api.controller.rdb.data.export.strategy.*;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: zgq
|
||||
* @date: 2024年03月24日 12:53
|
||||
*/
|
||||
public class ExportDBDataStrategyFactory {
|
||||
|
||||
public static final Map<String, Class<? extends ExportDBDataStrategy>> SERVICE_MAP = Map.of(
|
||||
ExportTypeEnum.SQL.getCode(), ExportDBData2SqlStrategy.class,
|
||||
ExportTypeEnum.CSV.getCode(), ExportDBData2CsvStrategy.class,
|
||||
ExportTypeEnum.EXCEL.getCode(), ExportDBData2ExcelStrategy.class,
|
||||
ExportTypeEnum.JSON.getCode(), ExportDBData2JsonStrategy.class
|
||||
);
|
||||
|
||||
@SneakyThrows
|
||||
public static Class<?> get(String type) {
|
||||
Class<?> dataResult = SERVICE_MAP.get(type);
|
||||
if (dataResult == null) {
|
||||
throw new ClassNotFoundException("no ExportUI was found");
|
||||
} else {
|
||||
return dataResult;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package ai.chat2db.server.web.api.controller.rdb.request;
|
||||
|
||||
import ai.chat2db.server.web.api.controller.data.source.request.DataSourceBaseRequest;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author: zgq
|
||||
* @date: 2024年03月24日 12:36
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class DatabaseExportDataRequest extends DataSourceBaseRequest {
|
||||
@NotNull
|
||||
private String exportType;
|
||||
}
|
Reference in New Issue
Block a user