模型库

This commit is contained in:
ZZX9599
2025-09-22 17:13:22 +08:00
parent adf375648b
commit 521efbafac
40 changed files with 1177 additions and 523 deletions

View File

@ -11,9 +11,6 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ApiResponse handleException(Exception e) {
if (!e.getMessage().contains("No static resource")) {
log.error("全局异常处理:{}", e.getMessage());
}
return ApiResponse.failure(e.getMessage());
}

View File

@ -23,10 +23,10 @@ public class SaTokenConfig implements WebMvcConfigurer {
excludePathPatterns.add("/v3/api-docs/**");
excludePathPatterns.add("/fileInfo/download/**");
excludePathPatterns.add("/fileInfo/preview/**");
excludePathPatterns.add("/fileInfo/previewLocal/**");
excludePathPatterns.add("/data/clt/**");
excludePathPatterns.add("/data/mbtiles/**");
excludePathPatterns.add("/data/pak/**");
excludePathPatterns.add("/**");
// 注册 Sa-Token 拦截器
registry.addInterceptor(new SaInterceptor(handle -> {

View File

@ -44,7 +44,6 @@ public class ServerInitService {
public void checkDefaultData() {
checkDefaultUserAndRole();
checkDefaultSource();
}
public void checkDefaultUserAndRole() {
@ -73,98 +72,4 @@ public class ServerInitService {
userService.save(user);
}
}
public void checkDefaultSource() {
if(sourceService.count() == 0) {
// 查询管理员角色
Role adminRole = roleService.getOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleName, "管理员"));
log.info("初始化默认资源数据");
Source source1 = new Source();
source1.setId(UUID.fastUUID().toString(true));
source1.setSourceName("倾斜模型");
source1.setSourceType("directory");
source1.setTreeIndex(0);
source1.setIsShow(1);
sourceService.save(source1);
roleSourceService.addRoleSource(adminRole.getId(), source1.getId());
Source source2 = new Source();
source2.setId(UUID.fastUUID().toString(true));
source2.setSourceName("人工模型");
source2.setSourceType("directory");
source2.setTreeIndex(0);
source2.setIsShow(1);
sourceService.save(source2);
roleSourceService.addRoleSource(adminRole.getId(), source2.getId());
Source source3 = new Source();
source3.setId(UUID.fastUUID().toString(true));
source3.setSourceName("卫星底图");
source3.setSourceType("directory");
source3.setTreeIndex(0);
source3.setIsShow(1);
sourceService.save(source3);
roleSourceService.addRoleSource(adminRole.getId(), source3.getId());
Source source4 = new Source();
source4.setId(UUID.fastUUID().toString(true));
source4.setSourceName("地形");
source4.setSourceType("directory");
source4.setTreeIndex(0);
source4.setIsShow(1);
sourceService.save(source4);
roleSourceService.addRoleSource(adminRole.getId(), source4.getId());
Source source5 = new Source();
source5.setId(UUID.fastUUID().toString(true));
source5.setSourceName("在线图源");
source5.setSourceType("directory");
source5.setTreeIndex(0);
source5.setIsShow(1);
sourceService.save(source5);
roleSourceService.addRoleSource(adminRole.getId(), source5.getId());
Source source6 = new Source();
source6.setId(UUID.fastUUID().toString(true));
source6.setSourceName("卫星图");
source6.setSourceType("arcgisWximagery");
source6.setParentId(source5.getId());
source6.setTreeIndex(0);
source6.setIsShow(1);
sourceService.save(source6);
roleSourceService.addRoleSource(adminRole.getId(), source6.getId());
Source source7 = new Source();
source7.setId(UUID.fastUUID().toString(true));
source7.setSourceName("暗黑地图");
source7.setSourceType("arcgisBlueImagery");
source7.setParentId(source5.getId());
source7.setTreeIndex(0);
source7.setIsShow(1);
sourceService.save(source7);
roleSourceService.addRoleSource(adminRole.getId(), source7.getId());
Source source8 = new Source();
source8.setId(UUID.fastUUID().toString(true));
source8.setSourceName("路网图");
source8.setSourceType("gdlwImagery");
source8.setParentId(source5.getId());
source8.setTreeIndex(0);
source8.setIsShow(1);
sourceService.save(source8);
roleSourceService.addRoleSource(adminRole.getId(), source8.getId());
Source source9 = new Source();
source9.setId(UUID.fastUUID().toString(true));
source9.setSourceName("矢量图");
source9.setSourceType("gdslImagery");
source9.setParentId(source5.getId());
source9.setTreeIndex(0);
source9.setIsShow(1);
sourceService.save(source9);
roleSourceService.addRoleSource(adminRole.getId(), source9.getId());
}
}
}

View File

@ -34,7 +34,7 @@ public class CodeUtil {
}
// 传入需要生成代码的表名
Generation("model");
Generation("business_config");
}
public static void Generation(String... tableName) {

View File

@ -0,0 +1,28 @@
package com.yj.earth.common.util;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileUtil {
/**
* 将本地文件转换为 MultipartFile
*/
public static MultipartFile convertToMultipartFile(File file) {
try (FileInputStream inputStream = new FileInputStream(file)) {
return new MockMultipartFile(
"files",
file.getName(),
MediaType.APPLICATION_OCTET_STREAM_VALUE,
inputStream
);
} catch (IOException e) {
return null;
}
}
}

View File

@ -47,4 +47,43 @@ public class JsonUtil {
return new HashMap<>(0);
}
}
/**
* 将 JSON 字符串转换为指定类型的对象
*/
public static <T> T jsonToObject(String json, Class<T> clazz) {
if (json == null || json.trim().isEmpty()) {
return null;
}
return objectMapper.convertValue(json, clazz);
}
/**
* 将 Map 转换为指定类型的对象
*/
public static <T> T mapToObject(Map<String, Object> map, Class<T> clazz) {
if (map == null || clazz == null) {
return null;
}
try {
// 使用ObjectMapper将Map转换为指定类型对象
return objectMapper.convertValue(map, clazz);
} catch (IllegalArgumentException e) {
log.error("Map转对象失败、目标类型: {}, Map内容: {}", clazz.getName(), map, e);
return null;
}
}
/**
* 将任意 Object 转化为 JSON
*/
public static String toJson(Object obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
log.error("对象转JSON失败", e);
return null;
}
}
}

View File

@ -0,0 +1,334 @@
package com.yj.earth.common.util;
import java.sql.*;
import java.util.*;
import java.lang.reflect.*;
import java.util.Date;
import java.time.LocalDateTime; // 新增导入
import java.time.format.DateTimeFormatter; // 新增导入
import java.time.format.DateTimeParseException; // 新增导入
public class SQLiteUtil {
// 加载 SQLite JDBC 驱动
static {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
throw new RuntimeException("无法加载SQLite JDBC驱动", e);
}
}
// 统一日期格式匹配数据库TEXT字段存储的格式yyyy-MM-dd'T'HH:mm:ss.SSS
private static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
/**
* 根据数据库文件绝对路径获取连接
*/
public static Connection getConnection(String dbFilePath) throws SQLException {
String url = "jdbc:sqlite:" + dbFilePath;
return DriverManager.getConnection(url);
}
/**
* 执行查询并返回单个对象
*/
public static <T> T queryForObject(String dbFilePath, String sql, List<Object> params, Class<T> clazz) throws SQLException, IllegalAccessException, InstantiationException {
List<T> results = queryForList(dbFilePath, sql, params, clazz);
return results.isEmpty() ? null : results.get(0);
}
/**
* 执行查询并返回对象列表
*/
public static <T> List<T> queryForList(String dbFilePath, String sql, List<Object> params, Class<T> clazz)
throws SQLException, IllegalAccessException, InstantiationException {
List<T> resultList = new ArrayList<>();
// 使用try-with-resources确保资源自动关闭
try (Connection conn = getConnection(dbFilePath);
PreparedStatement pstmt = createPreparedStatement(conn, sql, params)) {
// 执行查询
try (ResultSet rs = pstmt.executeQuery()) {
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
// 处理结果集
while (rs.next()) {
T obj = clazz.newInstance();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnName(i);
Object value = rs.getObject(i);
// 设置对象属性(自动处理类型转换)
setFieldValue(obj, columnName, value);
}
resultList.add(obj);
}
}
}
return resultList;
}
/**
* 执行增删改SQL语句
*/
public static int executeUpdate(String dbFilePath, String sql, List<Object> params) throws SQLException {
try (Connection conn = getConnection(dbFilePath);
PreparedStatement pstmt = createPreparedStatement(conn, sql, params)) {
return pstmt.executeUpdate();
}
}
/**
* 创建并设置参数化的PreparedStatement关键处理LocalDateTime转String
*/
private static PreparedStatement createPreparedStatement(Connection conn, String sql, List<Object> params)
throws SQLException {
PreparedStatement pstmt = conn.prepareStatement(sql);
if (params != null && !params.isEmpty()) {
int index = 1;
for (Object value : params) {
// 新增LocalDateTime类型转为String、适配SQLite的TEXT字段
if (value instanceof LocalDateTime) {
String dateStr = ((LocalDateTime) value).format(LOCAL_DATE_TIME_FORMATTER);
pstmt.setObject(index++, dateStr);
}
// 新增byte[]类型显式指定为BLOB避免SQLite自动转换异常
else if (value instanceof byte[]) {
pstmt.setBytes(index++, (byte[]) value);
} else {
pstmt.setObject(index++, value);
}
}
}
return pstmt;
}
/**
* 通过反射设置对象的字段值
*/
private static void setFieldValue(Object obj, String columnName, Object value) {
try {
Field field = findField(obj.getClass(), columnName);
if (field != null) {
field.setAccessible(true);
Object convertedValue = convertValue(field.getType(), value);
field.set(obj, convertedValue);
}
} catch (IllegalAccessException e) {
System.err.println("警告: 无法设置字段 " + columnName + " 的值 - " + e.getMessage());
}
}
/**
* 查找字段、支持下划线命名转驼峰命名如created_at → createdAt
*/
private static Field findField(Class<?> clazz, String columnName) {
// 1. 直接匹配字段名(如数据库列名与字段名一致)
try {
return clazz.getDeclaredField(columnName);
} catch (NoSuchFieldException e) {
// 2. 下划线转驼峰后匹配如created_at → createdAt
String camelCaseName = underscoreToCamelCase(columnName);
try {
return clazz.getDeclaredField(camelCaseName);
} catch (NoSuchFieldException e1) {
// 3. 递归查找父类(支持继承场景)
if (clazz.getSuperclass() != null) {
return findField(clazz.getSuperclass(), columnName);
}
return null;
}
}
}
/**
* 下划线命名转驼峰命名(工具方法)
*/
private static String underscoreToCamelCase(String str) {
if (str == null || str.isEmpty()) {
return str;
}
StringBuilder sb = new StringBuilder();
boolean nextUpperCase = false;
for (char c : str.toCharArray()) {
if (c == '_') {
nextUpperCase = true;
} else {
if (nextUpperCase) {
sb.append(Character.toUpperCase(c));
nextUpperCase = false;
} else {
// 修正首字母小写如CREATED_AT → createdAt、而非CreatedAt
sb.append(Character.toLowerCase(c));
}
}
}
return sb.toString();
}
/**
* 核心类型转换新增LocalDateTime解析、优化BLOB适配
*/
private static Object convertValue(Class<?> targetType, Object value) {
if (value == null) {
return null;
}
// 类型已匹配、直接返回
if (targetType.isInstance(value)) {
return value;
}
// 1. 数字类型转换int/long/double等
if (targetType == Integer.class || targetType == int.class) {
return ((Number) value).intValue();
} else if (targetType == Long.class || targetType == long.class) {
return ((Number) value).longValue();
} else if (targetType == Double.class || targetType == double.class) {
return ((Number) value).doubleValue();
} else if (targetType == Float.class || targetType == float.class) {
return ((Number) value).floatValue();
}
// 2. 布尔类型转换(支持数字/字符串转布尔)
else if (targetType == Boolean.class || targetType == boolean.class) {
if (value instanceof Number) {
return ((Number) value).intValue() != 0;
} else if (value instanceof String) {
return "true".equalsIgnoreCase((String) value);
}
}
// 3. 字符串类型转换所有类型转String
else if (targetType == String.class) {
return value.toString();
}
// 4. 日期类型转换java.util.Date
else if (targetType == Date.class) {
if (value instanceof Timestamp) {
return new Date(((Timestamp) value).getTime());
} else if (value instanceof LocalDateTime) {
// 支持LocalDateTime转Date如需
return Date.from(((LocalDateTime) value).atZone(java.time.ZoneId.systemDefault()).toInstant());
}
}
// 5. 新增LocalDateTime类型转换SQLite TEXT → Java LocalDateTime
else if (targetType == LocalDateTime.class) {
if (value instanceof String) {
try {
// 解析数据库存储的ISO格式字符串如"2025-09-18T17:30:27.143"
return LocalDateTime.parse((String) value, LOCAL_DATE_TIME_FORMATTER);
} catch (DateTimeParseException e) {
System.err.println("警告: 日期解析失败、字符串=" + value + "、格式应为yyyy-MM-dd'T'HH:mm:ss.SSS - " + e.getMessage());
return null;
}
} else if (value instanceof Timestamp) {
// 兼容Timestamp类型如其他数据库迁移场景
return ((Timestamp) value).toLocalDateTime();
}
}
// 6. 新增byte[]类型转换SQLite BLOB → Java byte[]
else if (targetType == byte[].class && value instanceof Blob) {
Blob blob = (Blob) value;
try {
return blob.getBytes(1, (int) blob.length());
} catch (SQLException e) {
System.err.println("警告: BLOB转byte[]失败 - " + e.getMessage());
return null;
}
}
// 无法转换时返回原始值(避免崩溃、打印警告)
System.err.println("警告: 不支持的类型转换、目标类型=" + targetType.getName() + "、原始值类型=" + value.getClass().getName());
return value;
}
/**
* 执行DDL语句CREATE, ALTER, DROP等
*/
private static void executeDDL(String dbFilePath, String sql, List<Object> params) throws SQLException {
try (Connection conn = getConnection(dbFilePath);
PreparedStatement pstmt = createPreparedStatement(conn, sql, params)) {
pstmt.execute();
}
}
/**
* 执行无参数的DDL语句
*/
public static void executeDDL(String dbFilePath, String sql) {
try {
executeDDL(dbFilePath, sql, null);
} catch (SQLException e) {
throw new RuntimeException("执行DDL语句失败、SQL=" + sql, e);
}
}
/**
* 执行查询并返回count结果
*/
public static int queryForCount(String dbFilePath, String sql, List<Object> params) throws SQLException {
try (Connection conn = getConnection(dbFilePath);
PreparedStatement pstmt = createPreparedStatement(conn, sql, params);
ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
return rs.getInt(1);
}
return 0;
}
}
/**
* 执行无参数的查询并返回count结果
*/
public static int queryForCount(String dbFilePath, String sql) throws SQLException {
return queryForCount(dbFilePath, sql, null);
}
/**
* 初始化数据库表model_type + model
*/
public static void initialization(String modelPath) {
// 创建模型类型表
String sql = """
CREATE TABLE "model_type" (
"id" TEXT,
"name" TEXT,
"parent_id" TEXT,
"created_at" TEXT,
"updated_at" TEXT,
PRIMARY KEY ("id")
);
""";
executeDDL(modelPath, sql);
// 创建模型表
sql = """
CREATE TABLE "model" (
"id" TEXT,
"model_type_id" TEXT,
"model_name" TEXT,
"model_type" TEXT,
"poster_type" TEXT,
"poster" TEXT,
"data" TEXT,
"view" TEXT,
"created_at" TEXT,
"updated_at" TEXT,
PRIMARY KEY ("id")
);
""";
executeDDL(modelPath, sql);
}
}