package com.ruoyi.airline.service.impl; import com.ruoyi.airline.domain.api.IAirlineFileDomain; import com.ruoyi.airline.domain.model.AirlineFile; import com.ruoyi.airline.domain.model.kml.KmlInfo; import com.ruoyi.airline.domain.uitl.KmlFileUtils; import com.ruoyi.airline.domain.uitl.WayPointUitls; import com.ruoyi.airline.service.api.IAirlineFileService; import com.ruoyi.airline.service.convert.AirlineFileServiceConvert; import com.ruoyi.airline.service.dto.AirLinePointDTO; import com.ruoyi.airline.service.dto.AirlineFileDTO; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.exception.base.BaseException; import com.ruoyi.common.core.utils.file.FileUtils; import com.ruoyi.system.api.RemoteFileService; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.UUID; /** * 航线文件Service实现类 * * @author ruoyi * @date 2026-01-17 */ @Service public class AirlineFileServiceImpl implements IAirlineFileService { private static final Logger log = LoggerFactory.getLogger(AirlineFileServiceImpl.class); @Autowired private RemoteFileService remoteFileService; @Autowired private IAirlineFileDomain iAirlineFileDomain; @Override public AirlineFileDTO save(AirlineFileDTO dto) { AirlineFile model = AirlineFileServiceConvert.toModel(dto); Long id = iAirlineFileDomain.save(model); dto.setId(id); return dto; } /** * 上传航线文件,如果是KMZ的需要转换成 waypoint 的,并且需要将 原始航线文件保存。 * 并且限制航线修改,因为暂时没做到 从waypoingt 转 KMZ * * @param file * @return */ @Override public AirlineFileDTO parseAndUplload(MultipartFile file) { String originalFilename = file.getOriginalFilename(); String fileExtension = ""; if (originalFilename != null && originalFilename.lastIndexOf('.') > 0) { fileExtension = originalFilename.substring(originalFilename.lastIndexOf('.') + 1).toLowerCase(); } try { if ("zip".equals(fileExtension) || "kmz".equals(fileExtension)) { // 处理ZIP/KMZ文件 KmlInfo kmlInfo = new KmlInfo(); try (ArchiveInputStream archiveInputStream = new ZipArchiveInputStream(file.getInputStream());) { ArchiveEntry entry; while (!Objects.isNull(entry = archiveInputStream.getNextEntry())) { String name = entry.getName(); if (name.toLowerCase().endsWith(".kml")) { // 解KML文件 kmlInfo = KmlFileUtils.parseKml(archiveInputStream); } } if (Objects.isNull(kmlInfo)) { throw new BaseException("kmz文件内容缺失"); } String globalHeight = kmlInfo.getDocument().getFolder().getGlobalHeight(); R fileUrl = remoteFileService.uploadFileByData(UUID.randomUUID().toString(), "waypoints", WayPointUitls.kmz2waypoint(kmlInfo)); AirlineFileDTO dto = new AirlineFileDTO(); // 去除文件名中的后缀名 int pos = originalFilename.lastIndexOf("."); String fileNameWithoutExtension = pos > 0 ? originalFilename.substring(0, pos) : originalFilename; List airlineFiles =iAirlineFileDomain.selectFileNameLike(fileNameWithoutExtension); List fileNames = airlineFiles.stream().map(AirlineFile::getName).toList(); String newFileName = FileUtils.generateUniqueFileName(fileNameWithoutExtension, fileNames); dto.setFileName(newFileName); dto.setFileUrl(fileUrl.getData()); dto.setAirVendor(kmlInfo.getDocument().getKmlMissionConfig().getDroneInfo().getDroneEnumValue()); dto.setAirType(kmlInfo.getDocument().getKmlMissionConfig().getDroneInfo().getDroneEnumValue()); return dto; } } else if ("waypoints".equals(fileExtension)) { // 直接处理Waypoints文件 AirlineFileDTO dto = new AirlineFileDTO(); // 去除文件名中的后缀名 int pos = originalFilename.lastIndexOf("."); String fileNameWithoutExtension = pos > 0 ? originalFilename.substring(0, pos) : originalFilename; List airlineFiles =iAirlineFileDomain.selectFileNameLike(fileNameWithoutExtension); List fileNames = airlineFiles.stream().map(AirlineFile::getName).toList(); String newFileName = FileUtils.generateUniqueFileName(fileNameWithoutExtension, fileNames); dto.setFileName(newFileName); // 直接读取文件内容并上传 R fileUrl = remoteFileService.uploadFileByData(UUID.randomUUID().toString(), "waypoints", Arrays.toString(file.getBytes())); dto.setFileUrl(fileUrl.getData()); dto.setAirVendor(""); dto.setAirType(""); return dto; } else { throw new BaseException("不支持的文件格式,请上传KMZ或Waypoints文件"); } } catch (IOException e) { throw new BaseException("文件处理失败"); } catch (Exception e) { log.error("航线文件处理失败", e); throw new BaseException("航线文件处理失败"); } } /** * 航点编辑,直接将大疆KMZ转换成waypoints操作,就不需要区分大疆还是拓恒了 * * @param airlineFile 航线文件dto * @return */ @Override public AirlineFileDTO createOrupdate(AirlineFileDTO airlineFile) { StringBuilder waypointBuilder = new StringBuilder("QGC WPL 110\n"); List LineDto = airlineFile.getLinePointDtoList(); // 新建字节输出流,Freemarker操作此输出流写入生成的业务文件. if (LineDto != null && !LineDto.isEmpty()) { for (int i = 0; i < LineDto.size(); i++) { AirLinePointDTO point = LineDto.get(i); waypointBuilder.append(WayPointUitls.formatWaypointLine(point, i)).append("\n"); } // 上传文件 R fileUrl = remoteFileService.uploadFileByData(UUID.randomUUID().toString(), "waypoints", waypointBuilder.toString()); //保存航线文件数据 airlineFile.setFileUrl(fileUrl.getData()); airlineFile.setSource("airport"); airlineFile.setStatus(airlineFile.getStatus() == null ? 1 : airlineFile.getStatus()); AirlineFile model = AirlineFileServiceConvert.toModel(airlineFile); Long id = iAirlineFileDomain.save(model); model.setId(id); return AirlineFileServiceConvert.toDTO(model); } return null; } @Override public AirlineFile selectById(Long airlineId) { if (airlineId == null) { return null; } List ids = List.of(airlineId); List airlineFiles = iAirlineFileDomain.selectFileListByIds(ids); return airlineFiles != null && !airlineFiles.isEmpty() ? airlineFiles.get(0) : null; } }