package com.se.simu.service.Impl;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.se.simu.service.SemFilesSimuService;
|
import com.se.simu.utils.ZipUtils;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
|
import java.io.File;
|
import java.io.FileNotFoundException;
|
import java.io.FileOutputStream;
|
import java.io.IOException;
|
import java.nio.charset.StandardCharsets;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.nio.file.StandardCopyOption;
|
import java.sql.*;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.HashMap;
|
|
@Slf4j
|
@Service
|
public class SemFilesSimuServiceImpl implements SemFilesSimuService {
|
|
@Value("${config.outPath}")
|
private String outPath;
|
|
/**
|
* 获取 INTRODUCE
|
*
|
* @return {@link Object}
|
*/
|
@Override
|
public Object getIntroduce() {
|
HashMap<String, Object> introduceMap = new HashMap<>();
|
String introduce = "SEM定义城市空间对象(如建筑物、构筑物等)类型和相互关系的存储结构,支持为空间实体对象挂接非结构化的数据,如人工模型、点云模型、视频文件等。SEM可存储城市空间对象的元数据(Metadata)、实体对象(Entity)、链接对象(LinkObject)、属性(Attribute)、材质(Material)、纹理(Texture)、纹理顶点(TextureVertice)、图片数据(Image)、几何模板(Template)以及扩展内容(ExtensionSchema)等";
|
introduceMap.put("introduce", introduce);
|
introduceMap.put("10张表", "SEM包含元数据表、实体对象表、链接对象表、属性表、材质表、纹理表、纹理顶点表、图片数据表、几何模板表和扩展表");
|
introduceMap.put("Metadata(元数据表)", "用于存储 SEM 基础信息");
|
introduceMap.put("Entity(实体对象表)", "用于存储空间实体对象的几何数据");
|
introduceMap.put("LinkObject(链接对象表)", "用于存储空间实体对象的挂接对象信息");
|
introduceMap.put("Attribute(属性表)", "用于存储空间实体对象的属性");
|
introduceMap.put("Material(材质表)", "用于存储空间实体对象的材质信息");
|
introduceMap.put("Texture(纹理表)", "用于存储空间实体对象的纹理信息");
|
introduceMap.put("TextureVertice(纹理顶点表)", "记录空间实体对象的纹理顶点坐标值");
|
introduceMap.put("Image(图片数据表)", "存储空间实体对象的纹理或挂接的人工模型所应用的图片数据");
|
introduceMap.put("Template(几何模板表)", "存储空间实体对象的几何模板");
|
introduceMap.put("ExtensionSchema(扩展表)", "描述领域本体的扩展属性和扩展信息");
|
// 新增表
|
String dynzamizers = "1、动态数据存储在DYNZAMIZERS表中,其中:" + "url:数据url" + "data:zarr数据,使用的是zarr的压缩存储格式。详见zarr的zipstore。" + "gmlId:与实体对象相关联字段(使用ENTITY表(实体表)中的UUID相关联)" +
|
"" + "zarr数据结构示例:" + "Grid相关的zarr:" + "/" + "|——depth (n,height,width) " + "|——time(n)" + "" + "time存储时间序列" + "depth存储水深相关信息,三维数组,第一维为时间 与time相对应" +
|
"数组长度n代表时间切片的个数" + "height,width代表栅格的长和宽" + "降雨量相关zarr:" + "/" + "|——rainfall(n)" + "|——time(n)" + "" + "time存储时间序列" + "rainfall 存储降雨量相关信息,一维数组,与time相对应" +
|
"数组长度n代表时间切片的个数" + "" + "" + "2、terrain的存储方式:" + "类型为”+Terrain“" +
|
"Entity中几何存储地形的外包框,使用纹理贴图存储地形tif转出的png图片。";
|
introduceMap.put("DYNZAMIZERS(新增:动态数据存储)", dynzamizers);
|
//return dynzamizers.getBytes(StandardCharsets.UTF_8);
|
return introduceMap;
|
}
|
|
@Override
|
public Object createSimuBySemFile() {
|
return null;
|
}
|
|
@Override
|
public Object readSemFile(String filePath) {
|
// 文件地址
|
log.info("filePath:{}", filePath);
|
// 处理文件
|
JSONObject result = new JSONObject();
|
try {
|
// 测试连接SQLite数据库
|
Connection connection = connectToSQLiteWithCopy(filePath);
|
System.out.println("SQLite数据库连接成功!");
|
Statement stmt = connection.createStatement();
|
// 查询ENTITY表的数据并返回JSON格式的结果
|
// result = queryEntityTable(stmt);
|
result = queryDynamizersTable(stmt);
|
// 关闭连接
|
connection.close();
|
return result;
|
} catch (SQLException | IOException e) {
|
System.err.println("操作失败: " + e.getMessage());
|
return e.getMessage();
|
}
|
}
|
|
|
/**
|
* 根据传入的文件路径,添加后缀 `.db` 并连接 SQLite 数据库。
|
*
|
* @param filePath 文件路径
|
* @return SQLite数据库的连接
|
* @throws SQLException 如果SQLite连接失败
|
*/
|
public static Connection connectToSQLite(String filePath) throws SQLException {
|
// 检查文件路径是否为空
|
if (filePath == null || filePath.trim().isEmpty()) {
|
throw new IllegalArgumentException("文件路径不能为空");
|
}
|
|
// 检查文件是否已经有.db后缀,没有则添加
|
if (!filePath.endsWith(".db")) {
|
filePath = filePath + ".db";
|
}
|
log.info("Connecting to SQLite database: " + filePath);
|
|
// 创建文件对象
|
File dbFile = new File(filePath);
|
|
// 如果文件不存在,则创建一个新文件
|
if (!dbFile.exists()) {
|
log.info("文件不存在,请检查文件位置是否正确...");
|
return null;
|
// try {
|
// // 通过调用 createNewFile() 方法创建新文件
|
// boolean created = dbFile.createNewFile();
|
// if (!created) {
|
// throw new SQLException("无法创建数据库文件");
|
// }
|
// } catch (Exception e) {
|
// throw new SQLException("创建数据库文件时出错: " + e.getMessage(), e);
|
// }
|
}
|
|
// 使用 SQLite JDBC 连接字符串连接数据库
|
String url = "jdbc:sqlite:" + dbFile.getAbsolutePath();
|
log.info("连接到SQLite数据库: {}", url);
|
|
// 创建并返回数据库连接
|
return DriverManager.getConnection(url);
|
}
|
|
/**
|
* 根据传入的文件路径,复制文件并给复制的文件添加后缀 `.db`,然后连接 SQLite 数据库。
|
*
|
* @param filePath 原始文件路径
|
* @return SQLite数据库的连接
|
* @throws SQLException 如果SQLite连接失败
|
* @throws IOException 如果文件复制失败
|
*/
|
public static Connection connectToSQLiteWithCopy(String filePath) throws SQLException, IOException {
|
// 检查文件路径是否为空
|
if (filePath == null || filePath.trim().isEmpty()) {
|
throw new IllegalArgumentException("文件路径不能为空");
|
}
|
// 创建原始文件对象
|
File originalFile = new File(filePath);
|
// 检查原文件是否存在
|
if (!originalFile.exists()) {
|
throw new FileNotFoundException("原始文件不存在:" + filePath);
|
}
|
// 获取当前时间戳作为文件名的一部分
|
String timestamp = String.valueOf(System.currentTimeMillis());
|
// 创建一个新的文件名,添加一个随机后缀以避免文件名冲突
|
String newFilePath = filePath + "." + timestamp + ".db";
|
// 复制文件到新的路径
|
copyFile(originalFile, new File(newFilePath));
|
// 使用 SQLite JDBC 连接字符串连接新的数据库文件
|
String url = "jdbc:sqlite:" + newFilePath;
|
log.info("连接到SQLite数据库: {}", url);
|
// 返回SQLite数据库连接
|
return DriverManager.getConnection(url);
|
}
|
|
|
/**
|
* 复制文件到新的位置
|
*
|
* @param sourceFile 原始文件
|
* @param destFile 目标文件
|
* @throws IOException 如果复制过程中发生错误
|
*/
|
private static void copyFile(File sourceFile, File destFile) throws IOException {
|
// 使用NIO的Files.copy方法进行高效的文件复制
|
Path sourcePath = sourceFile.toPath();
|
Path destinationPath = destFile.toPath();
|
|
// 复制文件并覆盖目标文件
|
Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING);
|
log.info("文件已复制到:" + destinationPath.toString());
|
}
|
|
|
/**
|
* 查询ENTITY表的数据并返回JSON格式的数据
|
*
|
* @param stmt SQLite数据库连接
|
* @return JSON格式的查询结果
|
* @throws SQLException 如果查询过程中发生错误
|
*/
|
public static JSONObject queryEntityTable(Statement stmt) throws SQLException {
|
// 构建SQL查询语句
|
String querySql = "SELECT ID,DATA,SCHEMA,UUID FROM ENTITY";
|
// 执行查询并返回结果
|
try (ResultSet rs = stmt.executeQuery(querySql)) {
|
// 创建一个 JSON 数组用于存储多条记录
|
JSONArray jsonArray = new JSONArray();
|
// 将查询结果转化为JSON数组
|
JSONObject resJsonObject = new JSONObject();
|
// 遍历查询结果
|
while (rs.next()) {
|
JSONObject jsonObject = new JSONObject();
|
jsonObject.put("ID", rs.getInt("ID"));
|
String data = rs.getString("DATA");
|
// 将DATA字段进行反序列化
|
jsonObject.put("DATA", JSON.parse(data));
|
jsonObject.put("SCHEMA", rs.getInt("SCHEMA"));
|
jsonObject.put("UUID", rs.getString("UUID"));
|
// 将每一行的结果添加到JSON数组
|
jsonArray.add(jsonObject);
|
}
|
resJsonObject.put("entity", jsonArray);
|
return resJsonObject;
|
}
|
}
|
|
/**
|
* 查询DYNAMIZERS表的数据并返回JSON格式的数据
|
* 对于BLOB字段,转换为Base64字符串
|
*
|
* @param stmt SQL语句执行对象
|
* @return JSON格式的查询结果
|
* @throws SQLException 如果查询过程中发生错误
|
*/
|
public JSONObject queryDynamizersTable(Statement stmt) throws SQLException {
|
// 构建SQL查询语句
|
String querySql = "SELECT URL, GMLID, DATA FROM DYNAMIZERS";
|
// 创建一个 JSON 对象用于存储结果
|
JSONObject resultJson = new JSONObject();
|
// 创建一个 JSON 数组用于存储多条记录
|
JSONArray jsonArray = new JSONArray();
|
// 执行查询并返回结果
|
try (ResultSet rs = stmt.executeQuery(querySql)) {
|
// 遍历查询结果
|
while (rs.next()) {
|
JSONObject jsonObject = new JSONObject();
|
jsonObject.put("URL", rs.getString("URL"));
|
jsonObject.put("GMLID", rs.getString("GMLID"));
|
// 获取 BLOB 数据并将其转换为 Base64 编码字符串
|
byte[] blobData = rs.getBytes("DATA");
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
String dirpath = outPath + "\\" + formatter.format(LocalDateTime.now());
|
String filepath = outPath + "\\" + formatter.format(LocalDateTime.now()) + "\\" + rs.getString("URL");
|
try {
|
File file = new File(dirpath);
|
if (!file.exists()) {
|
file.mkdirs();
|
}
|
File resultFile = new File(filepath);
|
resultFile.createNewFile();
|
try (FileOutputStream fos = new FileOutputStream(filepath)) {
|
fos.write(blobData);
|
ZipUtils.unzip(filepath,dirpath);
|
System.out.println("Bytes written to file successfully.");
|
resultFile.delete();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
jsonObject.put("DATA", filepath);
|
jsonArray.add(jsonObject);
|
}
|
// 将查询结果放入最终的 JSON 对象中
|
resultJson.put("dynamizers", jsonArray);
|
}
|
return resultJson;
|
}
|
|
/**
|
* 使用分页 Query Entity Table
|
* // 假设每页查询1000条数据,查询第2页的数据
|
* // JSONArray result = queryEntityTableWithPagination(stmt, 1000, 2);
|
*
|
* @param stmt STMT
|
* @param pageSize
|
* @param pageNumber 页码
|
* @return {@link JSONArray}
|
* @throws SQLException sql异常
|
*/
|
public static JSONArray queryEntityTableWithPagination(Statement stmt, int pageSize, int pageNumber) throws SQLException {
|
// 计算查询的偏移量
|
int offset = (pageNumber - 1) * pageSize;
|
|
// 构建SQL查询语句,使用LIMIT和OFFSET进行分页
|
String querySql = "SELECT * FROM ENTITY LIMIT " + pageSize + " OFFSET " + offset;
|
|
try (ResultSet rs = stmt.executeQuery(querySql)) {
|
JSONArray jsonArray = new JSONArray();
|
|
// 遍历查询结果
|
while (rs.next()) {
|
JSONObject jsonObject = new JSONObject();
|
jsonObject.put("ID", rs.getInt("ID"));
|
jsonObject.put("DATA", rs.getString("DATA"));
|
jsonObject.put("SCHEMA", rs.getString("SCHEMA"));
|
jsonObject.put("UUID", rs.getString("UUID"));
|
|
jsonArray.add(jsonObject);
|
}
|
|
return jsonArray;
|
}
|
}
|
|
|
// public static void main(String[] args) {
|
// try {
|
// // 测试连接SQLite数据库
|
// Connection connection = connectToSQLiteWithCopy("D:\\0a_project\\simulation\\other\\1211SEM样例\\管点.sem");
|
// System.out.println("SQLite数据库连接成功!");
|
// // 关闭连接
|
// connection.close();
|
// } catch (SQLException | IOException e) {
|
// System.err.println("操作失败: " + e.getMessage());
|
// }
|
// }
|
|
/**
|
* 创建数据库连接
|
*/
|
private static Connection getConnection(String sqliteDbPath) throws SQLException {
|
// 创建SQLite数据库连接
|
Connection conn = DriverManager.getConnection("jdbc:sqlite:" + sqliteDbPath);
|
Statement stmt = conn.createStatement();
|
|
// 关闭数据库连接
|
//conn.close();
|
return conn;
|
}
|
|
|
}
|