增加导入航线(未测试)
This commit is contained in:
parent
86aabebb80
commit
f4e0dae1b7
|
|
@ -2,11 +2,15 @@ package com.multictrl.common.utils.kmz;
|
|||
|
||||
import com.multictrl.common.exception.RenException;
|
||||
import com.multictrl.modules.business.dto.RouteDTO;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
|
@ -96,4 +100,90 @@ public class KmzUtils {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 KMZ 文件,提取指定内容为 byte[]
|
||||
*
|
||||
* @param inputStream KMZ 文件流
|
||||
* @return 包含文件名与 byte[] 的映射
|
||||
* @throws IOException IO 异常
|
||||
*/
|
||||
public static Map<String, byte[]> extractKmzAsBytes(InputStream inputStream) throws IOException {
|
||||
Map<String, byte[]> result = new HashMap<>();
|
||||
|
||||
try (ZipArchiveInputStream zipStream = new ZipArchiveInputStream(inputStream)) {
|
||||
ZipArchiveEntry entry;
|
||||
while ((entry = zipStream.getNextEntry()) != null) {
|
||||
String entryName = entry.getName();
|
||||
|
||||
if (WPMZ_TEMPLATE_KML.equals(entryName)) {
|
||||
result.put("template.kml", readStreamToBytes(zipStream));
|
||||
} else if (WPMZ_WAYLINES_WPML.equals(entryName)) {
|
||||
result.put("waylines.wpml", readStreamToBytes(zipStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 InputStream 读取为 byte[]
|
||||
*
|
||||
* @param inputStream 输入流
|
||||
* @return 字节数组
|
||||
* @throws IOException IO 异常
|
||||
*/
|
||||
private static byte[] readStreamToBytes(InputStream inputStream) throws IOException {
|
||||
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
|
||||
byte[] data = new byte[1024];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, bytesRead);
|
||||
}
|
||||
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 zip 输入流解压到目标目录,完整保留 zip 内的目录结构。
|
||||
*
|
||||
* @param zipStream zip 输入流(调用方负责关闭外层流)
|
||||
* @param destDir 目标目录
|
||||
* @throws IOException 解压失败
|
||||
*/
|
||||
public static void unzipToDirectory(InputStream zipStream, File destDir) throws Exception {
|
||||
if (!destDir.exists()) {
|
||||
Files.createDirectories(destDir.toPath());
|
||||
}
|
||||
|
||||
try (ZipInputStream zis = new ZipInputStream(zipStream)) {
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
String entryName = entry.getName();
|
||||
File targetFile = new File(destDir, entryName);
|
||||
Path targetPath = targetFile.getCanonicalFile().toPath();
|
||||
Path destPath = destDir.getCanonicalFile().toPath();
|
||||
if (!targetPath.startsWith(destPath)) {
|
||||
throw new RenException("非法路径:" + entryName);
|
||||
}
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
Files.createDirectories(targetFile.toPath());
|
||||
} else {
|
||||
Files.createDirectories(targetFile.getParentFile().toPath());
|
||||
try (FileOutputStream fos = new FileOutputStream(targetFile)) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
while ((len = zis.read(buffer)) > 0) {
|
||||
fos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,279 @@
|
|||
package com.multictrl.common.utils.kmz;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.multictrl.common.constant.BusinessConstant;
|
||||
import com.multictrl.common.constant.SetActionParams;
|
||||
import com.multictrl.common.exception.RenException;
|
||||
import com.multictrl.modules.business.dto.RouteDTO;
|
||||
import com.multictrl.modules.business.dto.RouteWaypointDTO;
|
||||
import com.multictrl.modules.business.dto.WaypointActionDTO;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* kml解析
|
||||
*
|
||||
* @author Sdy
|
||||
* @since 1.0.0 2026/6/18
|
||||
*/
|
||||
public class WpmlKmlParser {
|
||||
|
||||
public static RouteDTO parseKmlFile(byte[] bytes, Boolean accurateImport) throws DocumentException {
|
||||
RouteDTO dto = new RouteDTO();
|
||||
SAXReader reader = new SAXReader();
|
||||
Document document = reader.read(new ByteArrayInputStream(bytes));
|
||||
Element root = document.getRootElement();
|
||||
|
||||
Element doc = root.element("Document");
|
||||
if (doc == null) {
|
||||
throw new RenException("kml文件有误,无法解析");
|
||||
}
|
||||
Element folder = doc.element("Folder");
|
||||
if (folder == null) {
|
||||
throw new RenException("模板信息不存在,无法解析");
|
||||
}
|
||||
//解析高度模式
|
||||
Element waylineCoordinateSysParam = folder.element("waylineCoordinateSysParam");
|
||||
if (waylineCoordinateSysParam == null) {
|
||||
if (!accurateImport) {
|
||||
throw new RenException("坐标系参数有误,无法解析");
|
||||
}
|
||||
} else {
|
||||
String heightMode = filedValid(waylineCoordinateSysParam.elementText("heightMode"), accurateImport);
|
||||
dto.setHeightModel(heightMode);
|
||||
}
|
||||
|
||||
// 解析
|
||||
String templateType = folder.elementText("templateType");
|
||||
if (StringUtils.isEmpty(templateType) && accurateImport) {
|
||||
return dto;
|
||||
}
|
||||
if (StringUtils.isEmpty(templateType) && !accurateImport) {
|
||||
throw new RenException("模板类型不存在,解析失败");
|
||||
}
|
||||
dto.setTemplateType(templateType);
|
||||
String autoFlightSpeed = filedValid(folder.elementText("autoFlightSpeed"), accurateImport);
|
||||
dto.setFlightSpeed(autoFlightSpeed == null ? null : Double.parseDouble(autoFlightSpeed));
|
||||
String globalHeight = filedValid(folder.elementText("globalHeight"), accurateImport);
|
||||
dto.setFlightHeight(globalHeight == null ? null : Double.parseDouble(globalHeight));
|
||||
|
||||
List<RouteWaypointDTO> waypointList = new ArrayList<>();
|
||||
List<Element> placemarks = folder.elements("Placemark");
|
||||
if (CollectionUtil.isEmpty(placemarks)) {
|
||||
if (accurateImport) {
|
||||
dto.setRouteWaypointList(waypointList);
|
||||
} else {
|
||||
throw new RenException("航点信息不存在,解析失败");
|
||||
}
|
||||
} else {
|
||||
for (Element placemark : placemarks) {
|
||||
RouteWaypointDTO waypoint = new RouteWaypointDTO();
|
||||
String useGlobalSpeed = placemark.elementText("useGlobalSpeed");
|
||||
String useGlobalHeight = placemark.elementText("useGlobalHeight");
|
||||
waypoint.setFollowRouteSpeed(filedValid(useGlobalSpeed, accurateImport) == null ? null : "1".equals(useGlobalSpeed));
|
||||
waypoint.setFollowRouteHeight(filedValid(useGlobalHeight, accurateImport) == null ? null : "1".equals(useGlobalHeight));
|
||||
waypointList.add(waypoint);
|
||||
}
|
||||
dto.setRouteWaypointList(waypointList);
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
|
||||
public static void parseWpmlFile(byte[] bytes, RouteDTO dto, Boolean accurateImport) throws DocumentException, IOException {
|
||||
SAXReader reader = new SAXReader();
|
||||
Document document = reader.read(new ByteArrayInputStream(bytes));
|
||||
Element root = document.getRootElement();
|
||||
|
||||
Element doc = root.element("Document");
|
||||
if (doc == null) {
|
||||
throw new RenException("wpml文件有误,无法解析");
|
||||
}
|
||||
Element missionConfig = doc.element("missionConfig");
|
||||
if (missionConfig == null) {
|
||||
throw new RenException("任务信息不存在,无法解析");
|
||||
}
|
||||
dto.setFlyToWaylineMode(filedValid(missionConfig.elementText("flyToWaylineMode"), accurateImport));
|
||||
dto.setFinishAction(filedValid(missionConfig.elementText("finishAction"), accurateImport));
|
||||
String exitOnRCLost = filedValid(missionConfig.elementText("exitOnRCLost"), accurateImport);
|
||||
dto.setExitOnRcLost(exitOnRCLost);
|
||||
if ("executeLostAction".equals(exitOnRCLost)) {
|
||||
dto.setExecuteRcLostAction(filedValid(missionConfig.elementText("executeRCLostAction"), accurateImport));
|
||||
}
|
||||
String takeOffSecurityHeight = filedValid(missionConfig.elementText("takeOffSecurityHeight"), accurateImport);
|
||||
dto.setTakeoffSecurityHeight(StringUtils.isBlank(takeOffSecurityHeight) ? null : Double.parseDouble(missionConfig.elementText("takeOffSecurityHeight")));
|
||||
String globalTransitionalSpeed = filedValid(missionConfig.elementText("globalTransitionalSpeed"), accurateImport);
|
||||
dto.setGlobalTransitionalSpeed(StringUtils.isBlank(globalTransitionalSpeed) ? null : Double.parseDouble(globalTransitionalSpeed));
|
||||
String globalRTHHeight = filedValid(missionConfig.elementText("globalRTHHeight"), accurateImport);
|
||||
dto.setGlobalRthHeight(StringUtils.isBlank(globalRTHHeight) ? null : Double.parseDouble(globalRTHHeight));
|
||||
/*Element droneInfo = missionConfig.element("droneInfo");
|
||||
if (droneInfo == null) {
|
||||
if (!accurateImport) {
|
||||
throw new RenException("飞行器机型信息不存在,无法解析");
|
||||
}
|
||||
} else {
|
||||
String droneEnumValue = filedValid(droneInfo.elementText("droneEnumValue"), accurateImport);
|
||||
String droneSubEnumValue = filedValid(droneInfo.elementText("droneSubEnumValue"), accurateImport);
|
||||
}*/
|
||||
/*Element payloadInfo = missionConfig.element("payloadInfo");
|
||||
if (payloadInfo == null) {
|
||||
if (!accurateImport) {
|
||||
throw new RenException("负载机型信息不存在,无法解析");
|
||||
}
|
||||
} else {
|
||||
String payloadEnumValue = filedValid(payloadInfo.elementText("payloadEnumValue"), accurateImport);
|
||||
String cameraName = CameraModel.getNameByType(payloadEnumValue);
|
||||
dto.setCameraType(cameraName);
|
||||
}*/
|
||||
|
||||
Element folder = doc.element("Folder");
|
||||
if (folder == null) {
|
||||
if (!accurateImport) {
|
||||
throw new RenException("航线信息不存在,无法解析");
|
||||
}
|
||||
} else {
|
||||
String autoFlightSpeed = filedValid(folder.elementText("autoFlightSpeed"), accurateImport);
|
||||
dto.setFlightSpeed(StringUtils.isBlank(autoFlightSpeed) ? null : Double.parseDouble(autoFlightSpeed));
|
||||
|
||||
List<Element> placemarks = folder.elements("Placemark");
|
||||
if (CollectionUtil.isEmpty(placemarks)) {
|
||||
if (!accurateImport) {
|
||||
throw new RenException("航点信息不存在,无法解析");
|
||||
}
|
||||
} else {
|
||||
List<RouteWaypointDTO> waypointList = dto.getRouteWaypointList();
|
||||
if (waypointList == null || waypointList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < waypointList.size(); i++) {
|
||||
RouteWaypointDTO waypoint = waypointList.get(i);
|
||||
Element placemark = placemarks.get(i);
|
||||
Element point = placemark.element("Point");
|
||||
if (point == null) {
|
||||
if (!accurateImport) {
|
||||
throw new RenException("航点经纬度不存在,无法解析");
|
||||
}
|
||||
} else {
|
||||
String coordinates = point.elementText("coordinates");
|
||||
String[] split = coordinates.split(",");
|
||||
waypoint.setLongitude(Double.valueOf(split[0]));
|
||||
waypoint.setLatitude(Double.valueOf(split[1]));
|
||||
}
|
||||
String index = filedValid(placemark.elementText("index"), accurateImport);
|
||||
waypoint.setWaypointSort(StringUtils.isBlank(index) ? null : Integer.valueOf(index));
|
||||
String executeHeight = filedValid(placemark.elementText("executeHeight"), accurateImport);
|
||||
waypoint.setFlightHeight(StringUtils.isBlank(executeHeight) ? null : Double.parseDouble(executeHeight));
|
||||
String waypointSpeed = filedValid(placemark.elementText("waypointSpeed"), accurateImport);
|
||||
waypoint.setFlightSpeed(StringUtils.isBlank(waypointSpeed) ? null : Double.parseDouble(waypointSpeed));
|
||||
Element waypointHeadingParam = placemark.element("waypointHeadingParam");
|
||||
if (waypointHeadingParam == null) {
|
||||
if (!accurateImport) {
|
||||
throw new RenException("偏航角模式参数不存在,无法解析");
|
||||
}
|
||||
} else {
|
||||
waypoint.setWaypointHeadingMode(filedValid(waypointHeadingParam.elementText("waypointHeadingMode"), accurateImport));
|
||||
String waypointHeadingAngle = filedValid(waypointHeadingParam.elementText("waypointHeadingAngle"), accurateImport);
|
||||
if (StrUtil.isNotBlank(waypointHeadingAngle)) {
|
||||
waypoint.setWaypointHeadingAngle(waypointHeadingAngle);
|
||||
}
|
||||
String waypointPoiPoint = waypointHeadingParam.elementText("waypointPoiPoint");
|
||||
if (StrUtil.isNotBlank(waypointPoiPoint)) {
|
||||
waypoint.setWaypointPoiPoint(waypointPoiPoint);
|
||||
}
|
||||
String waypointHeadingPathMode = filedValid(waypointHeadingParam.elementText("waypointHeadingPathMode"), accurateImport);
|
||||
waypoint.setWaypointHeadingPathMode(StringUtils.isBlank(waypointHeadingPathMode) ? "" : waypointHeadingPathMode);
|
||||
}
|
||||
|
||||
Element waypointTurnParam = placemark.element("waypointTurnParam");
|
||||
if (waypointTurnParam == null) {
|
||||
if (!accurateImport) {
|
||||
throw new RenException("航点转弯模式不存在,无法解析");
|
||||
}
|
||||
} else {
|
||||
waypoint.setWaypointTruningMode(filedValid(waypointTurnParam.elementText("waypointTurnMode"), accurateImport));
|
||||
String waypointTurnDampingDist = filedValid(waypointTurnParam.elementText("waypointTurnDampingDist"), accurateImport);
|
||||
if (StrUtil.isNotBlank(waypointTurnDampingDist)) {
|
||||
waypoint.setWaypointTurnDampingDist(waypointTurnDampingDist);
|
||||
}
|
||||
}
|
||||
|
||||
List<WaypointActionDTO> actionList = waypoint.getWaypointActionList();
|
||||
if (CollectionUtil.isEmpty(actionList)) {
|
||||
actionList = new ArrayList<>();
|
||||
}
|
||||
List<Element> actionGroups = placemark.elements("actionGroup");
|
||||
for (Element actionGroup : actionGroups) {
|
||||
Element actionTrigger = actionGroup.element("actionTrigger");
|
||||
String actionTriggerType = actionTrigger.elementText("actionTriggerType");
|
||||
if ("multipleTiming".equals(actionTriggerType) || "multipleDistance".equals(actionTriggerType)) {
|
||||
String actionGroupId = actionGroup.elementText("actionGroupId");
|
||||
String actionTriggerParam = actionTrigger.elementText("actionTriggerParam");
|
||||
WaypointActionDTO action = new WaypointActionDTO();
|
||||
action.setActionType(actionTriggerType);
|
||||
action.setActionValue(actionTriggerParam);
|
||||
action.setActionSort(Integer.parseInt(actionGroupId));
|
||||
actionList.add(action);
|
||||
|
||||
String actionGroupEndIndex = actionGroup.elementText("actionGroupEndIndex");
|
||||
RouteWaypointDTO uavWaypointDTO = waypointList.get(Integer.parseInt(actionGroupEndIndex));
|
||||
List<WaypointActionDTO> actionList1 = uavWaypointDTO.getWaypointActionList();
|
||||
if (CollectionUtil.isEmpty(actionList1)) {
|
||||
actionList1 = new ArrayList<>();
|
||||
}
|
||||
WaypointActionDTO action2 = new WaypointActionDTO();
|
||||
action2.setActionType(BusinessConstant.FINISH_TAKE_PHOTO_FLAG);
|
||||
action2.setActionValue(actionGroupEndIndex);
|
||||
action.setActionSort(Integer.parseInt(actionGroupId));
|
||||
actionList1.add(action2);
|
||||
uavWaypointDTO.setWaypointActionList(actionList1);
|
||||
} else {
|
||||
List<Element> actions = actionGroup.elements("action");
|
||||
for (Element act : actions) {
|
||||
WaypointActionDTO action = new WaypointActionDTO();
|
||||
String actionActuatorFunc = act.elementText("actionActuatorFunc");
|
||||
Element actionActuatorFuncParam = act.element("actionActuatorFuncParam");
|
||||
if ("gimbalRotate".equals(actionActuatorFunc)) {
|
||||
String gimbalYawRotateEnable = actionActuatorFuncParam.elementText("gimbalYawRotateEnable");
|
||||
if ("1".equals(gimbalYawRotateEnable)) {
|
||||
action.setActionType(actionActuatorFunc + "_yaw");
|
||||
} else {
|
||||
action.setActionType(actionActuatorFunc);
|
||||
}
|
||||
} else {
|
||||
action.setActionType(actionActuatorFunc);
|
||||
}
|
||||
SetActionParams.getAction(action, actionActuatorFuncParam);
|
||||
actionList.add(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
waypoint.setWaypointActionList(actionList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//赋值器
|
||||
public static String filedValid(String value, Boolean accurateImport) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
if (accurateImport) {
|
||||
return null;
|
||||
} else {
|
||||
throw new RenException("字段缺失,无法解析");
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import com.multictrl.common.validator.group.AddGroup;
|
|||
import com.multictrl.common.validator.group.UpdateGroup;
|
||||
import com.multictrl.modules.business.dto.RouteAiDTO;
|
||||
import com.multictrl.modules.business.dto.RouteDTO;
|
||||
import com.multictrl.modules.business.dto.UploadRouteDTO;
|
||||
import com.multictrl.modules.business.service.RouteService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
|
@ -116,4 +117,21 @@ public class RouteController {
|
|||
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@PostMapping("/upload")
|
||||
@Operation(summary = "导入航线")
|
||||
@LogOperation("导入航线")
|
||||
@Parameters({
|
||||
@Parameter(name = "dockSn", description = "机库SN"),
|
||||
@Parameter(name = "accurateImport", description = "是否精准导入"),
|
||||
@Parameter(name = "globalRthHeight", description = "返航高度"),
|
||||
@Parameter(name = "file", description = "航线文件")
|
||||
})
|
||||
@RequiresPermissions("bus:route:upload")
|
||||
public Result<Object> upload(UploadRouteDTO dto) {
|
||||
ValidatorUtils.validateEntity(dto);
|
||||
routeService.upload(dto);
|
||||
|
||||
return new Result<>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
package com.multictrl.modules.business.dto;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.multictrl.common.validator.group.DefaultGroup;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 导入航线参数
|
||||
*
|
||||
* @author Sdy
|
||||
* @since 1.0.0 2026/6/18
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "导入航线参数")
|
||||
public class UploadRouteDTO {
|
||||
|
||||
@NotBlank(message = "机库SN不能为空")
|
||||
// @Schema(description = "机库SN")
|
||||
private String dockSn;
|
||||
|
||||
@NotNull(message = "是否精准导入不能为空")
|
||||
// @Schema(description = "是否精准导入 true false")
|
||||
private Boolean accurateImport;
|
||||
|
||||
// @Schema(description = "返航高度")
|
||||
private Double globalRthHeight;
|
||||
|
||||
@NotNull(message = "航线文件不能为空")
|
||||
// @Schema(description = "航线文件")
|
||||
private MultipartFile file;
|
||||
|
||||
@JsonIgnore
|
||||
@Schema(hidden = true)
|
||||
@AssertTrue(message = "返航高度不能为空")
|
||||
public boolean isGlobalRthHeightValid() {
|
||||
if (accurateImport) {
|
||||
return globalRthHeight != null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,9 @@ public class WaypointActionDTO implements Serializable {
|
|||
@Schema(description = "动作值")
|
||||
private String actionValue;
|
||||
|
||||
@Schema(description = "动作顺序")
|
||||
private Integer actionSort;
|
||||
|
||||
@Schema(description = "航点顺序", hidden = true)
|
||||
// @JsonIgnore
|
||||
private String waypointOrder;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.multictrl.common.page.PageData;
|
|||
import com.multictrl.common.service.CrudService;
|
||||
import com.multictrl.modules.business.dto.RouteAiDTO;
|
||||
import com.multictrl.modules.business.dto.RouteDTO;
|
||||
import com.multictrl.modules.business.dto.UploadRouteDTO;
|
||||
import com.multictrl.modules.business.entity.RouteEntity;
|
||||
|
||||
import java.util.Map;
|
||||
|
|
@ -36,4 +37,7 @@ public interface RouteService extends CrudService<RouteEntity, RouteDTO> {
|
|||
|
||||
//删除AI任务
|
||||
void deleteRouteAi(Long routeId);
|
||||
|
||||
//上传航线
|
||||
void upload(UploadRouteDTO dto);
|
||||
}
|
||||
|
|
@ -1,24 +1,26 @@
|
|||
package com.multictrl.modules.business.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.multictrl.common.constant.BusinessConstant;
|
||||
import com.multictrl.common.exception.ErrorCode;
|
||||
import com.multictrl.common.exception.ExceptionUtils;
|
||||
import com.multictrl.common.exception.RenException;
|
||||
import com.multictrl.common.page.PageData;
|
||||
import com.multictrl.common.service.impl.CrudServiceImpl;
|
||||
import com.multictrl.common.utils.ConvertUtils;
|
||||
import com.multictrl.common.utils.JsonUtils;
|
||||
import com.multictrl.common.utils.kmz.KmzUtils;
|
||||
import com.multictrl.common.utils.kmz.WpmlKmlParser;
|
||||
import com.multictrl.common.validator.AssertUtils;
|
||||
import com.multictrl.common.validator.ValidatorUtils;
|
||||
import com.multictrl.modules.business.dao.RouteAiDao;
|
||||
import com.multictrl.modules.business.dao.RouteDao;
|
||||
import com.multictrl.modules.business.dao.RouteWaypointDao;
|
||||
import com.multictrl.modules.business.dao.WaypointActionDao;
|
||||
import com.multictrl.modules.business.dto.RouteAiDTO;
|
||||
import com.multictrl.modules.business.dto.RouteDTO;
|
||||
import com.multictrl.modules.business.dto.RouteWaypointDTO;
|
||||
import com.multictrl.modules.business.dto.WaypointActionDTO;
|
||||
import com.multictrl.modules.business.dto.*;
|
||||
import com.multictrl.modules.business.entity.RouteAiEntity;
|
||||
import com.multictrl.modules.business.entity.RouteEntity;
|
||||
import com.multictrl.modules.business.entity.RouteWaypointEntity;
|
||||
|
|
@ -27,8 +29,10 @@ import com.multictrl.modules.business.service.MinioService;
|
|||
import com.multictrl.modules.business.service.RouteService;
|
||||
import com.multictrl.modules.security.user.SecurityUser;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -41,8 +45,9 @@ import java.util.Map;
|
|||
* @author Sdy
|
||||
* @since 1.0.0 2026-04-20
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RouteServiceImpl extends CrudServiceImpl<RouteDao, RouteEntity, RouteDTO> implements RouteService {
|
||||
private final RouteWaypointDao routeWaypointDao;
|
||||
private final WaypointActionDao waypointActionDao;
|
||||
|
|
@ -211,6 +216,60 @@ public class RouteServiceImpl extends CrudServiceImpl<RouteDao, RouteEntity, Rou
|
|||
routeAiDao.delete(new QueryWrapper<RouteAiEntity>().eq("route_id", routeId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(UploadRouteDTO dto) {
|
||||
MultipartFile file = dto.getFile();
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String name = FileUtil.getPrefix(originalFilename);
|
||||
String suffix = FileUtil.getSuffix(originalFilename);
|
||||
if (!"kmz".equals(suffix)) {
|
||||
throw new RenException(ErrorCode.FILE_FORMAT_ERROR, "kmz");
|
||||
}
|
||||
//判断航线名称是否已存在
|
||||
checkRouteExist(null, name);
|
||||
|
||||
RouteDTO routeDTO = null;
|
||||
try {
|
||||
Map<String, byte[]> kmzInfo = KmzUtils.extractKmzAsBytes(file.getInputStream());
|
||||
byte[] template = kmzInfo.get("template.kml");
|
||||
routeDTO = WpmlKmlParser.parseKmlFile(template, dto.getAccurateImport());
|
||||
byte[] waylines = kmzInfo.get("waylines.wpml");
|
||||
WpmlKmlParser.parseWpmlFile(waylines, routeDTO, dto.getAccurateImport());
|
||||
|
||||
log.debug("解析结果:{}", JsonUtils.toJsonString(dto));
|
||||
} catch (Exception e) {
|
||||
log.error("解析结果失败:{}", ExceptionUtils.getErrorStackTrace(e));
|
||||
// throw new RenException(ErrorCode.FILE_PARSER_ERROR);
|
||||
throw new RenException(e.getMessage());
|
||||
}
|
||||
|
||||
routeDTO.setRouteName(name);
|
||||
routeDTO.setGlobalRthHeight(dto.getGlobalRthHeight());
|
||||
String path = dto.getDockSn() + "/" + originalFilename;
|
||||
try {
|
||||
minioService.uploadFile(file.getInputStream(), BusinessConstant.ROUTE_KMZ_BUCKET, path);
|
||||
} catch (IOException e) {
|
||||
log.error("文件上传失败:{}", ExceptionUtils.getErrorStackTrace(e));
|
||||
throw new RenException(ErrorCode.OSS_UPLOAD_FILE_ERROR);
|
||||
}
|
||||
routeDTO.setKmzUrl(BusinessConstant.ROUTE_KMZ_BUCKET + "/" + path);
|
||||
routeDTO.setIsAccurateImport(dto.getAccurateImport());
|
||||
routeDTO.setDockSn(dto.getDockSn());
|
||||
|
||||
//航点动作处理
|
||||
List<RouteWaypointDTO> routeWaypointList = routeDTO.getRouteWaypointList();
|
||||
handleWaypointAction(routeWaypointList);
|
||||
|
||||
//保存信息
|
||||
RouteEntity routeEntity = ConvertUtils.sourceToTarget(routeDTO, currentModelClass());
|
||||
routeEntity.setDeptId(SecurityUser.getDeptId());
|
||||
routeEntity.setWaypointNum(routeWaypointList.size());
|
||||
baseDao.insert(routeEntity);
|
||||
|
||||
//保存航点信息
|
||||
saveWaypoint(routeEntity.getId(), routeWaypointList);
|
||||
}
|
||||
|
||||
//判断航线是否存在
|
||||
private void checkRouteExist(Long id, String routeName) {
|
||||
RouteEntity uavRouteEntity = baseDao.selectOne(new QueryWrapper<RouteEntity>()
|
||||
|
|
|
|||
Loading…
Reference in New Issue