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.to(dto); Long id = iAirlineFileDomain.save(model); dto.setId(id); return dto; } /** * 上传航线文件,如果是KMZ的需要转换成 waypoint 的,并且需要将 原始航线文件保存。 * 并且限制航线修改,因为暂时没做到 从waypoingt 转 KMZ * * @param file * @param groupId * @return */ @Override public AirlineFileDTO parseAndUplload(MultipartFile file, Long groupId) { String originalFilename = file.getOriginalFilename(); String fileExtension = ""; if (originalFilename != null && originalFilename.lastIndexOf('.') > 0) { fileExtension = originalFilename.substring(originalFilename.lastIndexOf('.') + 1).toLowerCase(); } int pos = 0; if (originalFilename != null) { pos = originalFilename.lastIndexOf("."); } String fileNameWithoutExtension = pos > 0 ? originalFilename.substring(0, pos) : originalFilename; String newFileName = getNewFileNameLikeByGroupId(fileNameWithoutExtension, groupId); log.info("filename :{}, new filename :{}",fileNameWithoutExtension, newFileName); 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(); AirlineFileDTO dto = new AirlineFileDTO(); // 去除文件名中的后缀名 dto.setName(newFileName); dto.setFileName(originalFilename); R fileUrl = remoteFileService.uploadFileByData(UUID.randomUUID().toString(), "waypoints", WayPointUitls.kmz2waypoint(kmlInfo)); dto.setFileUrl(fileUrl.getData()); dto.setType(kmlInfo.getDocument().getFolder().getTemplateType()); // TODO 大疆默认1,后续想办法优化成表格破诶中 String airVendor = "1"; String airType = kmlInfo.getDocument().getKmlMissionConfig().getDroneInfo().getDroneEnumValue(); String airSubType = kmlInfo.getDocument().getKmlMissionConfig().getDroneInfo().getDroneSubEnumValue(); dto.setAirVendor(airVendor); // 无人机的领域默认为0 dto.setAirType(String.format("0-%s-%s", airType, airSubType)); return dto; } } else if ("waypoints".equals(fileExtension)) { // 直接处理Waypoints文件 AirlineFileDTO dto = new AirlineFileDTO(); // 去除文件名中的后缀名 dto.setName(newFileName); dto.setFileName(originalFilename); // 直接读取文件内容并上传 R fileUrl = remoteFileService.uploadFileByData(UUID.randomUUID().toString(), "waypoints", new String(file.getBytes())); dto.setFileUrl(fileUrl.getData()); // TODO 拓恒默认0,后续想办法优化成表格破诶中 String airVendor = "0"; String airType = "0"; String airSubType = "1"; // 默认Fm003,的type为1 dto.setAirVendor(airVendor); // 无人机的领域默认为0 dto.setAirType(String.format("0-%s-%s", airType, airSubType)); 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.to(airlineFile); Long id = iAirlineFileDomain.save(model); model.setId(id); return AirlineFileServiceConvert.from(model); } return null; } @Override public AirlineFileDTO selectById(Long airlineId) { if (airlineId == null) { return null; } List ids = List.of(airlineId); List airlineFiles = iAirlineFileDomain.selectFileListByIds(ids); List airlineFilesDTO = AirlineFileServiceConvert.fromList(airlineFiles); return airlineFilesDTO != null && !airlineFilesDTO.isEmpty() ? airlineFilesDTO.get(0) : null; } @Override public String getNewFileNameLikeByGroupId(String name, Long groupId) { List airlineFiles = iAirlineFileDomain.selectFileNameLikeByGroupId(name, groupId); String newFileName = name; if (airlineFiles != null && !airlineFiles.isEmpty()) { List fileNames = airlineFiles.stream().map(AirlineFile::getName).toList(); newFileName = FileUtils.generateUniqueFileName(name, fileNames); } return newFileName; } @Override public Long update(AirlineFileDTO dto) { AirlineFile model = AirlineFileServiceConvert.to(dto); return iAirlineFileDomain.update(model); } }