|
|
@@ -3,13 +3,16 @@ package com.dji.sample.wayline.service.impl;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.dji.sample.common.util.WaylineUtil;
|
|
|
import com.dji.sample.component.oss.model.OssConfiguration;
|
|
|
import com.dji.sample.component.oss.service.impl.OssServiceContext;
|
|
|
import com.dji.sample.wayline.dao.IWaylineFileMapper;
|
|
|
import com.dji.sample.wayline.model.dto.KmzFileProperties;
|
|
|
import com.dji.sample.wayline.model.dto.WaylineFileDTO;
|
|
|
+import com.dji.sample.wayline.model.dto.WaylinePointDTO;
|
|
|
import com.dji.sample.wayline.model.entity.WaylineFileEntity;
|
|
|
import com.dji.sample.wayline.service.IWaylineFileService;
|
|
|
+import com.dji.sample.wayline.service.IWaylinePointService;
|
|
|
import com.dji.sdk.cloudapi.device.DeviceDomainEnum;
|
|
|
import com.dji.sdk.cloudapi.device.DeviceEnum;
|
|
|
import com.dji.sdk.cloudapi.device.DeviceSubTypeEnum;
|
|
|
@@ -29,10 +32,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.util.DigestUtils;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
-
|
|
|
-import java.io.File;
|
|
|
-import java.io.IOException;
|
|
|
-import java.io.InputStream;
|
|
|
+import javax.xml.parsers.ParserConfigurationException;
|
|
|
+import java.io.*;
|
|
|
import java.math.BigDecimal;
|
|
|
import java.net.URL;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
@@ -42,7 +43,6 @@ import java.util.stream.Collectors;
|
|
|
import java.util.zip.ZipEntry;
|
|
|
import java.util.zip.ZipInputStream;
|
|
|
|
|
|
-import static com.dji.sample.wayline.model.dto.KmzFileProperties.WAYLINE_FILE_SUFFIX;
|
|
|
|
|
|
/**
|
|
|
* @author sean
|
|
|
@@ -59,6 +59,13 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
@Autowired
|
|
|
private OssServiceContext ossService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private IWaylinePointService waylinePointService;
|
|
|
+
|
|
|
+ private static final String WAYLINE_FILE_SUFFIX = ".kmz";
|
|
|
+ private static final String TEMPLATE_FILE_PATH = "wpmz/template.kml";
|
|
|
+ private static final String WAYLINES_FILE_PATH = "wpmz/waylines.wpml";
|
|
|
+
|
|
|
@Override
|
|
|
public PaginationData<GetWaylineListResponse> getWaylinesByParam(String workspaceId, GetWaylineListRequest param) {
|
|
|
// Paging Query
|
|
|
@@ -67,20 +74,20 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
new LambdaQueryWrapper<WaylineFileEntity>()
|
|
|
.eq(WaylineFileEntity::getWorkspaceId, workspaceId)
|
|
|
.eq(Objects.nonNull(param.getFavorited()), WaylineFileEntity::getFavorited, param.getFavorited())
|
|
|
- .and(param.getTemplateType() != null, wrapper -> {
|
|
|
- for (WaylineTypeEnum type : param.getTemplateType()) {
|
|
|
- wrapper.like(WaylineFileEntity::getTemplateTypes, type.getValue()).or();
|
|
|
- }
|
|
|
+ .and(param.getTemplateType() != null, wrapper -> {
|
|
|
+ for (WaylineTypeEnum type : param.getTemplateType()) {
|
|
|
+ wrapper.like(WaylineFileEntity::getTemplateTypes, type.getValue()).or();
|
|
|
+ }
|
|
|
})
|
|
|
- .and(param.getPayloadModelKey() != null, wrapper -> {
|
|
|
- for (DeviceEnum type : param.getPayloadModelKey()) {
|
|
|
- wrapper.like(WaylineFileEntity::getPayloadModelKeys, type.getType()).or();
|
|
|
- }
|
|
|
+ .and(param.getPayloadModelKey() != null, wrapper -> {
|
|
|
+ for (DeviceEnum type : param.getPayloadModelKey()) {
|
|
|
+ wrapper.like(WaylineFileEntity::getPayloadModelKeys, type.getType()).or();
|
|
|
+ }
|
|
|
})
|
|
|
- .and(param.getDroneModelKeys() != null, wrapper -> {
|
|
|
- for (DeviceEnum type : param.getDroneModelKeys()) {
|
|
|
- wrapper.eq(WaylineFileEntity::getDroneModelKey, type.getType()).or();
|
|
|
- }
|
|
|
+ .and(param.getDroneModelKeys() != null, wrapper -> {
|
|
|
+ for (DeviceEnum type : param.getDroneModelKeys()) {
|
|
|
+ wrapper.eq(WaylineFileEntity::getDroneModelKey, type.getType()).or();
|
|
|
+ }
|
|
|
})
|
|
|
.like(Objects.nonNull(param.getKey()), WaylineFileEntity::getName, param.getKey())
|
|
|
// There is a risk of SQL injection
|
|
|
@@ -101,8 +108,8 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
this.entityConvertToDTO(
|
|
|
mapper.selectOne(
|
|
|
new LambdaQueryWrapper<WaylineFileEntity>()
|
|
|
- .eq(WaylineFileEntity::getWorkspaceId, workspaceId)
|
|
|
- .eq(WaylineFileEntity::getWaylineId, waylineId))));
|
|
|
+ .eq(WaylineFileEntity::getWorkspaceId, workspaceId)
|
|
|
+ .eq(WaylineFileEntity::getWaylineId, waylineId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -136,11 +143,17 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
throw new RuntimeException("The file " + metadata.getObjectKey() +
|
|
|
" does not exist in the bucket[" + OssConfiguration.bucket + "].");
|
|
|
}
|
|
|
+ WaylineFileDTO vaDto = validKmzFile(object).get();
|
|
|
+ metadata.setPointDTOS(vaDto.getPointDTOS());
|
|
|
file.setSign(DigestUtils.md5DigestAsHex(object));
|
|
|
+ file.setHeight(vaDto.getHeight());
|
|
|
+ file.setEllipsoidHeight(vaDto.getEllipsoidHeight());
|
|
|
+ file.setHeightMode(vaDto.getHeightMode());
|
|
|
} catch (IOException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
}
|
|
|
+ waylinePointService.isnertPoint(metadata.getPointDTOS(), file.getWaylineId());
|
|
|
int insertId = mapper.insert(file);
|
|
|
return insertId > 0 ? file.getId() : insertId;
|
|
|
}
|
|
|
@@ -162,8 +175,8 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
@Override
|
|
|
public List<String> getDuplicateNames(String workspaceId, List<String> names) {
|
|
|
return mapper.selectList(new LambdaQueryWrapper<WaylineFileEntity>()
|
|
|
- .eq(WaylineFileEntity::getWorkspaceId, workspaceId)
|
|
|
- .in(WaylineFileEntity::getName, names))
|
|
|
+ .eq(WaylineFileEntity::getWorkspaceId, workspaceId)
|
|
|
+ .in(WaylineFileEntity::getName, names))
|
|
|
.stream()
|
|
|
.map(WaylineFileEntity::getName)
|
|
|
.collect(Collectors.toList());
|
|
|
@@ -177,8 +190,8 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
}
|
|
|
GetWaylineListResponse wayline = waylineOpt.get();
|
|
|
boolean isDel = mapper.delete(new LambdaUpdateWrapper<WaylineFileEntity>()
|
|
|
- .eq(WaylineFileEntity::getWorkspaceId, workspaceId)
|
|
|
- .eq(WaylineFileEntity::getWaylineId, waylineId))
|
|
|
+ .eq(WaylineFileEntity::getWorkspaceId, workspaceId)
|
|
|
+ .eq(WaylineFileEntity::getWaylineId, waylineId))
|
|
|
> 0;
|
|
|
if (!isDel) {
|
|
|
return false;
|
|
|
@@ -188,15 +201,20 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
|
|
|
@Override
|
|
|
public void importKmzFile(MultipartFile file, String workspaceId, String creator) {
|
|
|
- Optional<WaylineFileDTO> waylineFileOpt = validKmzFile(file);
|
|
|
- if (waylineFileOpt.isEmpty()) {
|
|
|
+
|
|
|
+ String filename = file.getOriginalFilename();
|
|
|
+ if (Objects.nonNull(filename) && !filename.endsWith(WAYLINE_FILE_SUFFIX)) {
|
|
|
throw new RuntimeException("The file format is incorrect.");
|
|
|
}
|
|
|
-
|
|
|
try {
|
|
|
+ Optional<WaylineFileDTO> waylineFileOpt = validKmzFile(file.getInputStream());
|
|
|
+ if (waylineFileOpt.isEmpty()) {
|
|
|
+ throw new RuntimeException("The file format is incorrect.");
|
|
|
+ }
|
|
|
WaylineFileDTO waylineFile = waylineFileOpt.get();
|
|
|
+ waylineFile.setObjectKey(OssConfiguration.objectDirPrefix + File.separator + filename);
|
|
|
+ waylineFile.setName(filename.substring(0, filename.lastIndexOf(WAYLINE_FILE_SUFFIX)));
|
|
|
waylineFile.setUsername(creator);
|
|
|
-
|
|
|
ossService.putObject(OssConfiguration.bucket, waylineFile.getObjectKey(), file.getInputStream());
|
|
|
this.saveWaylineFile(workspaceId, waylineFile);
|
|
|
} catch (IOException e) {
|
|
|
@@ -204,60 +222,77 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private Optional<WaylineFileDTO> validKmzFile(MultipartFile file) {
|
|
|
- String filename = file.getOriginalFilename();
|
|
|
- if (Objects.nonNull(filename) && !filename.endsWith(WAYLINE_FILE_SUFFIX)) {
|
|
|
- throw new RuntimeException("The file format is incorrect.");
|
|
|
- }
|
|
|
- try (ZipInputStream unzipFile = new ZipInputStream(file.getInputStream(), StandardCharsets.UTF_8)) {
|
|
|
-
|
|
|
- ZipEntry nextEntry = unzipFile.getNextEntry();
|
|
|
- while (Objects.nonNull(nextEntry)) {
|
|
|
- boolean isWaylines = (KmzFileProperties.FILE_DIR_FIRST + "/" + KmzFileProperties.FILE_DIR_SECOND_TEMPLATE).equals(nextEntry.getName());
|
|
|
- if (!isWaylines) {
|
|
|
- nextEntry = unzipFile.getNextEntry();
|
|
|
- continue;
|
|
|
+ private Optional<WaylineFileDTO> validKmzFile(InputStream fileInputStream) {
|
|
|
+ WaylineFileDTO waylineFileDTO = new WaylineFileDTO();
|
|
|
+ try (ZipInputStream unzipFile = new ZipInputStream(fileInputStream)) {
|
|
|
+ ZipEntry nextEntry;
|
|
|
+ Document templateDoc = null;
|
|
|
+ while ((nextEntry = unzipFile.getNextEntry()) != null) {
|
|
|
+ // 手动处理文件名的编码问题
|
|
|
+ String entryName = new String(nextEntry.getName().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
|
|
|
+
|
|
|
+ if (TEMPLATE_FILE_PATH.equals(entryName)) {
|
|
|
+ templateDoc = readDocument(unzipFile);
|
|
|
+ } else if (WAYLINES_FILE_PATH.equals(entryName)) {
|
|
|
+ List<WaylinePointDTO> points = WaylineUtil.extractWaypoints(unzipFile);
|
|
|
+ waylineFileDTO.setPointDTOS(points);
|
|
|
}
|
|
|
- SAXReader reader = new SAXReader();
|
|
|
- Document document = reader.read(unzipFile);
|
|
|
- if (!StandardCharsets.UTF_8.name().equals(document.getXMLEncoding())) {
|
|
|
- throw new RuntimeException("The file encoding format is incorrect.");
|
|
|
+ if (templateDoc != null && null != waylineFileDTO.getPointDTOS() ) {
|
|
|
+ break;
|
|
|
}
|
|
|
+ // 关闭当前 ZipEntry
|
|
|
+ unzipFile.closeEntry();
|
|
|
+ }
|
|
|
+ if (templateDoc == null ) {
|
|
|
+ throw new RuntimeException("The file format is incorrect.");
|
|
|
+ }
|
|
|
+ Node droneNode = templateDoc.selectSingleNode("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_INFO);
|
|
|
+ Node payloadNode = templateDoc.selectSingleNode("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_INFO);
|
|
|
+ if (Objects.isNull(droneNode) || Objects.isNull(payloadNode)) {
|
|
|
+ throw new RuntimeException("The file format is incorrect.");
|
|
|
+ }
|
|
|
|
|
|
- Node droneNode = document.selectSingleNode("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_INFO);
|
|
|
- Node payloadNode = document.selectSingleNode("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_INFO);
|
|
|
- if (Objects.isNull(droneNode) || Objects.isNull(payloadNode)) {
|
|
|
- throw new RuntimeException("The file format is incorrect.");
|
|
|
- }
|
|
|
+ DeviceTypeEnum type = DeviceTypeEnum.find(Integer.parseInt(droneNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_ENUM_VALUE)));
|
|
|
+ DeviceSubTypeEnum subType = DeviceSubTypeEnum.find(Integer.parseInt(droneNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_SUB_ENUM_VALUE)));
|
|
|
+ DeviceTypeEnum payloadType = DeviceTypeEnum.find(Integer.parseInt(payloadNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_ENUM_VALUE)));
|
|
|
+ DeviceSubTypeEnum payloadSubType = DeviceSubTypeEnum.find(Integer.parseInt(payloadNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_SUB_ENUM_VALUE)));
|
|
|
+ String templateType = templateDoc.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_TEMPLATE_TYPE);
|
|
|
+ BigDecimal height = new BigDecimal(templateDoc.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.HEIGHT));
|
|
|
+ BigDecimal ellipsoidHeight = new BigDecimal(templateDoc.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.ELLIPSOID_HEIGHT));
|
|
|
+ String heightMode = templateDoc.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.HEIGHT_MODE);
|
|
|
|
|
|
- DeviceTypeEnum type = DeviceTypeEnum.find(Integer.parseInt(droneNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_ENUM_VALUE)));
|
|
|
- DeviceSubTypeEnum subType = DeviceSubTypeEnum.find(Integer.parseInt(droneNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_SUB_ENUM_VALUE)));
|
|
|
- DeviceTypeEnum payloadType = DeviceTypeEnum.find(Integer.parseInt(payloadNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_ENUM_VALUE)));
|
|
|
- DeviceSubTypeEnum payloadSubType = DeviceSubTypeEnum.find(Integer.parseInt(payloadNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_SUB_ENUM_VALUE)));
|
|
|
- String templateType = document.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_TEMPLATE_TYPE);
|
|
|
- BigDecimal height = new BigDecimal(document.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.HEIGHT));
|
|
|
- BigDecimal ellipsoidHeight = new BigDecimal(document.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.ELLIPSOID_HEIGHT));
|
|
|
- String heightMode = document.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.HEIGHT_MODE);
|
|
|
- return Optional.of(WaylineFileDTO.builder()
|
|
|
- .droneModelKey(DeviceEnum.find(DeviceDomainEnum.DRONE, type, subType).getDevice())
|
|
|
- .payloadModelKeys(List.of(DeviceEnum.find(DeviceDomainEnum.PAYLOAD, payloadType, payloadSubType).getDevice()))
|
|
|
- .objectKey(OssConfiguration.objectDirPrefix + File.separator + filename)
|
|
|
- .name(filename.substring(0, filename.lastIndexOf(WAYLINE_FILE_SUFFIX)))
|
|
|
- .height(height)
|
|
|
- .heightMode(heightMode)
|
|
|
- .ellipsoidHeight(ellipsoidHeight)
|
|
|
- .sign(DigestUtils.md5DigestAsHex(file.getInputStream()))
|
|
|
- .templateTypes(List.of(WaylineTypeEnum.find(templateType).getValue()))
|
|
|
- .build());
|
|
|
- }
|
|
|
+ waylineFileDTO.setDroneModelKey(DeviceEnum.find(DeviceDomainEnum.DRONE, type, subType).getDevice());
|
|
|
+ waylineFileDTO.setPayloadModelKeys(List.of(DeviceEnum.find(DeviceDomainEnum.PAYLOAD, payloadType, payloadSubType).getDevice()));
|
|
|
+
|
|
|
+ waylineFileDTO.setHeight(height);
|
|
|
+ waylineFileDTO.setHeightMode(heightMode);
|
|
|
+ waylineFileDTO.setEllipsoidHeight(ellipsoidHeight);
|
|
|
+ waylineFileDTO.setSign(DigestUtils.md5DigestAsHex(fileInputStream));
|
|
|
+ waylineFileDTO.setTemplateTypes(List.of(WaylineTypeEnum.find(templateType).getValue()));
|
|
|
|
|
|
+ return Optional.of(WaylineFileDTO.builder()
|
|
|
+ .droneModelKey(waylineFileDTO.getDroneModelKey())
|
|
|
+ .payloadModelKeys(waylineFileDTO.getPayloadModelKeys())
|
|
|
+ .objectKey(waylineFileDTO.getObjectKey())
|
|
|
+ .name(waylineFileDTO.getName())
|
|
|
+ .height(waylineFileDTO.getHeight())
|
|
|
+ .heightMode(waylineFileDTO.getHeightMode())
|
|
|
+ .ellipsoidHeight(waylineFileDTO.getEllipsoidHeight())
|
|
|
+ .sign(waylineFileDTO.getSign())
|
|
|
+ .templateTypes(waylineFileDTO.getTemplateTypes())
|
|
|
+ .pointDTOS(waylineFileDTO.getPointDTOS())
|
|
|
+ .build());
|
|
|
} catch (IOException | DocumentException e) {
|
|
|
e.printStackTrace();
|
|
|
+ } catch (ParserConfigurationException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
}
|
|
|
return Optional.empty();
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* Convert database entity objects into wayline data transfer object.
|
|
|
+ *
|
|
|
* @param entity
|
|
|
* @return
|
|
|
*/
|
|
|
@@ -285,12 +320,12 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
|
|
|
/**
|
|
|
* Convert the received wayline object into a database entity object.
|
|
|
+ *
|
|
|
* @param file
|
|
|
* @return
|
|
|
*/
|
|
|
private WaylineFileEntity dtoConvertToEntity(WaylineFileDTO file) {
|
|
|
WaylineFileEntity.WaylineFileEntityBuilder builder = WaylineFileEntity.builder();
|
|
|
-
|
|
|
if (file != null) {
|
|
|
builder.droneModelKey(file.getDroneModelKey())
|
|
|
.name(file.getName())
|
|
|
@@ -308,7 +343,28 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
|
|
|
.sign(file.getSign())
|
|
|
.build();
|
|
|
}
|
|
|
-
|
|
|
return builder.build();
|
|
|
}
|
|
|
+
|
|
|
+ private Document readDocument(InputStream inputStream) throws IOException, ParserConfigurationException, DocumentException {
|
|
|
+ // 将 InputStream 读取到字节数组中
|
|
|
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
+ byte[] buffer = new byte[1024];
|
|
|
+ int length;
|
|
|
+ while ((length = inputStream.read(buffer)) != -1) {
|
|
|
+ baos.write(buffer, 0, length);
|
|
|
+ }
|
|
|
+ byte[] content = baos.toByteArray();
|
|
|
+ // 使用 ByteArrayInputStream 重新创建 InputStream
|
|
|
+ ByteArrayInputStream bais = new ByteArrayInputStream(content);
|
|
|
+ SAXReader reader = new SAXReader();
|
|
|
+ Document document = reader.read(bais);
|
|
|
+ if (!StandardCharsets.UTF_8.name().equals(document.getXMLEncoding())) {
|
|
|
+ throw new RuntimeException("The file encoding format is incorrect.");
|
|
|
+ }
|
|
|
+ return document;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
}
|