全部
This commit is contained in:
@ -77,7 +77,7 @@ public class AuthGenerator {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
// 生成加密的授权字符串
|
||||
String authContent = generateAuth("标准版", 1000, 365, "8B1FB12E9F8E80109724989E0B25773B");
|
||||
String authContent = generateAuth("标准版", 1000, 1, "25F429FDA965007B72BB7A6B2C03535A");
|
||||
|
||||
// 定义授权文件路径(当前目录下的 yjearth.YJ)
|
||||
Path licPath = Paths.get("yjearth.YJ");
|
||||
@ -92,3 +92,4 @@ public class AuthGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,18 +10,25 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Tag(name = "系统设置管理")
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
// 授权文件存储路径、项目根目录下的 license 目录
|
||||
private static final String AUTH_FILE_PATH = "license/yjearth.YJ";
|
||||
// 授权文件存储目录(项目根目录下的 license 目录)
|
||||
private static final String LICENSE_DIR = "license";
|
||||
// 授权文件后缀(固定为.YJ)
|
||||
private static final String AUTH_FILE_SUFFIX = ".YJ";
|
||||
|
||||
@GetMapping("/info")
|
||||
@Operation(summary = "获取系统授权码")
|
||||
@ -37,28 +44,34 @@ public class AuthController {
|
||||
return ApiResponse.failure("请选择授权文件");
|
||||
}
|
||||
|
||||
// 验证文件名是否为 yjearth.YJ
|
||||
String fileName = file.getOriginalFilename();
|
||||
if (fileName == null || !fileName.equals("yjearth.YJ")) {
|
||||
return ApiResponse.failure("请上传 yjearth.YJ");
|
||||
// 验证文件名不为空且后缀为.YJ
|
||||
if (fileName == null || !fileName.endsWith(AUTH_FILE_SUFFIX)) {
|
||||
return ApiResponse.failure("授权码错误、请联系管理员提供正确的授权文件");
|
||||
}
|
||||
|
||||
try {
|
||||
// 读取文件内容
|
||||
// 读取文件内容并验证有效性
|
||||
String authContent = new String(file.getBytes(), StandardCharsets.UTF_8).trim();
|
||||
// 验证授权内容有效性
|
||||
String serverHardwareMd5 = ServerUniqueIdUtil.getServerUniqueId();
|
||||
boolean isValid = AuthValidator.validateAuth(authContent, serverHardwareMd5);
|
||||
if (!isValid) {
|
||||
return ApiResponse.failure("授权文件无效或已过期");
|
||||
return ApiResponse.failure("授权码错误、请联系管理员提供正确的授权文件");
|
||||
}
|
||||
// 创建目录(如果不存在)
|
||||
Path path = Paths.get(AUTH_FILE_PATH);
|
||||
if (!Files.exists(path.getParent())) {
|
||||
Files.createDirectories(path.getParent());
|
||||
|
||||
// 处理license目录(不存在则创建)
|
||||
Path licenseDirPath = Paths.get(LICENSE_DIR);
|
||||
if (!Files.exists(licenseDirPath)) {
|
||||
Files.createDirectories(licenseDirPath);
|
||||
}
|
||||
// 保存授权文件
|
||||
Files.write(path, authContent.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// 删除目录下已存在的所有.YJ文件(确保仅保留一个)
|
||||
deleteAllYjFilesInLicenseDir();
|
||||
|
||||
// 保存新的授权文件(使用原文件名)
|
||||
Path newAuthFilePath = licenseDirPath.resolve(fileName);
|
||||
Files.write(newAuthFilePath, authContent.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
return ApiResponse.failure("导入授权文件失败: " + e.getMessage());
|
||||
@ -69,18 +82,60 @@ public class AuthController {
|
||||
@Operation(summary = "查看授权信息")
|
||||
public ApiResponse showAuth() {
|
||||
try {
|
||||
// 检查授权文件是否存在
|
||||
Path path = Paths.get(AUTH_FILE_PATH);
|
||||
if (!Files.exists(path)) {
|
||||
return ApiResponse.failure("请先导入授权");
|
||||
// 查找license目录下的所有.YJ文件
|
||||
List<Path> yjFileList = findAllYjFilesInLicenseDir();
|
||||
|
||||
// 处理文件数量异常
|
||||
if (yjFileList.isEmpty()) {
|
||||
return ApiResponse.successWithMessage("未找到授权文件");
|
||||
}
|
||||
// 读取授权文件内容
|
||||
String authContent = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
|
||||
// 获取授权详情
|
||||
if (yjFileList.size() > 1) {
|
||||
return ApiResponse.successWithMessage("授权目录下存在多个" + AUTH_FILE_SUFFIX + "文件,请删除多余文件后重试");
|
||||
}
|
||||
|
||||
// 读取唯一的.YJ文件内容
|
||||
Path authFilePath = yjFileList.get(0);
|
||||
String authContent = new String(Files.readAllBytes(authFilePath), StandardCharsets.UTF_8);
|
||||
|
||||
// 解析并返回授权信息
|
||||
AuthInfo authInfo = AuthValidator.getAuthInfo(authContent);
|
||||
return ApiResponse.success(authInfo);
|
||||
} catch (Exception e) {
|
||||
return ApiResponse.failure("获取授权信息失败: " + e.getMessage());
|
||||
return ApiResponse.successWithMessage("授权码错误、请联系管理员提供正确的授权文件");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找 license 目录下所有后缀为 .YJ 的文件
|
||||
*/
|
||||
private List<Path> findAllYjFilesInLicenseDir() throws IOException {
|
||||
Path licenseDirPath = Paths.get(LICENSE_DIR);
|
||||
if (!Files.exists(licenseDirPath)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (!Files.isDirectory(licenseDirPath)) {
|
||||
throw new IOException("license路径不是合法目录");
|
||||
}
|
||||
|
||||
// 遍历目录、筛选后缀为 .YJ的文件(不区分大小写)
|
||||
try (var directoryStream = Files.list(licenseDirPath)) {
|
||||
return directoryStream
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(path -> {
|
||||
String fileName = path.getFileName().toString().toLowerCase();
|
||||
return fileName.endsWith(AUTH_FILE_SUFFIX.toLowerCase());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 license 目录下所有后缀为 .YJ 的文件
|
||||
*/
|
||||
private void deleteAllYjFilesInLicenseDir() throws IOException {
|
||||
List<Path> yjFileList = findAllYjFilesInLicenseDir();
|
||||
for (Path yjFile : yjFileList) {
|
||||
Files.delete(yjFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,7 +193,7 @@ public class FileInfoController {
|
||||
// 标准化路径
|
||||
targetFilePath = Paths.get(fileAbsolutePath).toRealPath();
|
||||
|
||||
// 校验文件合法性: 是否存在、是否为普通文件
|
||||
// 是否存在、是否为普通文件
|
||||
BasicFileAttributes fileAttr = Files.readAttributes(targetFilePath, BasicFileAttributes.class);
|
||||
if (!fileAttr.isRegularFile()) {
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
@ -204,21 +204,27 @@ public class FileInfoController {
|
||||
// 设置预览响应头
|
||||
String fileName = targetFilePath.getFileName().toString();
|
||||
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
|
||||
|
||||
// 手动映射常见图片格式的 MIME 类型
|
||||
String contentType = Files.probeContentType(targetFilePath);
|
||||
String fileExtension = getFileExtension(fileName).toLowerCase();
|
||||
// 覆盖默认探测结果
|
||||
contentType = mapImageContentType(fileExtension, contentType);
|
||||
|
||||
// 对于文本类型文件、指定字符编码
|
||||
if (contentType != null && contentType.startsWith("text/")) {
|
||||
response.setContentType(contentType + "; charset=UTF-8");
|
||||
} else {
|
||||
response.setContentType(contentType != null ? contentType : "application/octet-stream");
|
||||
// 确保 Content-Type 不为空
|
||||
response.setContentType(contentType != null ? contentType : "image/png");
|
||||
}
|
||||
|
||||
response.setContentLengthLong(fileAttr.size());
|
||||
// 关键修改: 将attachment改为inline实现预览
|
||||
// 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];
|
||||
@ -240,4 +246,32 @@ public class FileInfoController {
|
||||
fileInfoService.writeResponseMessage(response, "预览失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件后缀
|
||||
*/
|
||||
private String getFileExtension(String fileName) {
|
||||
int lastDotIndex = fileName.lastIndexOf('.');
|
||||
return lastDotIndex == -1 ? "" : fileName.substring(lastDotIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 映射图片格式到标准 MIME 类型
|
||||
*/
|
||||
private String mapImageContentType(String fileExtension, String probeContentType) {
|
||||
Map<String, String> imageMimeMap = new HashMap<>();
|
||||
imageMimeMap.put("webp", "image/webp");
|
||||
imageMimeMap.put("png", "image/png");
|
||||
imageMimeMap.put("jpg", "image/jpeg");
|
||||
imageMimeMap.put("jpeg", "image/jpeg");
|
||||
imageMimeMap.put("gif", "image/gif");
|
||||
imageMimeMap.put("bmp", "image/bmp");
|
||||
imageMimeMap.put("svg", "image/svg+xml");
|
||||
|
||||
// 如果探针结果已存在且是图片类型
|
||||
if (probeContentType != null && probeContentType.startsWith("image/")) {
|
||||
return probeContentType;
|
||||
}
|
||||
return imageMimeMap.getOrDefault(fileExtension, probeContentType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,16 +29,18 @@ import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
@Data
|
||||
@Slf4j
|
||||
@Tag(name = "路径规划管理")
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/graphhopper")
|
||||
public class GraphHopperController {
|
||||
@ -56,20 +58,44 @@ public class GraphHopperController {
|
||||
private final AtomicBoolean isLoading = new AtomicBoolean(false);
|
||||
private final AtomicBoolean isLoaded = new AtomicBoolean(false);
|
||||
|
||||
@Operation(summary = "加载地图数据")
|
||||
@Operation(summary = "加载地图数据(启用路网文件)")
|
||||
@PostMapping("/loadMap")
|
||||
|
||||
public ApiResponse loadMap(@Parameter(description = "文件路径") @RequestParam String path) {
|
||||
File osmFile = new File(path);
|
||||
if (!osmFile.exists()) {
|
||||
return ApiResponse.failure("地图文件不存在: " + path);
|
||||
}
|
||||
if (!osmFile.isFile() || !osmFile.getName().endsWith(".pbf")) {
|
||||
return ApiResponse.failure("仅支持有效的.pbf格式OSM文件");
|
||||
if (!osmFile.isFile()) {
|
||||
return ApiResponse.failure("请提供有效的文件路径");
|
||||
}
|
||||
|
||||
String fileName = osmFile.getName();
|
||||
File tempPbfFile = null;
|
||||
|
||||
// 判断文件后缀
|
||||
if (fileName.endsWith(".pbf")) {
|
||||
// 直接使用原文件
|
||||
} else if (fileName.endsWith(".pbfl")) {
|
||||
try {
|
||||
// 创建临时文件,后缀改为 .pbf
|
||||
String tempFileName = UUID.randomUUID().toString() + ".pbf";
|
||||
tempPbfFile = new File(osmFile.getParent(), tempFileName);
|
||||
|
||||
// 复制文件内容
|
||||
Files.copy(osmFile.toPath(), tempPbfFile.toPath());
|
||||
|
||||
// 将路径指向临时文件
|
||||
path = tempPbfFile.getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
return ApiResponse.failure("创建临时文件失败: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
return ApiResponse.failure("仅支持有效的.pbf或.pbfl格式OSM文件");
|
||||
}
|
||||
|
||||
// 防止并发加载
|
||||
if (isLoading.get()) {
|
||||
return ApiResponse.failure("地图正在加载中、请稍后查询状态");
|
||||
return ApiResponse.failure("对应区域的路网文件正在启用中、请稍后查询状态");
|
||||
}
|
||||
|
||||
// 标记加载状态
|
||||
@ -77,19 +103,21 @@ public class GraphHopperController {
|
||||
isLoaded.set(false);
|
||||
|
||||
// 异步执行: 删除旧数据 → 创建新实例 → 加载新地图
|
||||
String finalPath = path;
|
||||
File finalTempPbfFile = tempPbfFile;
|
||||
new Thread(() -> {
|
||||
GraphHopper newHopper = null;
|
||||
try {
|
||||
// 关键步骤1: 彻底删除旧地图数据目录
|
||||
deleteOldGraphDir();
|
||||
// 关键步骤2: 创建全新的GraphHopper实例
|
||||
newHopper = createNewGraphHopperInstance(path);
|
||||
newHopper = createNewGraphHopperInstance(finalPath);
|
||||
// 关键步骤3: 加载新地图
|
||||
newHopper.importOrLoad();
|
||||
// 关键步骤4: 加载成功 → 替换当前实例 + 更新状态
|
||||
currentHopper = newHopper;
|
||||
isLoaded.set(true);
|
||||
log.info("地图加载成功");
|
||||
log.info("对应区域的路网文件启用成功");
|
||||
} catch (Exception e) {
|
||||
// 加载失败 → 清理新实例资源
|
||||
if (newHopper != null) {
|
||||
@ -97,22 +125,31 @@ public class GraphHopperController {
|
||||
}
|
||||
isLoaded.set(false);
|
||||
e.printStackTrace();
|
||||
log.error("地图加载失败: " + e.getMessage());
|
||||
log.error("对应区域的路网文件启用失败: " + e.getMessage());
|
||||
} finally {
|
||||
// 无论成功/失败、释放加载锁
|
||||
isLoading.set(false);
|
||||
|
||||
// 删除临时文件
|
||||
if (finalTempPbfFile != null && finalTempPbfFile.exists()) {
|
||||
if (finalTempPbfFile.delete()) {
|
||||
log.info("临时文件已删除: " + finalTempPbfFile.getAbsolutePath());
|
||||
} else {
|
||||
log.warn("临时文件删除失败: " + finalTempPbfFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@Operation(summary = "清除地图服务")
|
||||
@Operation(summary = "清除地图服务(停用路网文件)")
|
||||
@PostMapping("/clearMap")
|
||||
|
||||
public ApiResponse clearMap() {
|
||||
// 防止并发操作(与加载操作互斥)
|
||||
if (isLoading.get()) {
|
||||
return ApiResponse.failure("地图正在加载中、无法清除、请稍后再试");
|
||||
return ApiResponse.failure("对应区域的路网文件正在启用中、无法清除、请稍后再试");
|
||||
}
|
||||
|
||||
// 标记正在处理清除操作
|
||||
@ -120,24 +157,24 @@ public class GraphHopperController {
|
||||
try {
|
||||
// 1. 关闭当前GraphHopper实例
|
||||
if (currentHopper != null) {
|
||||
log.info("开始关闭当前地图服务实例");
|
||||
log.info("开始关闭当前路网服务实例");
|
||||
currentHopper.close();
|
||||
currentHopper = null;
|
||||
log.info("地图服务实例已关闭");
|
||||
log.info("路网服务实例已关闭");
|
||||
}
|
||||
|
||||
// 2. 删除地图数据目录
|
||||
log.info("开始删除地图数据目录");
|
||||
log.info("开始删除路网数据目录");
|
||||
deleteOldGraphDir();
|
||||
log.info("地图数据目录已删除");
|
||||
log.info("路网数据目录已删除");
|
||||
|
||||
// 3. 重置状态变量
|
||||
isLoaded.set(false);
|
||||
|
||||
return ApiResponse.success("地图服务已成功清除");
|
||||
return ApiResponse.success("对应区域的路网文件已成功停用并清除");
|
||||
} catch (Exception e) {
|
||||
log.error("清除地图服务失败", e);
|
||||
return ApiResponse.failure("清除地图服务失败: " + e.getMessage());
|
||||
log.error("清除路网服务失败", e);
|
||||
return ApiResponse.failure("清除路网服务失败: " + e.getMessage());
|
||||
} finally {
|
||||
// 释放操作锁
|
||||
isLoading.set(false);
|
||||
@ -146,15 +183,17 @@ public class GraphHopperController {
|
||||
|
||||
@Operation(summary = "路径规划")
|
||||
@PostMapping("/route")
|
||||
|
||||
public ApiResponse calculateRoute(@RequestBody RouteRequest request) {
|
||||
// 区分未加载地图和加载中两种状态
|
||||
// 区分三种核心状态提示
|
||||
if (isLoading.get()) {
|
||||
return ApiResponse.failure("地图正在加载中、请稍后再试");
|
||||
// 场景1: 导入了路网文件但未启用(加载中)
|
||||
return ApiResponse.failure("请启用对应区域的路网文件");
|
||||
}
|
||||
if (!isLoaded.get() || currentHopper == null) {
|
||||
return ApiResponse.failure("地图未加载、请先加载地图");
|
||||
// 场景2: 未导入路网文件
|
||||
return ApiResponse.failure("请导入并启用对应区域的路网文件");
|
||||
}
|
||||
|
||||
try {
|
||||
// 构建路径点列表
|
||||
List<GHPoint> ghPoints = new ArrayList<>();
|
||||
@ -182,9 +221,10 @@ public class GraphHopperController {
|
||||
boolean hasPointNotFoundError = response.getErrors().stream()
|
||||
.anyMatch(e -> e instanceof com.graphhopper.util.exceptions.PointNotFoundException);
|
||||
if (hasOutOfBoundsError) {
|
||||
return ApiResponse.failure("路径超出地图范围");
|
||||
// 场景3: 已启用但路径超出路网范围
|
||||
return ApiResponse.failure("绘制路径超出有效路网范围");
|
||||
} else if (hasPointNotFoundError) {
|
||||
return ApiResponse.failure("未超地图范围但找不到路径点");
|
||||
return ApiResponse.failure("未超路网范围但找不到有效路径点");
|
||||
} else {
|
||||
return ApiResponse.failure("路径计算异常: " + response.getErrors().get(0).getMessage());
|
||||
}
|
||||
@ -199,27 +239,26 @@ public class GraphHopperController {
|
||||
RouteResponse routeResponse = new RouteResponse(bestPath.getDistance() / 1000, (double) (bestPath.getTime() / 60000), pathPoints);
|
||||
return ApiResponse.success(routeResponse);
|
||||
} catch (com.graphhopper.util.exceptions.PointOutOfBoundsException e) {
|
||||
// 捕获单点超出范围的异常
|
||||
return ApiResponse.failure("路径超出地图范围");
|
||||
// 捕获单点超出范围的异常(场景3)
|
||||
return ApiResponse.failure("绘制路径超出有效路网范围");
|
||||
} catch (Exception e) {
|
||||
return ApiResponse.failure("路径计算异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "获取地图加载状态")
|
||||
@Operation(summary = "获取路网文件加载状态")
|
||||
@GetMapping("/status")
|
||||
public ApiResponse getMapStatus() {
|
||||
if (isLoading.get()) {
|
||||
return ApiResponse.success("地图正在加载中");
|
||||
return ApiResponse.success("对应区域的路网文件正在启用中");
|
||||
} else if (isLoaded.get() && currentHopper != null) {
|
||||
return ApiResponse.success("地图已加载完成");
|
||||
return ApiResponse.success("对应区域的路网文件已启用");
|
||||
} else {
|
||||
return ApiResponse.success("地图未加载");
|
||||
return ApiResponse.success("未导入对应区域的路网文件");
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "获取交通方式")
|
||||
|
||||
@PostMapping("/profiles")
|
||||
public ApiResponse profiles() {
|
||||
return ApiResponse.success(graphHopperProperties.getProfiles());
|
||||
@ -252,7 +291,7 @@ public class GraphHopperController {
|
||||
private void deleteOldGraphDir() {
|
||||
File graphDir = new File(graphHopperProperties.getGraphLocation());
|
||||
if (!graphDir.exists()) {
|
||||
log.info("旧地图目录不存在、无需删除: " + graphHopperProperties.getGraphLocation());
|
||||
log.info("旧路网目录不存在、无需删除: " + graphHopperProperties.getGraphLocation());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -264,14 +303,14 @@ public class GraphHopperController {
|
||||
deleteOldGraphDir(file);
|
||||
} else {
|
||||
boolean deleted = file.delete();
|
||||
log.info("删除旧地图文件: " + file.getAbsolutePath() + " → " + (deleted ? "成功" : "失败"));
|
||||
log.info("删除旧路网文件: " + file.getAbsolutePath() + " → " + (deleted ? "成功" : "失败"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除空目录
|
||||
boolean dirDeleted = graphDir.delete();
|
||||
System.out.println("删除旧地图目录: " + graphDir.getAbsolutePath() + " → " + (dirDeleted ? "成功" : "失败"));
|
||||
log.info("删除旧路网目录: " + graphDir.getAbsolutePath() + " → " + (dirDeleted ? "成功" : "失败"));
|
||||
}
|
||||
|
||||
// 重载:递归删除子目录
|
||||
|
||||
@ -193,6 +193,9 @@ public class IconLibraryController {
|
||||
@GetMapping("/iconTypeTree")
|
||||
public ApiResponse iconTypeTree(@Parameter(description = "图标名称") @RequestParam(value = "iconName", required = false) String iconName) throws SQLException, IllegalAccessException, InstantiationException {
|
||||
List<IconTypeVo> treeList = iconTypeList(iconName);
|
||||
if(treeList == null){
|
||||
return ApiResponse.successWithMessage("请先创建或导入图标库");
|
||||
}
|
||||
return ApiResponse.success(treeList);
|
||||
}
|
||||
|
||||
@ -392,7 +395,7 @@ public class IconLibraryController {
|
||||
queryWrapper.eq(IconLibrary::getIsEnable, 1);
|
||||
IconLibrary library = iconLibraryService.getOne(queryWrapper);
|
||||
if(library == null){
|
||||
throw new RuntimeException("请先创建或导入图标库");
|
||||
return null;
|
||||
}
|
||||
return library.getPath();
|
||||
}
|
||||
|
||||
@ -206,6 +206,9 @@ public class MilitaryLibraryController {
|
||||
@GetMapping("/militaryTypeTree")
|
||||
public ApiResponse militaryTypeTree(@Parameter(description = "军标名称") @RequestParam(value = "militaryName", required = false) String militaryName) throws SQLException, IllegalAccessException, InstantiationException {
|
||||
List<MilitaryTypeVo> treeList = militaryTypeList(militaryName);
|
||||
if (treeList == null) {
|
||||
return ApiResponse.successWithMessage("请先创建或导入军标库");
|
||||
}
|
||||
return ApiResponse.success(treeList);
|
||||
}
|
||||
|
||||
@ -430,7 +433,7 @@ public class MilitaryLibraryController {
|
||||
queryWrapper.eq(MilitaryLibrary::getIsEnable, 1); // 1=启用、0=未启用
|
||||
MilitaryLibrary library = militaryLibraryService.getOne(queryWrapper);
|
||||
if (library == null) {
|
||||
throw new RuntimeException("请先创建或导入军标库");
|
||||
return null;
|
||||
}
|
||||
return library.getPath();
|
||||
}
|
||||
|
||||
@ -175,7 +175,11 @@ public class ModelLibraryController {
|
||||
@Operation(summary = "模型类型列表")
|
||||
@GetMapping("/modelTypeList")
|
||||
public ApiResponse modelTypeTree(@Parameter(description = "模型名称") @RequestParam(value = "modelName", required = false) String modelName) throws SQLException, IllegalAccessException, InstantiationException {
|
||||
return ApiResponse.success(modelTypeList(modelName));
|
||||
List<ModelTypeVo> modelTypeVos = modelTypeList(modelName);
|
||||
if (modelTypeVos == null) {
|
||||
return ApiResponse.successWithMessage("请先创建或导入模型库");
|
||||
}
|
||||
return ApiResponse.success(modelTypeVos);
|
||||
}
|
||||
|
||||
@Operation(summary = "添加模型文件")
|
||||
@ -547,7 +551,7 @@ public class ModelLibraryController {
|
||||
queryWrapper.eq(ModelLibrary::getIsEnable, 1);
|
||||
ModelLibrary modelLibrary = modelLibraryService.getOne(queryWrapper);
|
||||
if (modelLibrary == null) {
|
||||
throw new RuntimeException("请先创建或导入模型库");
|
||||
return null;
|
||||
}
|
||||
return modelLibrary.getPath();
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Tag(name = "地图文件管理")
|
||||
@RestController
|
||||
@ -27,12 +28,22 @@ public class PbfInfoController {
|
||||
|
||||
@Operation(summary = "添加地图文件")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse add(@Parameter(description = "地图文件路径") @RequestParam(required = true) String path) {
|
||||
public ApiResponse add(@Parameter(description = "地图文件路径列表") @RequestParam(required = true) List<String> paths) {
|
||||
// 批量转换为PbfInfo对象
|
||||
List<PbfInfo> pbfInfoList = paths.stream()
|
||||
.map(path -> {
|
||||
PbfInfo pbfInfo = new PbfInfo();
|
||||
pbfInfo.setPath(path);
|
||||
pbfInfo.setName(FileUtil.mainName(path));
|
||||
pbfInfo.setIsEnable(0);
|
||||
pbfInfoService.save(pbfInfo);
|
||||
return pbfInfo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 批量保存
|
||||
pbfInfoService.saveBatch(pbfInfoList);
|
||||
|
||||
// 返回成功结果
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@ -83,6 +94,4 @@ public class PbfInfoController {
|
||||
graphHopperController.clearMap();
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ import java.io.File;
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "POI文件管理")
|
||||
@ -27,14 +28,22 @@ public class PoiInfoController {
|
||||
@Resource
|
||||
private PoiInfoService poiInfoService;
|
||||
|
||||
@Operation(summary = "添加POI文件")
|
||||
@Operation(summary = "批量添加POI文件")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse add(@Parameter(description = "POI文件路径") @RequestParam(required = true) String path) {
|
||||
public ApiResponse add(@Parameter(description = "POI文件路径列表") @RequestParam(required = true) List<String> paths) {
|
||||
// 批量转换为PoiInfo对象
|
||||
List<PoiInfo> poiInfoList = paths.stream()
|
||||
.map(path -> {
|
||||
PoiInfo poiInfo = new PoiInfo();
|
||||
poiInfo.setPath(path);
|
||||
poiInfo.setName(FileUtil.mainName(path));
|
||||
poiInfo.setIsEnable(0);
|
||||
poiInfoService.save(poiInfo);
|
||||
return poiInfo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 批量保存
|
||||
poiInfoService.saveBatch(poiInfoList);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@ -57,7 +66,7 @@ public class PoiInfoController {
|
||||
|
||||
@Operation(summary = "启用POI文件")
|
||||
@PostMapping("/enable")
|
||||
public ApiResponse enable(@Parameter(description = "地图文件ID") @RequestParam(required = true) String id) {
|
||||
public ApiResponse enable(@Parameter(description = "POI文件ID") @RequestParam(required = true) String id) {
|
||||
PoiInfo poiInfo = poiInfoService.getById(id);
|
||||
poiInfo.setIsEnable(1);
|
||||
poiInfoService.updateById(poiInfo);
|
||||
@ -74,7 +83,7 @@ public class PoiInfoController {
|
||||
|
||||
@Operation(summary = "禁用POI文件")
|
||||
@PostMapping("/disable")
|
||||
public ApiResponse disable(@Parameter(description = "地图文件ID") @RequestParam(required = true) String id) {
|
||||
public ApiResponse disable(@Parameter(description = "POI文件ID") @RequestParam(required = true) String id) {
|
||||
PoiInfo poiInfo = new PoiInfo();
|
||||
poiInfo.setId(id);
|
||||
poiInfo.setIsEnable(0);
|
||||
@ -84,10 +93,7 @@ public class PoiInfoController {
|
||||
|
||||
@Operation(summary = "POI搜索")
|
||||
@GetMapping("/search")
|
||||
public ApiResponse search(
|
||||
@Parameter(description = "分页页码") Integer pageNum,
|
||||
@Parameter(description = "分页大小") Integer pageSize,
|
||||
@Parameter(description = "名称搜索") String name) {
|
||||
public ApiResponse search(@Parameter(description = "分页页码") Integer pageNum, @Parameter(description = "分页大小") Integer pageSize, @Parameter(description = "名称搜索") String name) {
|
||||
int offset = (pageNum - 1) * pageSize;
|
||||
// 查询启用的POI文件
|
||||
PoiInfo poiInfo = poiInfoService.getOne(new QueryWrapper<PoiInfo>().lambda().eq(PoiInfo::getIsEnable, 1));
|
||||
|
||||
@ -26,6 +26,8 @@ import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
@ -186,11 +188,21 @@ public class SourceController {
|
||||
queryWrapper.eq(Source::getId, updateLevelDto.getId());
|
||||
Source source = sourceService.getOne(queryWrapper);
|
||||
String params = source.getParams();
|
||||
if (params != null) {
|
||||
// 修改这个 JSON 的值
|
||||
params = JsonUtil.modifyJsonValue(params, "layerIndex", updateLevelDto.getLayerIndex());
|
||||
source.setParams(params);
|
||||
sourceService.updateById(source);
|
||||
}
|
||||
// 否则是新增
|
||||
if (params == null) {
|
||||
Map<String, Object> paramsMap = new HashMap<>();
|
||||
paramsMap.put("layerIndex", updateLevelDto.getLayerIndex());
|
||||
paramsMap.put("id", updateLevelDto.getId());
|
||||
source.setParams(MapUtil.mapToString(paramsMap));
|
||||
sourceService.updateById(source);
|
||||
}
|
||||
}
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@ -250,53 +262,67 @@ public class SourceController {
|
||||
|
||||
@PostMapping("/uploadLocationImage")
|
||||
@Operation(summary = "新增定位图片")
|
||||
public ApiResponse uploadLocationImage(@RequestParam("ids") @Parameter(description = "上传定位图片ID列表") List<String> ids,
|
||||
public ApiResponse uploadLocationImage(
|
||||
@RequestParam("ids") @Parameter(description = "上传定位图片ID列表") List<String> 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) {
|
||||
// 验证并转换参数
|
||||
@RequestParam("filePaths") @Parameter(description = "图片文件绝对路径列表", required = true) List<String> filePaths) {
|
||||
|
||||
sourceParamsValidator.validateAndConvert(
|
||||
sourceType,
|
||||
JsonUtil.jsonToMap(params)
|
||||
);
|
||||
|
||||
// 检查是否有重复的filePath
|
||||
for (String filePath : filePaths) {
|
||||
// 检查数据库中是否已存在该文件路径
|
||||
boolean exists = sourceService.lambdaQuery()
|
||||
.eq(Source::getSourcePath, filePath)
|
||||
.eq(Source::getIsShow, SHOW)
|
||||
.exists();
|
||||
|
||||
if (exists) {
|
||||
return ApiResponse.failure("数据库存在参数中部分文件路径、不允许重复上传:" + filePath);
|
||||
}
|
||||
}
|
||||
|
||||
List<Source> sources = new ArrayList<>();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
Map<String, Object> dataMap = fileInfoService.handleLocationImageUpload(files[i]);
|
||||
// 构建并保存资源对象
|
||||
for (int i = 0; i < filePaths.size(); i++) {
|
||||
String filePath = filePaths.get(i);
|
||||
File file = new File(filePath);
|
||||
|
||||
try {
|
||||
Map<String, Object> dataMap = fileInfoService.handleLocationImageUpload(file);
|
||||
Source source = new Source();
|
||||
source.setSourcePath(filePath);
|
||||
source.setId(ids.get(i));
|
||||
source.setSourceName(files[i].getOriginalFilename());
|
||||
source.setSourceName(Paths.get(filePath).getFileName().toString());
|
||||
source.setParentId(parentId);
|
||||
source.setSourceType(sourceType);
|
||||
source.setTreeIndex(treeIndex);
|
||||
|
||||
// 转换为对象
|
||||
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());
|
||||
point.setName(Paths.get(filePath).getFileName().toString());
|
||||
point.getLabel().setText(Paths.get(filePath).getFileName().toString());
|
||||
// 解析经纬度、海拔
|
||||
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);
|
||||
|
||||
// 根据资源类型设置链接/VR内容
|
||||
if ("linkImage".equals(sourceType)) {
|
||||
// 设置地址
|
||||
List<Point.Attribute.Link.LinkContent> list = new ArrayList<>();
|
||||
Point.Attribute.Link.LinkContent linkContent = new Point.Attribute.Link.LinkContent();
|
||||
linkContent.setName("带定位照片");
|
||||
@ -311,15 +337,17 @@ public class SourceController {
|
||||
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);
|
||||
} catch (Exception e) {
|
||||
return ApiResponse.failure("处理文件失败:" + filePath + ",原因:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
return ApiResponse.success(sources);
|
||||
}
|
||||
|
||||
@ -71,10 +71,11 @@ public class TsPlanController {
|
||||
}
|
||||
|
||||
private TsSource createSourceIfNotExists(String sourceName, String sourceType, String parentId, int treeIndex, int isShow, String tsPlanId) {
|
||||
// 检查资源是否已存在(通过名称和父ID组合判断唯一性)
|
||||
// 检查资源是否已存在(通过名称和父ID和计划ID组合判断唯一性)
|
||||
TsSource existingSource = tsSourceService.getOne(new LambdaQueryWrapper<TsSource>()
|
||||
.eq(TsSource::getSourceName, sourceName)
|
||||
.eq(parentId != null, TsSource::getParentId, parentId)
|
||||
.eq(TsSource::getPlanId, tsPlanId)
|
||||
.isNull(parentId == null, TsSource::getParentId));
|
||||
if (existingSource != null) {
|
||||
return existingSource;
|
||||
@ -128,21 +129,24 @@ public class TsPlanController {
|
||||
@Parameter(description = "开始时间") @RequestParam(required = false) String startTime,
|
||||
@Parameter(description = "结束时间") @RequestParam(required = false) String endTime) {
|
||||
LambdaQueryWrapper<TsPlan> queryWrapper = new LambdaQueryWrapper<>();
|
||||
// 创建人昵称模糊查询
|
||||
if (StringUtils.isNotBlank(nickname)) {
|
||||
LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<User>()
|
||||
.select(User::getId)
|
||||
.like(User::getNickname, nickname);
|
||||
List<String> userIds = userService.list(userQueryWrapper).stream()
|
||||
.map(User::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (userIds.isEmpty()) {
|
||||
// 返回空数据
|
||||
return ApiResponse.success(new Page<TsPlan>());
|
||||
}
|
||||
}
|
||||
|
||||
// 方案名称模糊查询
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
queryWrapper.like(TsPlan::getName, name);
|
||||
}
|
||||
|
||||
// 创建人昵称模糊查询
|
||||
if (StringUtils.isNotBlank(nickname)) {
|
||||
queryWrapper.in(TsPlan::getCreatedBy,
|
||||
new LambdaQueryWrapper<User>()
|
||||
.select(User::getId)
|
||||
.like(User::getNickname, nickname)
|
||||
);
|
||||
}
|
||||
|
||||
// 时间范围查询
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
try {
|
||||
@ -154,36 +158,17 @@ public class TsPlanController {
|
||||
LocalDateTime end = LocalDateTime.parse(endTime, formatter);
|
||||
queryWrapper.le(TsPlan::getCreatedAt, end);
|
||||
}
|
||||
} catch (DateTimeParseException e) {
|
||||
} catch (
|
||||
DateTimeParseException e) {
|
||||
return ApiResponse.failure("时间格式错误、需为 yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
// 执行分页查询
|
||||
Page<TsPlan> page = tsPlanService.page(new Page<>(pageNum, pageSize), queryWrapper);
|
||||
|
||||
// 关联查询用户信息并封装结果
|
||||
if (!page.getRecords().isEmpty()) {
|
||||
List<String> creatorIds = page.getRecords().stream()
|
||||
.map(TsPlan::getCreatedBy)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!creatorIds.isEmpty()) {
|
||||
List<User> creators = userService.listByIds(creatorIds);
|
||||
Map<String, String> creatorNicknameMap = creators.stream()
|
||||
.collect(Collectors.toMap(
|
||||
User::getId,
|
||||
user -> user.getNickname() != null ? user.getNickname() : "未知昵称",
|
||||
(k1, k2) -> k1
|
||||
));
|
||||
|
||||
page.getRecords().forEach(plan -> {
|
||||
plan.setCreatedBy(creatorNicknameMap.getOrDefault(plan.getCreatedBy(), "未知用户"));
|
||||
});
|
||||
List<TsPlan> records = page.getRecords();
|
||||
for (TsPlan record : records) {
|
||||
record.setCreatedBy(userService.getById(record.getCreatedBy()).getNickname());
|
||||
}
|
||||
}
|
||||
|
||||
return ApiResponse.success(page);
|
||||
}
|
||||
|
||||
|
||||
@ -2,14 +2,17 @@ package com.yj.earth.business.controller;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.yj.earth.business.domain.Source;
|
||||
import com.yj.earth.business.domain.TsSource;
|
||||
import com.yj.earth.business.service.TsSourceService;
|
||||
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.DragSourceDto;
|
||||
import com.yj.earth.dto.tsPlan.BatchUpdateShowStatusDto;
|
||||
import com.yj.earth.dto.tsSource.AddTsModelSourceDto;
|
||||
import com.yj.earth.dto.tsSource.AddTsSourceDto;
|
||||
import com.yj.earth.dto.tsSource.DragTsSourceDto;
|
||||
import com.yj.earth.dto.tsSource.UpdateTsSourceDto;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@ -68,6 +71,20 @@ public class TsSourceController {
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@Operation(summary = "拖动资源")
|
||||
@PostMapping("/dragSource")
|
||||
public ApiResponse drag(@RequestBody List<DragTsSourceDto> dragTsSourceDtoList) {
|
||||
for (DragTsSourceDto dragTsSourceDto : dragTsSourceDtoList) {
|
||||
LambdaQueryWrapper<TsSource> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(TsSource::getId, dragTsSourceDto.getId());
|
||||
TsSource tsSource = tsSourceService.getOne(queryWrapper);
|
||||
tsSource.setTreeIndex(dragTsSourceDto.getTreeIndex());
|
||||
tsSource.setParentId(dragTsSourceDto.getParentId());
|
||||
tsSourceService.updateById(tsSource);
|
||||
}
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询某个方案下的态势资源")
|
||||
@PostMapping("/query")
|
||||
public ApiResponse query(@Parameter(description = "态势方案ID") @RequestParam(required = true) String id) {
|
||||
|
||||
@ -32,6 +32,9 @@ public class TsPlan implements Serializable {
|
||||
@Schema(description = "创建人")
|
||||
private String createdBy;
|
||||
|
||||
@Schema(description = "滑轮")
|
||||
private Integer wheel;
|
||||
|
||||
@Schema(description = "仿真开始时间")
|
||||
private LocalDateTime simulationStartTime;
|
||||
|
||||
|
||||
@ -5,12 +5,14 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
public interface FileInfoService extends IService<FileInfo> {
|
||||
// 根据文件ID获取文件绝对路径
|
||||
String getFileAbsolutePath(String id);
|
||||
Map<String, Object> handleLocationImageUpload(MultipartFile file);
|
||||
Map<String, Object> handleLocationImageUpload(File file);
|
||||
String uploadWithPreview(MultipartFile file);
|
||||
void writeResponseMessage(HttpServletResponse response, String message);
|
||||
String getFullUploadPath();
|
||||
|
||||
@ -104,6 +104,62 @@ public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> i
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Object> handleLocationImageUpload(File file) {
|
||||
// 构建并返回结果
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
if (file == null || !file.exists()) {
|
||||
throw new IllegalArgumentException("文件不存在");
|
||||
}
|
||||
if (file.length() == 0) {
|
||||
throw new IllegalArgumentException("上传文件不能为空(空文件)");
|
||||
}
|
||||
|
||||
// 原始文件名
|
||||
String originalFilename = file.getName();
|
||||
// 文件后缀
|
||||
String fileSuffix = FileUtil.extName(originalFilename);
|
||||
// 文件MIME类型
|
||||
String contentType = Files.probeContentType(file.toPath());
|
||||
|
||||
if (contentType == null || !contentType.startsWith("image/")) {
|
||||
throw new IllegalArgumentException("请上传图片文件,当前文件类型:" + contentType);
|
||||
}
|
||||
|
||||
// 获取完整的上传目录路径
|
||||
Path fullUploadPath = Paths.get(getFullUploadPath());
|
||||
// 生成唯一文件名
|
||||
String uniqueFileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + fileSuffix;
|
||||
// 创建文件存储目录(不存在则创建)
|
||||
Files.createDirectories(fullUploadPath);
|
||||
// 构建目标文件路径
|
||||
Path destFilePath = fullUploadPath.resolve(uniqueFileName);
|
||||
// 覆盖已存在的文件
|
||||
Files.copy(file.toPath(), destFilePath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||
String fileMd5 = calculateFileMd5(destFilePath.toFile());
|
||||
Map<String, Double> 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.length());
|
||||
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();
|
||||
try {
|
||||
|
||||
@ -95,12 +95,19 @@ public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> impleme
|
||||
public Source addModelSource(AddModelSourceDto addModelSourceDto) {
|
||||
// 获取资源绝对路径
|
||||
String sourcePath = addModelSourceDto.getSourcePath();
|
||||
// 判断数据是否在数据库存在
|
||||
LambdaQueryWrapper<Source> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Source::getSourcePath, sourcePath);
|
||||
if (sourceService.count(queryWrapper) > 0) {
|
||||
throw new RuntimeException("资源已存在");
|
||||
}
|
||||
|
||||
// 获取资源名称
|
||||
String sourceName = FileUtil.mainName(sourcePath);
|
||||
// 校验是否通过
|
||||
String message = sourceService.checkIsPass(addModelSourceDto.getParentId(), sourceName);
|
||||
if (message != null) {
|
||||
return null;
|
||||
throw new RuntimeException("父节点不存在");
|
||||
}
|
||||
// 调用SDK加载资源
|
||||
String sourceId = sourceService.addAndGetSourceId(sourcePath);
|
||||
|
||||
@ -31,7 +31,9 @@ public class SaTokenConfig implements WebMvcConfigurer {
|
||||
excludePathPatterns.add("/iconLibrary/data/icon/**");
|
||||
excludePathPatterns.add("/militaryLibrary/data/military/**");
|
||||
excludePathPatterns.add("/modelLibrary/data/**");
|
||||
excludePathPatterns.add("/**");
|
||||
excludePathPatterns.add("/auth/show");
|
||||
excludePathPatterns.add("/auth/info");
|
||||
excludePathPatterns.add("/auth/import");
|
||||
|
||||
// 注册 Sa-Token 拦截器
|
||||
registry.addInterceptor(new SaInterceptor(handle -> {
|
||||
|
||||
@ -39,7 +39,7 @@ public class ServerInitService {
|
||||
for (Source source : list) {
|
||||
// 同步资源
|
||||
sourceService.getDetail(source.getSourcePath(), sourceService.addAndGetSourceId(source.getSourcePath()));
|
||||
log.info("初始化资源<--{}-->完成", source.getSourceName());
|
||||
log.info("初始化资源 <--{}--> 完成", source.getSourceName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,8 @@ public class TsPlan {
|
||||
private String name;
|
||||
@Schema(description = "方案描述")
|
||||
private String desc;
|
||||
@Schema(description = "滑轮")
|
||||
private Integer wheel;
|
||||
@Schema(description = "创建人")
|
||||
private String createdBy;
|
||||
@Schema(description = "仿真开始时间")
|
||||
|
||||
@ -11,6 +11,8 @@ public class AddTsPlanDto {
|
||||
private String name;
|
||||
@Schema(description = "方案描述")
|
||||
private String desc;
|
||||
@Schema(description = "滑轮")
|
||||
private Integer wheel;
|
||||
@Schema(description = "仿真开始时间")
|
||||
private LocalDateTime simulationStartTime;
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@ public class UpdateTsPlanDto {
|
||||
private String name;
|
||||
@Schema(description = "方案描述")
|
||||
private String desc;
|
||||
@Schema(description = "滑轮")
|
||||
private Integer wheel;
|
||||
@Schema(description = "仿真开始时间")
|
||||
private LocalDateTime simulationStartTime;
|
||||
}
|
||||
|
||||
16
src/main/java/com/yj/earth/dto/tsSource/DragTsSourceDto.java
Normal file
16
src/main/java/com/yj/earth/dto/tsSource/DragTsSourceDto.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.yj.earth.dto.tsSource;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DragTsSourceDto {
|
||||
@Schema(description = "主键")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "父级ID")
|
||||
private String parentId;
|
||||
|
||||
@Schema(description = "树形索引")
|
||||
private Integer treeIndex;
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.yj.earth.params;
|
||||
|
||||
import com.yj.earth.annotation.SourceType;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -22,6 +23,7 @@ public class MilitaryParam {
|
||||
private Attribute attribute;
|
||||
private String attributeType;
|
||||
private Text text;
|
||||
private CustomView customView;
|
||||
|
||||
@Data
|
||||
public static class Position {
|
||||
@ -63,4 +65,26 @@ public class MilitaryParam {
|
||||
private int far;
|
||||
private Position position;
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class CustomView {
|
||||
private LinkImage.CustomView.Orientation orientation;
|
||||
private LinkImage.CustomView.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,6 @@ public class Vector {
|
||||
private List<Object> headTables;
|
||||
private boolean show;
|
||||
private String color;
|
||||
private double opacity;
|
||||
private Double opacity;
|
||||
private Object customView;
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
package com.yj.earth.vo;
|
||||
|
||||
import com.yj.earth.business.domain.Icon;
|
||||
import com.yj.earth.business.domain.Military;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user