From 521efbafaccf6eab119114694ef49a637ffe1a97 Mon Sep 17 00:00:00 2001 From: ZZX9599 <536509593@qq.com> Date: Mon, 22 Sep 2025 17:13:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 + .../java/com/yj/earth/aspect/AuthAspect.java | 4 +- .../java/com/yj/earth/auth/AuthGenerator.java | 4 + .../controller/FileInfoController.java | 165 +++------ .../business/controller/ModelController.java | 65 ---- .../controller/ModelTypeController.java | 12 - .../business/controller/SourceController.java | 82 +++-- .../TacticalCalculationController.java | 2 +- .../com/yj/earth/business/domain/Model.java | 39 +- .../yj/earth/business/domain/ModelType.java | 19 +- .../yj/earth/business/mapper/ModelMapper.java | 18 - .../business/mapper/ModelTypeMapper.java | 18 - .../business/service/FileInfoService.java | 8 + .../earth/business/service/ModelService.java | 16 - .../business/service/ModelTypeService.java | 16 - .../service/impl/FileInfoServiceImpl.java | 206 ++++++++++- .../service/impl/ModelServiceImpl.java | 20 -- .../service/impl/ModelTypeServiceImpl.java | 20 -- .../common/config/GlobalExceptionHandler.java | 3 - .../yj/earth/common/config/SaTokenConfig.java | 2 +- .../common/service/ServerInitService.java | 95 ----- .../com/yj/earth/common/util/CodeUtil.java | 2 +- .../com/yj/earth/common/util/FileUtil.java | 28 ++ .../com/yj/earth/common/util/JsonUtil.java | 39 ++ .../com/yj/earth/common/util/SQLiteUtil.java | 334 ++++++++++++++++++ .../yj/earth/datasource/DatabaseManager.java | 6 +- .../com/yj/earth/design/BusinessConfig.java | 24 ++ .../com/yj/earth/design/ModelLibrary.java | 22 ++ .../businessConfig/AddBusinessConfigDto.java | 13 + .../yj/earth/dto/model/AddModelTypeDto.java | 12 + ...ileDto.java => CreateModelLibraryDto.java} | 6 +- .../java/com/yj/earth/params/LinkImage.java | 134 +++++++ src/main/java/com/yj/earth/params/Point.java | 18 + .../java/com/yj/earth/params/Terrain.java | 12 + .../java/com/yj/earth/params/VrImage.java | 134 +++++++ .../java/com/yj/earth/vo/ModelTypeVo.java | 40 +++ src/main/java/com/yj/earth/vo/ModelVo.java | 9 + src/main/resources/application.yml | 4 - src/main/resources/mapper/ModelMapper.xml | 24 -- src/main/resources/mapper/ModelTypeMapper.xml | 19 - 40 files changed, 1177 insertions(+), 523 deletions(-) delete mode 100644 src/main/java/com/yj/earth/business/controller/ModelController.java delete mode 100644 src/main/java/com/yj/earth/business/controller/ModelTypeController.java delete mode 100644 src/main/java/com/yj/earth/business/mapper/ModelMapper.java delete mode 100644 src/main/java/com/yj/earth/business/mapper/ModelTypeMapper.java delete mode 100644 src/main/java/com/yj/earth/business/service/ModelService.java delete mode 100644 src/main/java/com/yj/earth/business/service/ModelTypeService.java delete mode 100644 src/main/java/com/yj/earth/business/service/impl/ModelServiceImpl.java delete mode 100644 src/main/java/com/yj/earth/business/service/impl/ModelTypeServiceImpl.java create mode 100644 src/main/java/com/yj/earth/common/util/FileUtil.java create mode 100644 src/main/java/com/yj/earth/common/util/SQLiteUtil.java create mode 100644 src/main/java/com/yj/earth/design/BusinessConfig.java create mode 100644 src/main/java/com/yj/earth/design/ModelLibrary.java create mode 100644 src/main/java/com/yj/earth/dto/businessConfig/AddBusinessConfigDto.java create mode 100644 src/main/java/com/yj/earth/dto/model/AddModelTypeDto.java rename src/main/java/com/yj/earth/dto/model/{CreateModelFileDto.java => CreateModelLibraryDto.java} (68%) create mode 100644 src/main/java/com/yj/earth/params/LinkImage.java create mode 100644 src/main/java/com/yj/earth/params/Terrain.java create mode 100644 src/main/java/com/yj/earth/params/VrImage.java create mode 100644 src/main/java/com/yj/earth/vo/ModelTypeVo.java create mode 100644 src/main/java/com/yj/earth/vo/ModelVo.java delete mode 100644 src/main/resources/mapper/ModelMapper.xml delete mode 100644 src/main/resources/mapper/ModelTypeMapper.xml diff --git a/pom.xml b/pom.xml index 1ea7803..18c2c19 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,12 @@ spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + + com.baomidou diff --git a/src/main/java/com/yj/earth/aspect/AuthAspect.java b/src/main/java/com/yj/earth/aspect/AuthAspect.java index d459f6f..72765c3 100644 --- a/src/main/java/com/yj/earth/aspect/AuthAspect.java +++ b/src/main/java/com/yj/earth/aspect/AuthAspect.java @@ -61,13 +61,13 @@ public class AuthAspect { } } - // 授权有效,继续执行原方法 + // 授权有效、继续执行原方法 return point.proceed(); } /** * 读取授权文件内容 - * @return 授权文件内容,如果文件不存在或读取失败则返回null + * @return 授权文件内容、如果文件不存在或读取失败则返回null */ private String readLicenseFile() { try { diff --git a/src/main/java/com/yj/earth/auth/AuthGenerator.java b/src/main/java/com/yj/earth/auth/AuthGenerator.java index 5539d81..2260890 100644 --- a/src/main/java/com/yj/earth/auth/AuthGenerator.java +++ b/src/main/java/com/yj/earth/auth/AuthGenerator.java @@ -70,4 +70,8 @@ public class AuthGenerator { throw new RuntimeException("授权信息加密失败", e); } } + + public static void main(String[] args) { + System.out.println(generateAuth("标准版", 1000, 30, "DAC653349FD15F1E6DB2F9322AD628F4")); + } } diff --git a/src/main/java/com/yj/earth/business/controller/FileInfoController.java b/src/main/java/com/yj/earth/business/controller/FileInfoController.java index 546ef9a..b4e3df6 100644 --- a/src/main/java/com/yj/earth/business/controller/FileInfoController.java +++ b/src/main/java/com/yj/earth/business/controller/FileInfoController.java @@ -4,17 +4,22 @@ import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.IdUtil; import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageProcessingException; +import com.drew.lang.Rational; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import java.io.*; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import cn.hutool.crypto.digest.DigestUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.drew.metadata.MetadataException; +import com.drew.metadata.exif.GpsDirectory; import com.yj.earth.business.domain.FileInfo; import com.yj.earth.business.service.FileInfoService; import com.yj.earth.common.util.ApiResponse; @@ -46,41 +51,22 @@ public class FileInfoController { @Resource private FileInfoService fileInfoService; - @Value("${file.upload.path}") - private String uploadPath; - - // 获取项目根目录 - private String getProjectRootPath() { - return System.getProperty("user.dir"); - } - - // 获取完整的上传目录路径 - private String getFullUploadPath() { - // 拼接项目根目录和配置的上传路径 - return getProjectRootPath() + File.separator + uploadPath; - } - @Operation(summary = "文件上传") @PostMapping("/upload") public ApiResponse uploadFiles(@Parameter(description = "上传的文件数组", required = true) @RequestParam("files") MultipartFile[] files) throws IOException { - // 校验文件数组是否为空 if (files == null || files.length == 0) { return ApiResponse.failure("上传文件不能为空"); } - // 获取完整的上传目录路径 - String fullUploadPath = getFullUploadPath(); - + String fullUploadPath = fileInfoService.getFullUploadPath(); List fileInfoVoList = new ArrayList<>(); - // 遍历处理每个文件 for (MultipartFile file : files) { // 跳过空文件 if (file.isEmpty()) { continue; } - // 获取原始文件名和后缀 String originalFilename = file.getOriginalFilename(); String fileSuffix = FileUtil.extName(originalFilename); @@ -106,7 +92,7 @@ public class FileInfoController { // 查询有没有文件名一样并且 MD5 也一样的数据 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(FileInfo::getFileName, originalFilename).eq(FileInfo::getFileMd5, fileMd5); - if (fileInfoService.count(queryWrapper) > 0) { // 修复了此处的bug、添加了queryWrapper参数 + if (fileInfoService.count(queryWrapper) > 0) { return ApiResponse.failure("已存在文件名相同且内容完全一致的文件"); } @@ -116,7 +102,7 @@ public class FileInfoController { fileInfo.setFileSuffix(fileSuffix); fileInfo.setContentType(contentType); fileInfo.setFileSize(file.getSize()); - fileInfo.setFilePath(uniqueFileName); // 只保存相对文件名、不保存完整路径 + fileInfo.setFilePath(uniqueFileName); fileInfo.setFileMd5(fileMd5); // 保存文件信息并获取ID @@ -152,7 +138,7 @@ public class FileInfoController { } // 构建完整文件路径 - String fullPath = getFullUploadPath() + File.separator + fileInfo.getFilePath(); + String fullPath = fileInfoService.getFullUploadPath() + File.separator + fileInfo.getFilePath(); File file = new File(fullPath); // 校验文件是否存在 @@ -185,7 +171,7 @@ public class FileInfoController { } // 构建完整文件路径 - String fullPath = getFullUploadPath() + File.separator + fileInfo.getFilePath(); + String fullPath = fileInfoService.getFullUploadPath() + File.separator + fileInfo.getFilePath(); File file = new File(fullPath); // 校验文件是否存在 @@ -204,100 +190,59 @@ public class FileInfoController { } } - public String handleLocationImageUpload(MultipartFile file) { + @Operation(summary = "本地文件预览") + @GetMapping("/previewLocal") + public void previewLocalFile(@Parameter(description = "本地文件绝对路径") @RequestParam String fileAbsolutePath, HttpServletResponse response) { + Path targetFilePath = null; try { - // 校验文件是否为空 - if (file.isEmpty()) { - throw new IllegalArgumentException("上传文件不能为空"); - } - // 获取文件基本信息 - String originalFilename = file.getOriginalFilename(); - String fileSuffix = FileUtil.extName(originalFilename); - String contentType = file.getContentType(); - // 验证是否为图片文件 - if (contentType == null || !contentType.startsWith("image/")) { - throw new IllegalArgumentException("请上传图片文件"); - } - // 获取完整的上传目录路径 - Path fullUploadPath = Paths.get(getFullUploadPath()); - // 生成唯一文件名 - String uniqueFileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + fileSuffix; - // 创建文件存储目录 - Files.createDirectories(fullUploadPath); - // 构建完整文件路径并保存文件 - Path destFilePath = fullUploadPath.resolve(uniqueFileName); - // 先将文件保存到目标位置 - file.transferTo(destFilePath); - // 计算文件MD5(使用已保存的文件) - String fileMd5 = calculateFileMd5(destFilePath.toFile()); - // 检查文件是否已存在 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(FileInfo::getFileName, originalFilename) - .eq(FileInfo::getFileMd5, fileMd5); - if (fileInfoService.count(queryWrapper) > 0) { - throw new IllegalStateException("已存在相同的图片文件"); - } - // 提取图片元数据(使用已保存的文件,避免使用临时文件) - Map metadata; - try (InputStream is = Files.newInputStream(destFilePath)) { - metadata = extractImageMetadata(is); - } - // 保存文件信息到数据库 - FileInfo fileInfo = new FileInfo(); - fileInfo.setFileName(originalFilename); - fileInfo.setFileSuffix(fileSuffix); - fileInfo.setContentType(contentType); - fileInfo.setFileSize(file.getSize()); - fileInfo.setFilePath(uniqueFileName); - fileInfo.setFileMd5(fileMd5); - fileInfoService.save(fileInfo); - // 构建并返回结果 - Map result = new HashMap<>(); - result.put("previewUrl", "/fileInfo/preview/" + fileInfo.getId()); - result.put("downloadUrl", "/fileInfo/download/" + fileInfo.getId()); - result.put("metadata", metadata); - return JsonUtil.mapToJson(result); - } catch (IOException e) { - throw new RuntimeException("文件上传失败: " + e.getMessage(), e); - } - } + // 标准化路径 + targetFilePath = Paths.get(fileAbsolutePath).toRealPath(); - /** - * 计算文件的 MD5 - */ - private String calculateFileMd5(File file) throws IOException { - try (InputStream is = new FileInputStream(file)) { - return DigestUtils.md5DigestAsHex(is); - } - } + // 校验文件合法性:是否存在、是否为普通文件 + BasicFileAttributes fileAttr = Files.readAttributes(targetFilePath, BasicFileAttributes.class); + if (!fileAttr.isRegularFile()) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + fileInfoService.writeResponseMessage(response, "目标路径不是有效的文件"); + return; + } - /** - * 提取图片的EXIF元数据(包括定位信息) - */ - private Map extractImageMetadata(InputStream inputStream) { - try { - Map result = new HashMap<>(); - Metadata metadata = ImageMetadataReader.readMetadata(inputStream); + // 设置预览响应头 + String fileName = targetFilePath.getFileName().toString(); + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()); + String contentType = Files.probeContentType(targetFilePath); - // 遍历所有元数据目录 - for (Directory directory : metadata.getDirectories()) { - String directoryName = directory.getName(); - Map directoryTags = new HashMap<>(); + // 对于文本类型文件、指定字符编码 + if (contentType != null && contentType.startsWith("text/")) { + response.setContentType(contentType + "; charset=UTF-8"); + } else { + response.setContentType(contentType != null ? contentType : "application/octet-stream"); + } - // 提取当前目录下的所有标签 - for (com.drew.metadata.Tag tag : directory.getTags()) { - directoryTags.put(tag.getTagName(), tag.getDescription()); - } - - // 存储当前目录的所有标签 - if (!directoryTags.isEmpty()) { - result.put(directoryName, directoryTags); + response.setContentLengthLong(fileAttr.size()); + // 关键修改:将attachment改为inline实现预览 + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, + "inline; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName); + + // 写入文件流 + try (InputStream inputStream = Files.newInputStream(targetFilePath); + OutputStream outputStream = response.getOutputStream()) { + byte[] buffer = new byte[1024 * 8]; + int len; + while ((len = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, len); } + outputStream.flush(); } - return result; - } catch (ImageProcessingException | IOException e) { - return Collections.emptyMap(); + } catch (NoSuchFileException e) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + fileInfoService.writeResponseMessage(response, "文件不存在:" + fileAbsolutePath); + } catch (SecurityException e) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + fileInfoService.writeResponseMessage(response, "访问拒绝:无权限读取该文件"); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + fileInfoService.writeResponseMessage(response, "预览失败:" + e.getMessage()); } } } diff --git a/src/main/java/com/yj/earth/business/controller/ModelController.java b/src/main/java/com/yj/earth/business/controller/ModelController.java deleted file mode 100644 index 5d2b07e..0000000 --- a/src/main/java/com/yj/earth/business/controller/ModelController.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.yj.earth.business.controller; - -import com.yj.earth.business.service.ModelService; -import com.yj.earth.business.service.ModelTypeService; -import com.yj.earth.common.util.ApiResponse; -import com.yj.earth.datasource.DatabaseManager; -import com.yj.earth.design.Model; -import com.yj.earth.design.ModelType; -import com.yj.earth.dto.model.CreateModelFileDto; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.tags.Tag; -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; - -import javax.annotation.Resource; -import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; - -@Tag(name = "模型相关") -@RestController -@RequestMapping("/model") -public class ModelController { - @Resource - private ModelService modelService; - @Resource - private ModelTypeService modelTypeService; - - @Operation(summary = "创建模型库") - @PostMapping("/createModelFile") - public ApiResponse createModelFile(@RequestBody CreateModelFileDto createModelFileDto) { - try { - // 获取参数并处理文件路径 - String folderPath = createModelFileDto.getFolderPath(); - String modelFileName = createModelFileDto.getModelFileName() + ".model"; - // 创建文件夹(如果不存在) - File folder = new File(folderPath); - if (!folder.exists()) { - boolean folderCreated = folder.mkdirs(); - if (!folderCreated) { - return ApiResponse.failure("无法创建文件夹: " + folderPath); - } - } - // 构建完整文件路径 - String filePath = folderPath + File.separator + modelFileName; - // 加载 SQLite 驱动并创建数据库文件 - Class.forName("org.sqlite.JDBC"); - // SQLite会自动创建不存在的数据库文件 - try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + filePath)) { - if (connection != null) { - // 初始化表结构 - DatabaseManager.createTablesForEntities(DatabaseManager.DatabaseType.SQLITE, ModelType.class, connection); - DatabaseManager.createTablesForEntities(DatabaseManager.DatabaseType.SQLITE, Model.class, connection); - return ApiResponse.success(null); - } - } - } catch (Exception e) { - return ApiResponse.failure("创建模型库失败: " + e.getMessage()); - } - return ApiResponse.failure("未知错误"); - } -} diff --git a/src/main/java/com/yj/earth/business/controller/ModelTypeController.java b/src/main/java/com/yj/earth/business/controller/ModelTypeController.java deleted file mode 100644 index a63cd88..0000000 --- a/src/main/java/com/yj/earth/business/controller/ModelTypeController.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.yj.earth.business.controller; - -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@Tag(name = "模型类型管理") -@RestController -@RequestMapping("/modelType") -public class ModelTypeController { - -} diff --git a/src/main/java/com/yj/earth/business/controller/SourceController.java b/src/main/java/com/yj/earth/business/controller/SourceController.java index 8caeeb6..ca862fc 100644 --- a/src/main/java/com/yj/earth/business/controller/SourceController.java +++ b/src/main/java/com/yj/earth/business/controller/SourceController.java @@ -2,20 +2,8 @@ package com.yj.earth.business.controller; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.io.FileUtil; -import cn.hutool.core.lang.UUID; -import cn.hutool.core.util.IdUtil; -import cn.hutool.crypto.digest.DigestUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.drew.imaging.ImageMetadataReader; -import com.drew.imaging.ImageProcessingException; -import com.drew.metadata.Directory; -import com.drew.metadata.Metadata; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.yj.earth.annotation.CheckAuth; -import com.yj.earth.business.domain.FileInfo; -import com.yj.earth.business.domain.Role; import com.yj.earth.business.domain.Source; import com.yj.earth.business.service.*; import com.yj.earth.common.service.SourceDataGenerator; @@ -24,6 +12,7 @@ import com.yj.earth.common.util.ApiResponse; import com.yj.earth.common.util.JsonUtil; import com.yj.earth.common.util.MapUtil; import com.yj.earth.dto.source.*; +import com.yj.earth.params.Point; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -34,9 +23,6 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; import java.util.*; import static com.yj.earth.common.constant.GlobalConstant.DIRECTORY; @@ -62,12 +48,6 @@ public class SourceController { @Resource private FileInfoService fileInfoService; - @Resource - private FileInfoController fileInfoControllerl; - - @Value("${file.upload.path}") - private String uploadPath; - @PostMapping("/addDirectory") @Operation(summary = "新增目录资源") public ApiResponse addDirectory(@RequestBody AddDirectoryDto addDirectoryDto) { @@ -223,23 +203,75 @@ public class SourceController { public ApiResponse uploadLocationImage(@RequestParam("ids") @Parameter(description = "上传定位图片ID列表") List ids, @RequestParam(value = "parentId", required = false) @Parameter(description = "父节点ID") String parentId, @RequestParam(value = "treeIndex", required = false) @Parameter(description = "树状索引") Integer treeIndex, + @RequestParam(value = "params", required = false) @Parameter(description = "参数") String params, + @RequestParam(value = "sourceType", required = false) @Parameter(description = "资源类型") String sourceType, @RequestParam("files") @Parameter(description = "带有定位的图片文件", required = true) MultipartFile[] files) { + // 验证并转换参数 + sourceParamsValidator.validateAndConvert( + sourceType, + JsonUtil.jsonToMap(params) + ); + + List sources = new ArrayList<>(); for (int i = 0; i < files.length; i++) { - String detail = fileInfoControllerl.handleLocationImageUpload(files[i]); + Map dataMap = fileInfoService.handleLocationImageUpload(files[i]); // 构建并保存资源对象 Source source = new Source(); source.setId(ids.get(i)); source.setSourceName(files[i].getOriginalFilename()); source.setParentId(parentId); - source.setSourceType("locationImage"); + source.setSourceType(sourceType); source.setTreeIndex(treeIndex); - source.setDetail(detail); + + // 转换为对象 + Point point = JsonUtil.mapToObject(JsonUtil.jsonToMap(params), Point.class); + point.setId(ids.get(i)); + Point.Position position = new Point.Position(); + point.setName(files[i].getOriginalFilename()); + point.getLabel().setText(files[i].getOriginalFilename()); + Object lonObj = dataMap.get("lon"); + if (lonObj != null && lonObj instanceof Double) { + position.setLng((Double) lonObj); + } + + Object latObj = dataMap.get("lat"); + if (latObj != null && latObj instanceof Double) { + position.setLat((Double) latObj); + } + + Object altObj = dataMap.get("alt"); + if (altObj != null && altObj instanceof Double) { + position.setAlt((Double) altObj); + } + point.setPosition(position); + + if ("linkImage".equals(sourceType)) { + // 设置地址 + List list = new ArrayList<>(); + Point.Attribute.Link.LinkContent linkContent = new Point.Attribute.Link.LinkContent(); + linkContent.setName("带定位照片"); + linkContent.setUrl(dataMap.get("url").toString()); + list.add(linkContent); + point.getAttribute().getLink().setContent(list); + } else { + List list = new ArrayList<>(); + Point.Attribute.Vr.VrContent vrContent = new Point.Attribute.Vr.VrContent(); + vrContent.setName("带全景照片"); + vrContent.setUrl(dataMap.get("url").toString()); + list.add(vrContent); + point.getAttribute().getVr().setContent(list); + } + + // 将 vrImage 转化为 JSON + source.setParams(JsonUtil.toJson(point)); source.setIsShow(SHOW); sourceService.save(source); // 添加资源到该用户的角色下 roleSourceService.addRoleSource(userService.getById(StpUtil.getLoginIdAsString()).getRoleId(), source.getId()); + + sources.add(source); } - return ApiResponse.success(null); + return ApiResponse.success(sources); } @GetMapping("/type") diff --git a/src/main/java/com/yj/earth/business/controller/TacticalCalculationController.java b/src/main/java/com/yj/earth/business/controller/TacticalCalculationController.java index aabf0be..3531828 100644 --- a/src/main/java/com/yj/earth/business/controller/TacticalCalculationController.java +++ b/src/main/java/com/yj/earth/business/controller/TacticalCalculationController.java @@ -38,7 +38,7 @@ public class TacticalCalculationController { // 同向而行:时间 = 距离 / (速度差) double speedDiff = Math.abs(input.getSpeed1() - input.getSpeed2()); if (speedDiff <= 0) { - throw new IllegalArgumentException("同向而行时,速度不能相等或后方速度小于前方"); + throw new IllegalArgumentException("同向而行时、速度不能相等或后方速度小于前方"); } meetTimeHours = input.getInitialDistance() / speedDiff; } else { diff --git a/src/main/java/com/yj/earth/business/domain/Model.java b/src/main/java/com/yj/earth/business/domain/Model.java index 4cc5e0a..d6240c9 100644 --- a/src/main/java/com/yj/earth/business/domain/Model.java +++ b/src/main/java/com/yj/earth/business/domain/Model.java @@ -1,49 +1,34 @@ package com.yj.earth.business.domain; -import com.baomidou.mybatisplus.annotation.FieldFill; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; -import java.io.Serializable; import java.time.LocalDateTime; - @Data -public class Model implements Serializable { - - private static final long serialVersionUID = 1L; - +@NoArgsConstructor +@AllArgsConstructor +public class Model { @Schema(description = "主键") - @TableId(value = "id", type = IdType.ASSIGN_UUID) private String id; - @Schema(description = "模型类型ID") private String modelTypeId; - @Schema(description = "模型名称") private String modelName; - @Schema(description = "模型类型") private String modelType; - @Schema(description = "海报类型") private String posterType; - - @Schema(description = "海报") - private byte[] poster; - - @Schema(description = "数据") - private byte[] data; - - @Schema(description = "视图") + @Schema(description = "海报数据") + private String poster; + @Schema(description = "模型数据") + private String data; + @Schema(description = "模型视图") private String view; - - @TableField(fill = FieldFill.INSERT) + @Schema(description = "创建时间") private LocalDateTime createdAt; - - @TableField(fill = FieldFill.UPDATE) + @Schema(description = "更新时间") private LocalDateTime updatedAt; } diff --git a/src/main/java/com/yj/earth/business/domain/ModelType.java b/src/main/java/com/yj/earth/business/domain/ModelType.java index b303c8a..ca189af 100644 --- a/src/main/java/com/yj/earth/business/domain/ModelType.java +++ b/src/main/java/com/yj/earth/business/domain/ModelType.java @@ -1,35 +1,20 @@ package com.yj.earth.business.domain; -import com.baomidou.mybatisplus.annotation.FieldFill; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import java.io.Serializable; import java.time.LocalDateTime; @Data -public class ModelType implements Serializable { - - private static final long serialVersionUID = 1L; - +public class ModelType { @Schema(description = "主键") - @TableId(value = "id", type = IdType.ASSIGN_UUID) private String id; - @Schema(description = "模型类型名称") private String name; - - @Schema(description = "模型类型父级ID") + @Schema(description = "父级节点ID") private String parentId; - @Schema(description = "创建时间") - @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; - @Schema(description = "更新时间") - @TableField(fill = FieldFill.UPDATE) private LocalDateTime updatedAt; } diff --git a/src/main/java/com/yj/earth/business/mapper/ModelMapper.java b/src/main/java/com/yj/earth/business/mapper/ModelMapper.java deleted file mode 100644 index 9e46f96..0000000 --- a/src/main/java/com/yj/earth/business/mapper/ModelMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.yj.earth.business.mapper; - -import com.yj.earth.business.domain.Model; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.apache.ibatis.annotations.Mapper; - -/** - *

- * Mapper 接口 - *

- * - * @author 周志雄 - * @since 2025-09-16 - */ -@Mapper -public interface ModelMapper extends BaseMapper { - -} diff --git a/src/main/java/com/yj/earth/business/mapper/ModelTypeMapper.java b/src/main/java/com/yj/earth/business/mapper/ModelTypeMapper.java deleted file mode 100644 index 7c89063..0000000 --- a/src/main/java/com/yj/earth/business/mapper/ModelTypeMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.yj.earth.business.mapper; - -import com.yj.earth.business.domain.ModelType; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.apache.ibatis.annotations.Mapper; - -/** - *

- * Mapper 接口 - *

- * - * @author 周志雄 - * @since 2025-09-16 - */ -@Mapper -public interface ModelTypeMapper extends BaseMapper { - -} diff --git a/src/main/java/com/yj/earth/business/service/FileInfoService.java b/src/main/java/com/yj/earth/business/service/FileInfoService.java index d2d5de0..4cfce7f 100644 --- a/src/main/java/com/yj/earth/business/service/FileInfoService.java +++ b/src/main/java/com/yj/earth/business/service/FileInfoService.java @@ -2,8 +2,16 @@ package com.yj.earth.business.service; import com.yj.earth.business.domain.FileInfo; import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Map; public interface FileInfoService extends IService { // 根据文件ID获取文件绝对路径 String getFileAbsolutePath(String id); + Map handleLocationImageUpload(MultipartFile file); + String uploadWithPreview(MultipartFile file); + void writeResponseMessage(HttpServletResponse response, String message); + String getFullUploadPath(); } diff --git a/src/main/java/com/yj/earth/business/service/ModelService.java b/src/main/java/com/yj/earth/business/service/ModelService.java deleted file mode 100644 index 53081cf..0000000 --- a/src/main/java/com/yj/earth/business/service/ModelService.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.yj.earth.business.service; - -import com.yj.earth.business.domain.Model; -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 服务类 - *

- * - * @author 周志雄 - * @since 2025-09-16 - */ -public interface ModelService extends IService { - -} diff --git a/src/main/java/com/yj/earth/business/service/ModelTypeService.java b/src/main/java/com/yj/earth/business/service/ModelTypeService.java deleted file mode 100644 index dbb4798..0000000 --- a/src/main/java/com/yj/earth/business/service/ModelTypeService.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.yj.earth.business.service; - -import com.yj.earth.business.domain.ModelType; -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 服务类 - *

- * - * @author 周志雄 - * @since 2025-09-16 - */ -public interface ModelTypeService extends IService { - -} diff --git a/src/main/java/com/yj/earth/business/service/impl/FileInfoServiceImpl.java b/src/main/java/com/yj/earth/business/service/impl/FileInfoServiceImpl.java index 36d5d5b..6a2ea51 100644 --- a/src/main/java/com/yj/earth/business/service/impl/FileInfoServiceImpl.java +++ b/src/main/java/com/yj/earth/business/service/impl/FileInfoServiceImpl.java @@ -1,21 +1,38 @@ package com.yj.earth.business.service.impl; +import cn.hutool.core.io.FileUtil; +import com.drew.imaging.ImageMetadataReader; +import com.drew.lang.Rational; +import com.drew.metadata.Metadata; +import com.drew.metadata.exif.GpsDirectory; import com.yj.earth.business.domain.FileInfo; import com.yj.earth.business.mapper.FileInfoMapper; import com.yj.earth.business.service.FileInfoService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yj.earth.datasource.DatabaseManager; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.util.DigestUtils; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.multipart.MultipartFile; import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; @Service public class FileInfoServiceImpl extends ServiceImpl implements FileInfoService { - @Value("${file.upload.path}") - private String uploadPath; + private static final String DEFAULT_UPLOAD_PATH = "upload"; public String getFileAbsolutePath(String id) { @@ -26,7 +43,7 @@ public class FileInfoServiceImpl extends ServiceImpl i } // 构建完整文件路径 - String fullPath = uploadPath + File.separator + fileInfo.getFilePath(); + String fullPath = DEFAULT_UPLOAD_PATH + File.separator + fileInfo.getFilePath(); File file = new File(fullPath); // 校验文件是否存在 @@ -37,4 +54,187 @@ public class FileInfoServiceImpl extends ServiceImpl i // 获取并返回绝对路径 return file.getAbsolutePath(); } + + public Map handleLocationImageUpload(MultipartFile file) { + // 构建并返回结果 + Map result = new HashMap<>(); + try { + // 校验文件是否为空 + if (file.isEmpty()) { + throw new IllegalArgumentException("上传文件不能为空"); + } + // 获取文件基本信息 + String originalFilename = file.getOriginalFilename(); + String fileSuffix = FileUtil.extName(originalFilename); + String contentType = file.getContentType(); + // 验证是否为图片文件 + if (contentType == null || !contentType.startsWith("image/")) { + throw new IllegalArgumentException("请上传图片文件"); + } + // 获取完整的上传目录路径 + Path fullUploadPath = Paths.get(getFullUploadPath()); + // 生成唯一文件名 + String uniqueFileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + fileSuffix; + // 创建文件存储目录 + Files.createDirectories(fullUploadPath); + // 构建完整文件路径并保存文件 + Path destFilePath = fullUploadPath.resolve(uniqueFileName); + // 先将文件保存到目标位置 + file.transferTo(destFilePath); + // 计算文件MD5(使用已保存的文件) + String fileMd5 = calculateFileMd5(destFilePath.toFile()); + // 提取图片元数据(使用已保存的文件、避免使用临时文件) + Map metadata; + try (InputStream is = Files.newInputStream(destFilePath)) { + metadata = extractImageMetadata(is); + } + // 保存文件信息到数据库 + FileInfo fileInfo = new FileInfo(); + fileInfo.setFileName(originalFilename); + fileInfo.setFileSuffix(fileSuffix); + fileInfo.setContentType(contentType); + fileInfo.setFileSize(file.getSize()); + fileInfo.setFilePath(uniqueFileName); + fileInfo.setFileMd5(fileMd5); + this.save(fileInfo); + result.put("url", "/fileInfo/preview/" + fileInfo.getId()); + result.put("lon", metadata.get("lon")); + result.put("lat", metadata.get("lat")); + result.put("alt", metadata.get("alt")); + } catch (IOException e) { + throw new RuntimeException("文件上传失败: " + e.getMessage(), e); + } + return result; + } + + public String uploadWithPreview(MultipartFile file) { + FileInfo fileInfo = new FileInfo(); + // 构建并返回结果 + Map result = new HashMap<>(); + try { + // 校验文件是否为空 + if (file.isEmpty()) { + throw new IllegalArgumentException("上传文件不能为空"); + } + // 获取文件基本信息 + String originalFilename = file.getOriginalFilename(); + String fileSuffix = FileUtil.extName(originalFilename); + String contentType = file.getContentType(); + // 获取完整的上传目录路径 + Path fullUploadPath = Paths.get(getFullUploadPath()); + // 生成唯一文件名 + String uniqueFileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + fileSuffix; + // 创建文件存储目录 + Files.createDirectories(fullUploadPath); + // 构建完整文件路径并保存文件 + Path destFilePath = fullUploadPath.resolve(uniqueFileName); + // 先将文件保存到目标位置 + file.transferTo(destFilePath); + // 计算文件MD5(使用已保存的文件) + String fileMd5 = calculateFileMd5(destFilePath.toFile()); + // 保存文件信息到数据库 + fileInfo.setFileName(originalFilename); + fileInfo.setFileSuffix(fileSuffix); + fileInfo.setContentType(contentType); + fileInfo.setFileSize(file.getSize()); + fileInfo.setFilePath(uniqueFileName); + fileInfo.setFileMd5(fileMd5); + this.save(fileInfo); + } catch (IOException e) { + throw new RuntimeException("文件上传失败: " + e.getMessage(), e); + } + return "/fileInfo/preview/" + fileInfo.getId(); + } + + public void writeResponseMessage(HttpServletResponse response, String message) { + try { + response.setContentType("text/plain; charset=UTF-8"); + response.getWriter().write(message); + response.getWriter().flush(); + } catch (IOException e) { + } + } + + public String getFullUploadPath() { + // 拼接项目根目录和配置的上传路径 + return DatabaseManager.getRecommendedCacheDirectory() + File.separator + DEFAULT_UPLOAD_PATH; + } + + /** + * 提取图片的EXIF元数据 + */ + public Map extractImageMetadata(InputStream inputStream) { + Map result = new HashMap<>(3); + try { + Metadata metadata = ImageMetadataReader.readMetadata(inputStream); + // 获取GPS相关元数据目录(图片的经纬度和高度通常存储在GPS目录中) + GpsDirectory gpsDirectory = metadata.getFirstDirectoryOfType(GpsDirectory.class); + if (gpsDirectory == null) { + return result; + } + + // 解析纬度(度分秒转十进制) + Double latitude = parseLatitudeOrLongitude( + gpsDirectory.getRationalArray(GpsDirectory.TAG_LATITUDE), + gpsDirectory.getString(GpsDirectory.TAG_LATITUDE_REF) + ); + + // 解析经度(度分秒转十进制) + Double longitude = parseLatitudeOrLongitude( + gpsDirectory.getRationalArray(GpsDirectory.TAG_LONGITUDE), + gpsDirectory.getString(GpsDirectory.TAG_LONGITUDE_REF) + ); + + // 解析高度(考虑海拔参考、0表示海平面以上、1表示以下) + Double altitude = null; + if (gpsDirectory.containsTag(GpsDirectory.TAG_ALTITUDE)) { + Rational altitudeRational = gpsDirectory.getRational(GpsDirectory.TAG_ALTITUDE); + if (altitudeRational != null) { + altitude = altitudeRational.doubleValue(); + // 处理海拔参考(是否在海平面以下) + if (gpsDirectory.containsTag(GpsDirectory.TAG_ALTITUDE_REF) && + gpsDirectory.getInt(GpsDirectory.TAG_ALTITUDE_REF) == 1) { + altitude = -altitude; + } + } + } + + // 存入结果 Map + result.put("lat", latitude); + result.put("lon", longitude); + result.put("alt", altitude); + } catch (Exception e) { + throw new RuntimeException(e); + } + return result; + } + + /** + * 将GPS的度分秒格式转换为十进制坐标 + */ + public Double parseLatitudeOrLongitude(Rational[] degreesMinutesSeconds, String ref) { + if (degreesMinutesSeconds == null || degreesMinutesSeconds.length != 3 || ref == null) { + return null; + } + // 度分秒转十进制:度 + 分/60 + 秒/3600 + double degrees = degreesMinutesSeconds[0].doubleValue(); + double minutes = degreesMinutesSeconds[1].doubleValue(); + double seconds = degreesMinutesSeconds[2].doubleValue(); + double value = degrees + (minutes / 60) + (seconds / 3600); + // 根据方向参考调整正负(南纬/西经为负) + if (ref.equalsIgnoreCase("S") || ref.equalsIgnoreCase("W")) { + value = -value; + } + + return value; + } + + /** + * 计算文件的 MD5 + */ + public String calculateFileMd5(File file) throws IOException { + try (InputStream is = new FileInputStream(file)) { + return DigestUtils.md5DigestAsHex(is); + } + } } diff --git a/src/main/java/com/yj/earth/business/service/impl/ModelServiceImpl.java b/src/main/java/com/yj/earth/business/service/impl/ModelServiceImpl.java deleted file mode 100644 index 03dfe3e..0000000 --- a/src/main/java/com/yj/earth/business/service/impl/ModelServiceImpl.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.yj.earth.business.service.impl; - -import com.yj.earth.business.domain.Model; -import com.yj.earth.business.mapper.ModelMapper; -import com.yj.earth.business.service.ModelService; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.stereotype.Service; - -/** - *

- * 服务实现类 - *

- * - * @author 周志雄 - * @since 2025-09-16 - */ -@Service -public class ModelServiceImpl extends ServiceImpl implements ModelService { - -} diff --git a/src/main/java/com/yj/earth/business/service/impl/ModelTypeServiceImpl.java b/src/main/java/com/yj/earth/business/service/impl/ModelTypeServiceImpl.java deleted file mode 100644 index 8826fb9..0000000 --- a/src/main/java/com/yj/earth/business/service/impl/ModelTypeServiceImpl.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.yj.earth.business.service.impl; - -import com.yj.earth.business.domain.ModelType; -import com.yj.earth.business.mapper.ModelTypeMapper; -import com.yj.earth.business.service.ModelTypeService; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.stereotype.Service; - -/** - *

- * 服务实现类 - *

- * - * @author 周志雄 - * @since 2025-09-16 - */ -@Service -public class ModelTypeServiceImpl extends ServiceImpl implements ModelTypeService { - -} diff --git a/src/main/java/com/yj/earth/common/config/GlobalExceptionHandler.java b/src/main/java/com/yj/earth/common/config/GlobalExceptionHandler.java index 07cb141..364a530 100644 --- a/src/main/java/com/yj/earth/common/config/GlobalExceptionHandler.java +++ b/src/main/java/com/yj/earth/common/config/GlobalExceptionHandler.java @@ -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()); } diff --git a/src/main/java/com/yj/earth/common/config/SaTokenConfig.java b/src/main/java/com/yj/earth/common/config/SaTokenConfig.java index 9306d0c..49fdb47 100644 --- a/src/main/java/com/yj/earth/common/config/SaTokenConfig.java +++ b/src/main/java/com/yj/earth/common/config/SaTokenConfig.java @@ -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 -> { diff --git a/src/main/java/com/yj/earth/common/service/ServerInitService.java b/src/main/java/com/yj/earth/common/service/ServerInitService.java index 731574e..5d76c70 100644 --- a/src/main/java/com/yj/earth/common/service/ServerInitService.java +++ b/src/main/java/com/yj/earth/common/service/ServerInitService.java @@ -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().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()); - - - } - } } diff --git a/src/main/java/com/yj/earth/common/util/CodeUtil.java b/src/main/java/com/yj/earth/common/util/CodeUtil.java index c885103..ac113dc 100644 --- a/src/main/java/com/yj/earth/common/util/CodeUtil.java +++ b/src/main/java/com/yj/earth/common/util/CodeUtil.java @@ -34,7 +34,7 @@ public class CodeUtil { } // 传入需要生成代码的表名 - Generation("model"); + Generation("business_config"); } public static void Generation(String... tableName) { diff --git a/src/main/java/com/yj/earth/common/util/FileUtil.java b/src/main/java/com/yj/earth/common/util/FileUtil.java new file mode 100644 index 0000000..63cd703 --- /dev/null +++ b/src/main/java/com/yj/earth/common/util/FileUtil.java @@ -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; + } + } +} diff --git a/src/main/java/com/yj/earth/common/util/JsonUtil.java b/src/main/java/com/yj/earth/common/util/JsonUtil.java index 2b4e09c..37cdd8f 100644 --- a/src/main/java/com/yj/earth/common/util/JsonUtil.java +++ b/src/main/java/com/yj/earth/common/util/JsonUtil.java @@ -47,4 +47,43 @@ public class JsonUtil { return new HashMap<>(0); } } + + /** + * 将 JSON 字符串转换为指定类型的对象 + */ + public static T jsonToObject(String json, Class clazz) { + if (json == null || json.trim().isEmpty()) { + return null; + } + return objectMapper.convertValue(json, clazz); + } + + /** + * 将 Map 转换为指定类型的对象 + */ + public static T mapToObject(Map map, Class 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; + } + } } diff --git a/src/main/java/com/yj/earth/common/util/SQLiteUtil.java b/src/main/java/com/yj/earth/common/util/SQLiteUtil.java new file mode 100644 index 0000000..9665a0a --- /dev/null +++ b/src/main/java/com/yj/earth/common/util/SQLiteUtil.java @@ -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 queryForObject(String dbFilePath, String sql, List params, Class clazz) throws SQLException, IllegalAccessException, InstantiationException { + List results = queryForList(dbFilePath, sql, params, clazz); + return results.isEmpty() ? null : results.get(0); + } + + /** + * 执行查询并返回对象列表 + */ + public static List queryForList(String dbFilePath, String sql, List params, Class clazz) + throws SQLException, IllegalAccessException, InstantiationException { + List 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 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 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 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 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); + } + +} diff --git a/src/main/java/com/yj/earth/datasource/DatabaseManager.java b/src/main/java/com/yj/earth/datasource/DatabaseManager.java index 328d97a..7e91521 100644 --- a/src/main/java/com/yj/earth/datasource/DatabaseManager.java +++ b/src/main/java/com/yj/earth/datasource/DatabaseManager.java @@ -47,8 +47,8 @@ public class DatabaseManager { classes.add(Source.class); classes.add(RoleSource.class); classes.add(FileInfo.class); - classes.add(ModelType.class); - classes.add(Model.class); + classes.add(ModelLibrary.class); + classes.add(BusinessConfig.class); ENTITY_CLASSES = Collections.unmodifiableList(classes); } @@ -292,7 +292,7 @@ public class DatabaseManager { } } - private static Path getRecommendedCacheDirectory() { + public static Path getRecommendedCacheDirectory() { String os = System.getProperty("os.name").toLowerCase(); if (os.contains("win")) { String appData = System.getenv("APPDATA"); diff --git a/src/main/java/com/yj/earth/design/BusinessConfig.java b/src/main/java/com/yj/earth/design/BusinessConfig.java new file mode 100644 index 0000000..a3612f2 --- /dev/null +++ b/src/main/java/com/yj/earth/design/BusinessConfig.java @@ -0,0 +1,24 @@ +package com.yj.earth.design; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class BusinessConfig { + @Schema(description = "主键") + private String id; + + @Schema(description = "键") + private String key; + + @Schema(description = "值") + private String value; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "更新时间") + private LocalDateTime updatedAt; +} diff --git a/src/main/java/com/yj/earth/design/ModelLibrary.java b/src/main/java/com/yj/earth/design/ModelLibrary.java new file mode 100644 index 0000000..ccb9234 --- /dev/null +++ b/src/main/java/com/yj/earth/design/ModelLibrary.java @@ -0,0 +1,22 @@ +package com.yj.earth.design; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ModelLibrary { + @Schema(description = "主键") + private String id; + @Schema(description = "模型库路径") + private String path; + @Schema(description = "模型库名称") + private String name; + @Schema(description = "是否启用") + private Integer isEnable; + @Schema(description = "创建时间") + private LocalDateTime createdAt; + @Schema(description = "更新时间") + private LocalDateTime updatedAt; +} diff --git a/src/main/java/com/yj/earth/dto/businessConfig/AddBusinessConfigDto.java b/src/main/java/com/yj/earth/dto/businessConfig/AddBusinessConfigDto.java new file mode 100644 index 0000000..e463ba6 --- /dev/null +++ b/src/main/java/com/yj/earth/dto/businessConfig/AddBusinessConfigDto.java @@ -0,0 +1,13 @@ +package com.yj.earth.dto.businessConfig; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class AddBusinessConfigDto { + @Schema(description = "键") + private String key; + + @Schema(description = "值") + private String value; +} diff --git a/src/main/java/com/yj/earth/dto/model/AddModelTypeDto.java b/src/main/java/com/yj/earth/dto/model/AddModelTypeDto.java new file mode 100644 index 0000000..90ba484 --- /dev/null +++ b/src/main/java/com/yj/earth/dto/model/AddModelTypeDto.java @@ -0,0 +1,12 @@ +package com.yj.earth.dto.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class AddModelTypeDto { + @Schema(description = "模型类型名称") + private String name; + @Schema(description = "父级节点ID") + private String parentId; +} diff --git a/src/main/java/com/yj/earth/dto/model/CreateModelFileDto.java b/src/main/java/com/yj/earth/dto/model/CreateModelLibraryDto.java similarity index 68% rename from src/main/java/com/yj/earth/dto/model/CreateModelFileDto.java rename to src/main/java/com/yj/earth/dto/model/CreateModelLibraryDto.java index 3cf9d42..be92523 100644 --- a/src/main/java/com/yj/earth/dto/model/CreateModelFileDto.java +++ b/src/main/java/com/yj/earth/dto/model/CreateModelLibraryDto.java @@ -4,9 +4,9 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data -public class CreateModelFileDto { +public class CreateModelLibraryDto { @Schema(description = "模型库文件名称") - private String modelFileName; + private String name; @Schema(description = "生成文件夹路径") - private String folderPath; + private String path; } diff --git a/src/main/java/com/yj/earth/params/LinkImage.java b/src/main/java/com/yj/earth/params/LinkImage.java new file mode 100644 index 0000000..e7eb669 --- /dev/null +++ b/src/main/java/com/yj/earth/params/LinkImage.java @@ -0,0 +1,134 @@ +package com.yj.earth.params; + +import com.yj.earth.annotation.SourceType; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@SourceType("linkImage") +public class LinkImage { + private String id; + private boolean show; + private String name; + private Position position; + private int heightMode; + private boolean scaleByDistance; + private int near; + private int far; + private Billboard billboard; + private Label label; + private Attribute attribute; + private String richTextContent; + private CustomView customView; + + @Data + @NoArgsConstructor + public static class Position { + private double lng; + private double lat; + private double alt; + } + + @Data + @NoArgsConstructor + public static class Billboard { + private boolean show; + private String image; + private String defaultImage; + private int scale; + } + + @Data + @NoArgsConstructor + public static class Label { + private String text; + private boolean show; + private int fontFamily; + private int fontSize; + private String color; + } + + @Data + @NoArgsConstructor + public static class Attribute { + private Link link; + private Vr vr; + private Camera camera; + private Isc isc; + private Goods goods; + + @Data + @NoArgsConstructor + public static class Link { + private List content; + @Data + @NoArgsConstructor + public static class LinkContent { + private String name; + private String url; + } + } + + @Data + @NoArgsConstructor + public static class Vr { + private List content; + @Data + @NoArgsConstructor + public static class VrContent { + private String name; + private String url; + } + } + + @Data + @NoArgsConstructor + public static class Camera { + private List content; + } + + @Data + @NoArgsConstructor + public static class Isc { + private List content; + } + + @Data + @NoArgsConstructor + public static class Goods { + private List content; + @Data + @NoArgsConstructor + public static class GoodsContent { + private String id; + private String name; + private String cnt; + } + } + } + + @Data + @NoArgsConstructor + public static class CustomView { + private Orientation orientation; + private RelativePosition relativePosition; + @Data + @NoArgsConstructor + public static class Orientation { + private double heading; + private double pitch; + private double roll; + } + + @Data + @NoArgsConstructor + public static class RelativePosition { + private double lng; + private double lat; + private double alt; + } + } +} diff --git a/src/main/java/com/yj/earth/params/Point.java b/src/main/java/com/yj/earth/params/Point.java index 67659bc..0e9ec52 100644 --- a/src/main/java/com/yj/earth/params/Point.java +++ b/src/main/java/com/yj/earth/params/Point.java @@ -2,9 +2,12 @@ package com.yj.earth.params; import com.yj.earth.annotation.SourceType; import lombok.Data; +import lombok.NoArgsConstructor; + import java.util.List; @Data +@NoArgsConstructor @SourceType("point") public class Point { private String id; @@ -22,6 +25,7 @@ public class Point { private CustomView customView; @Data + @NoArgsConstructor public static class Position { private double lng; private double lat; @@ -29,6 +33,7 @@ public class Point { } @Data + @NoArgsConstructor public static class Billboard { private boolean show; private String image; @@ -37,6 +42,7 @@ public class Point { } @Data + @NoArgsConstructor public static class Label { private String text; private boolean show; @@ -46,6 +52,7 @@ public class Point { } @Data + @NoArgsConstructor public static class Attribute { private Link link; private Vr vr; @@ -54,9 +61,11 @@ public class Point { private Goods goods; @Data + @NoArgsConstructor public static class Link { private List content; @Data + @NoArgsConstructor public static class LinkContent { private String name; private String url; @@ -64,9 +73,11 @@ public class Point { } @Data + @NoArgsConstructor public static class Vr { private List content; @Data + @NoArgsConstructor public static class VrContent { private String name; private String url; @@ -74,19 +85,23 @@ public class Point { } @Data + @NoArgsConstructor public static class Camera { private List content; } @Data + @NoArgsConstructor public static class Isc { private List content; } @Data + @NoArgsConstructor public static class Goods { private List content; @Data + @NoArgsConstructor public static class GoodsContent { private String id; private String name; @@ -96,10 +111,12 @@ public class Point { } @Data + @NoArgsConstructor public static class CustomView { private Orientation orientation; private RelativePosition relativePosition; @Data + @NoArgsConstructor public static class Orientation { private double heading; private double pitch; @@ -107,6 +124,7 @@ public class Point { } @Data + @NoArgsConstructor public static class RelativePosition { private double lng; private double lat; diff --git a/src/main/java/com/yj/earth/params/Terrain.java b/src/main/java/com/yj/earth/params/Terrain.java new file mode 100644 index 0000000..8413306 --- /dev/null +++ b/src/main/java/com/yj/earth/params/Terrain.java @@ -0,0 +1,12 @@ +package com.yj.earth.params; + +import com.yj.earth.annotation.SourceType; +import lombok.Data; + +@Data +@SourceType("terrain") +public class Terrain { + private String id; + private String name; + private boolean show; +} diff --git a/src/main/java/com/yj/earth/params/VrImage.java b/src/main/java/com/yj/earth/params/VrImage.java new file mode 100644 index 0000000..99f7c2e --- /dev/null +++ b/src/main/java/com/yj/earth/params/VrImage.java @@ -0,0 +1,134 @@ +package com.yj.earth.params; + +import com.yj.earth.annotation.SourceType; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@SourceType("vrImage") +public class VrImage { + private String id; + private boolean show; + private String name; + private Position position; + private int heightMode; + private boolean scaleByDistance; + private int near; + private int far; + private Billboard billboard; + private Label label; + private Attribute attribute; + private String richTextContent; + private CustomView customView; + + @Data + @NoArgsConstructor + public static class Position { + private double lng; + private double lat; + private double alt; + } + + @Data + @NoArgsConstructor + public static class Billboard { + private boolean show; + private String image; + private String defaultImage; + private int scale; + } + + @Data + @NoArgsConstructor + public static class Label { + private String text; + private boolean show; + private int fontFamily; + private int fontSize; + private String color; + } + + @Data + @NoArgsConstructor + public static class Attribute { + private Link link; + private Vr vr; + private Camera camera; + private Isc isc; + private Goods goods; + + @Data + @NoArgsConstructor + public static class Link { + private List content; + @Data + @NoArgsConstructor + public static class LinkContent { + private String name; + private String url; + } + } + + @Data + @NoArgsConstructor + public static class Vr { + private List content; + @Data + @NoArgsConstructor + public static class VrContent { + private String name; + private String url; + } + } + + @Data + @NoArgsConstructor + public static class Camera { + private List content; + } + + @Data + @NoArgsConstructor + public static class Isc { + private List content; + } + + @Data + @NoArgsConstructor + public static class Goods { + private List content; + @Data + @NoArgsConstructor + public static class GoodsContent { + private String id; + private String name; + private String cnt; + } + } + } + + @Data + @NoArgsConstructor + public static class CustomView { + private Orientation orientation; + private RelativePosition relativePosition; + @Data + @NoArgsConstructor + public static class Orientation { + private double heading; + private double pitch; + private double roll; + } + + @Data + @NoArgsConstructor + public static class RelativePosition { + private double lng; + private double lat; + private double alt; + } + } +} diff --git a/src/main/java/com/yj/earth/vo/ModelTypeVo.java b/src/main/java/com/yj/earth/vo/ModelTypeVo.java new file mode 100644 index 0000000..14d1bc7 --- /dev/null +++ b/src/main/java/com/yj/earth/vo/ModelTypeVo.java @@ -0,0 +1,40 @@ +package com.yj.earth.vo; + +import com.yj.earth.business.domain.ModelType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ModelTypeVo { + @Schema(description = "主键") + private String id; + + @Schema(description = "模型类型名称") + private String name; + + @Schema(description = "父级节点ID") + private String parentId; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "更新时间") + private LocalDateTime updatedAt; + @Schema(description = "子节点列表") + private List children = new ArrayList<>(); + + public ModelTypeVo(ModelType modelType) { + this.id = modelType.getId(); + this.name = modelType.getName(); + this.parentId = modelType.getParentId(); + this.createdAt = modelType.getCreatedAt(); + this.updatedAt = modelType.getUpdatedAt(); + } +} diff --git a/src/main/java/com/yj/earth/vo/ModelVo.java b/src/main/java/com/yj/earth/vo/ModelVo.java new file mode 100644 index 0000000..efb151c --- /dev/null +++ b/src/main/java/com/yj/earth/vo/ModelVo.java @@ -0,0 +1,9 @@ +package com.yj.earth.vo; + +import com.yj.earth.business.domain.Model; +import lombok.Data; + +@Data +public class ModelVo extends Model { + private String modelTypeName; +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4e0626b..6f945d7 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -38,10 +38,6 @@ encrypt: aes: key: "ah62ks8dj7dh3yd6" -file: - upload: - path: upload - graphhopper: graphLocation: ./target/graphhopper profiles: diff --git a/src/main/resources/mapper/ModelMapper.xml b/src/main/resources/mapper/ModelMapper.xml deleted file mode 100644 index aa97ec1..0000000 --- a/src/main/resources/mapper/ModelMapper.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - id, model_type_id, model_name, model_type, poster_type, poster, data, view, created_at, updated_at - - - diff --git a/src/main/resources/mapper/ModelTypeMapper.xml b/src/main/resources/mapper/ModelTypeMapper.xml deleted file mode 100644 index 6716757..0000000 --- a/src/main/resources/mapper/ModelTypeMapper.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - id, name, parent_id, created_at, updated_at - - -