| | |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.dji.sample.common.model.Pagination; |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.component.oss.model.AliyunOSSConfiguration; |
| | | import com.dji.sample.component.oss.model.MinIOConfiguration; |
| | | import com.dji.sample.component.oss.service.IOssService; |
| | | import com.dji.sample.component.oss.service.impl.AliyunOssServiceImpl; |
| | | import com.dji.sample.component.oss.service.impl.MinIOServiceImpl; |
| | | import com.dji.sample.component.oss.model.OssConfiguration; |
| | | import com.dji.sample.component.oss.service.impl.OssServiceContext; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.wayline.dao.IWaylineFileMapper; |
| | | import com.dji.sample.wayline.model.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.WaylineFileEntity; |
| | | import com.dji.sample.wayline.model.WaylineQueryParam; |
| | | import com.dji.sample.wayline.model.dto.KmzFileProperties; |
| | | import com.dji.sample.wayline.model.dto.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.dto.WaylineListDTO; |
| | | import com.dji.sample.wayline.model.entity.WaylineFileEntity; |
| | | import com.dji.sample.wayline.model.enums.WaylineTemplateTypeEnum; |
| | | import com.dji.sample.wayline.model.param.WaylineQueryParam; |
| | | import com.dji.sample.wayline.service.IWaylineFileService; |
| | | import org.dom4j.Document; |
| | | import org.dom4j.DocumentException; |
| | | import org.dom4j.Node; |
| | | import org.dom4j.io.SAXReader; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | 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.IOException; |
| | | import java.io.InputStream; |
| | | import java.net.URL; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.sql.SQLException; |
| | | import java.util.*; |
| | | 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 |
| | |
| | | |
| | | @Autowired |
| | | private IWaylineFileMapper mapper; |
| | | |
| | | private IOssService ossService; |
| | | |
| | | @Autowired |
| | | private void setOssService(@Autowired AliyunOssServiceImpl aliyunOssService, @Autowired MinIOServiceImpl minIOService) { |
| | | if (AliyunOSSConfiguration.enable) { |
| | | this.ossService = aliyunOssService; |
| | | return; |
| | | } |
| | | if (MinIOConfiguration.enable) { |
| | | this.ossService = minIOService; |
| | | return; |
| | | } |
| | | throw new NullPointerException("ossService is null."); |
| | | } |
| | | private OssServiceContext ossService; |
| | | |
| | | @Override |
| | | public PaginationData<WaylineFileDTO> getWaylinesByParam(String workspaceId, WaylineQueryParam param) { |
| | |
| | | new LambdaQueryWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(param.isFavorited(), WaylineFileEntity::getFavorited, param.isFavorited()) |
| | | .and(param.getTemplateType() != null, wrapper -> { |
| | | for (Integer type : param.getTemplateType()) { |
| | | wrapper.like(WaylineFileEntity::getTemplateTypes, type).or(); |
| | | } |
| | | .and(param.getTemplateType() != null, wrapper -> { |
| | | for (Integer type : param.getTemplateType()) { |
| | | wrapper.like(WaylineFileEntity::getTemplateTypes, type).or(); |
| | | } |
| | | }) |
| | | // There is a risk of SQL injection |
| | | .last(StringUtils.hasText(param.getOrderBy()), " order by " + param.getOrderBy())); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public WaylineFileDTO getWaylineByWaylineId(String workspaceId, String waylineId) { |
| | | return this.entityConvertToDTO( |
| | | mapper.selectOne( |
| | | new LambdaQueryWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(WaylineFileEntity::getWaylineId, waylineId))); |
| | | public PaginationData<WaylineFileDTO> getShowWaylinesByParam(String workspaceId, WaylineQueryParam param) { |
| | | // Paging Query |
| | | Page<WaylineFileEntity> page = mapper.selectPage( |
| | | new Page<WaylineFileEntity>(param.getPage(), param.getPageSize()), |
| | | new LambdaQueryWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(WaylineFileEntity::getIsTemp,1) |
| | | .eq(param.isFavorited(), WaylineFileEntity::getFavorited, param.isFavorited()) |
| | | .and(param.getTemplateType() != null, wrapper -> { |
| | | for (Integer type : param.getTemplateType()) { |
| | | wrapper.like(WaylineFileEntity::getTemplateTypes, type).or(); |
| | | } |
| | | }) |
| | | // There is a risk of SQL injection |
| | | .last(StringUtils.hasText(param.getOrderBy()), " order by " + param.getOrderBy())); |
| | | |
| | | // Wrap the results of a paging query into a custom paging object. |
| | | List<WaylineFileDTO> records = page.getRecords() |
| | | .stream() |
| | | .map(this::entityConvertToDTO) |
| | | .collect(Collectors.toList()); |
| | | |
| | | return new PaginationData<>(records, new Pagination(page)); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public String getPatchesId(String waylineId) { |
| | | WaylineFileEntity entity = mapper.selectOne(new LambdaQueryWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWaylineId, waylineId)); |
| | | return entity.getPatchesId(); |
| | | } |
| | | |
| | | @Override |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | return ossService.getObjectUrl(bucket, objectKey); |
| | | public Optional<WaylineFileDTO> getWaylineByWaylineId(String workspaceId, String waylineId) { |
| | | return Optional.ofNullable( |
| | | this.entityConvertToDTO( |
| | | mapper.selectOne( |
| | | new LambdaQueryWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(WaylineFileEntity::getWaylineId, waylineId)))); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public URL getObjectUrl(String workspaceId, String waylineId) throws SQLException { |
| | | Optional<WaylineFileDTO> waylineOpt = this.getWaylineByWaylineId(workspaceId, waylineId); |
| | | if (waylineOpt.isEmpty()) { |
| | | throw new SQLException(waylineId + " 不存在"); |
| | | } |
| | | return ossService.getObjectUrl(OssConfiguration.bucket, waylineOpt.get().getObjectKey()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | WaylineFileEntity file = this.dtoConvertToEntity(metadata); |
| | | file.setWaylineId(UUID.randomUUID().toString()); |
| | | file.setWorkspaceId(workspaceId); |
| | | |
| | | if (!StringUtils.hasText(file.getSign())) { |
| | | try (InputStream object = ossService.getObject(OssConfiguration.bucket, metadata.getObjectKey())) { |
| | | if (object.available() == 0) { |
| | | throw new RuntimeException("文件" + metadata.getObjectKey() + |
| | | " 在空间中不存在[" + OssConfiguration.bucket + "]."); |
| | | } |
| | | file.setSign(DigestUtils.md5DigestAsHex(object)); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | int insertId = mapper.insert(file); |
| | | return insertId > 0 ? file.getId() : insertId; |
| | | } |
| | | |
| | | @Override |
| | | public Integer saveWaylineFiles(String workspaceId, WaylineFileDTO metadata, String patchesId,String isTemp) { |
| | | metadata.setPatchesId(patchesId); |
| | | WaylineFileEntity file = this.dtoConvertToEntity(metadata); |
| | | file.setWaylineId(UUID.randomUUID().toString()); |
| | | file.setWorkspaceId(workspaceId); |
| | | file.setIsTemp(isTemp); |
| | | if (!StringUtils.hasText(file.getSign())) { |
| | | try (InputStream object = ossService.getObject(OssConfiguration.bucket, metadata.getObjectKey())) { |
| | | if (object.available() == 0) { |
| | | throw new RuntimeException("文件" + metadata.getObjectKey() + |
| | | " 在空间中不存在[" + OssConfiguration.bucket + "]."); |
| | | } |
| | | file.setSign(DigestUtils.md5DigestAsHex(object)); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | int insertId = mapper.insert(file); |
| | | return insertId > 0 ? file.getId() : insertId; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Boolean markFavorite(String workspaceId, List<String> waylineIds, Boolean isFavorite) { |
| | |
| | | @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()); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteByWaylineId(String workspaceId, String waylineId) { |
| | | Optional<WaylineFileDTO> waylineOpt = this.getWaylineByWaylineId(workspaceId, waylineId); |
| | | if (waylineOpt.isEmpty()) { |
| | | return true; |
| | | } |
| | | WaylineFileDTO wayline = waylineOpt.get(); |
| | | boolean isDel = mapper.delete(new LambdaUpdateWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(WaylineFileEntity::getWaylineId, waylineId)) |
| | | > 0; |
| | | if (!isDel) { |
| | | return false; |
| | | } |
| | | return ossService.deleteObject(OssConfiguration.bucket, wayline.getObjectKey()); |
| | | } |
| | | |
| | | @Override |
| | | public String importKmzFile(MultipartFile file, String workspaceId, String creator, String patchesId,String isTemp) { |
| | | Optional<WaylineFileDTO> waylineFileOpt = validKmzFile(file); |
| | | if (waylineFileOpt.isEmpty()) { |
| | | throw new RuntimeException("文件格式错误"); |
| | | } |
| | | String back = null; |
| | | try { |
| | | WaylineFileDTO waylineFile = waylineFileOpt.get(); |
| | | waylineFile.setWaylineId(workspaceId); |
| | | waylineFile.setUsername(creator); |
| | | waylineFile.setIsTemp(isTemp); |
| | | back = ossService.putObject(OssConfiguration.bucket, waylineFile.getObjectKey(), file.getInputStream()); |
| | | if (back == null) { |
| | | this.saveWaylineFiles(workspaceId, waylineFile, patchesId,isTemp); |
| | | } |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return back; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public WaylineFileDTO importKmzFileBack(MultipartFile file, String workspaceId, String creator) { |
| | | WaylineFileDTO waylineFile = null; |
| | | Optional<WaylineFileDTO> waylineFileOpt = validKmzFile(file); |
| | | if (waylineFileOpt.isEmpty()) { |
| | | throw new RuntimeException("文件格式错误"); |
| | | } |
| | | |
| | | try { |
| | | waylineFile = waylineFileOpt.get(); |
| | | waylineFile.setWaylineId(workspaceId); |
| | | waylineFile.setUsername(creator); |
| | | ossService.putObject(OssConfiguration.bucket, waylineFile.getObjectKey(), file.getInputStream()); |
| | | this.saveWaylineFile(workspaceId, waylineFile); |
| | | |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return waylineFile; |
| | | } |
| | | @Override |
| | | public WaylineFileDTO importPlaneKmzFile(MultipartFile file, String workspaceId, String creator,String newName,String id) { |
| | | WaylineFileDTO waylineFile = null; |
| | | Optional<WaylineFileDTO> waylineFileOpt = validKmzFile(file); |
| | | if (waylineFileOpt.isEmpty()) { |
| | | throw new RuntimeException("文件格式错误"); |
| | | } |
| | | |
| | | try { |
| | | waylineFile = waylineFileOpt.get(); |
| | | waylineFile.setWaylineId(workspaceId); |
| | | waylineFile.setUsername(creator); |
| | | ossService.putObject(OssConfiguration.bucket, waylineFile.getObjectKey(), file.getInputStream()); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return waylineFile; |
| | | } |
| | | |
| | | @Override |
| | | public WaylineFileEntity selectByName(String name) { |
| | | return mapper.selectOne(new LambdaQueryWrapper<WaylineFileEntity>().eq(WaylineFileEntity::getName, name)); |
| | | } |
| | | |
| | | @Override |
| | | public List<WaylineListDTO> waylineList(String workspaceId, String droneName) { |
| | | LambdaQueryChainWrapper<WaylineFileEntity> wrapper = |
| | | new LambdaQueryChainWrapper<>(mapper).eq(WaylineFileEntity::getWorkspaceId, workspaceId); |
| | | if (StringUtils.hasText(droneName)) { |
| | | wrapper.like(WaylineFileEntity::getName, droneName); |
| | | } |
| | | |
| | | return wrapper.list().stream().map(r -> WaylineListDTO.builder().waylineFileId(r.getWaylineId()).name(r.getName()).build()) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | private Optional<WaylineFileDTO> validKmzFile(MultipartFile file) { |
| | | String filename = file.getOriginalFilename(); |
| | | if (Objects.nonNull(filename) && !filename.endsWith(WAYLINE_FILE_SUFFIX)) { |
| | | throw new RuntimeException("文件格式错误"); |
| | | } |
| | | 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; |
| | | } |
| | | SAXReader reader = new SAXReader(); |
| | | Document document = reader.read(unzipFile); |
| | | if (!StandardCharsets.UTF_8.name().equals(document.getXMLEncoding())) { |
| | | throw new RuntimeException("文件编码格式错误"); |
| | | } |
| | | |
| | | 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("文件格式错误"); |
| | | } |
| | | |
| | | String type = droneNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_ENUM_VALUE); |
| | | String subType = droneNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_SUB_ENUM_VALUE); |
| | | String payloadType = payloadNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_ENUM_VALUE); |
| | | String payloadSubType = payloadNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_SUB_ENUM_VALUE); |
| | | String templateType = document.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_TEMPLATE_TYPE); |
| | | |
| | | if (!StringUtils.hasText(type) || !StringUtils.hasText(subType) || |
| | | !StringUtils.hasText(payloadSubType) || !StringUtils.hasText(payloadType) || |
| | | !StringUtils.hasText(templateType)) { |
| | | throw new RuntimeException("文件格式错误"); |
| | | } |
| | | |
| | | return Optional.of(WaylineFileDTO.builder() |
| | | .droneModelKey(String.format("%s-%s-%s", DeviceDomainEnum.SUB_DEVICE.getVal(), type, subType)) |
| | | .payloadModelKeys(List.of(String.format("%s-%s-%s", DeviceDomainEnum.PAYLOAD.getVal(), payloadType, payloadSubType))) |
| | | // .objectKey(OssConfiguration.objectDirPrefix + File.separator + filename) |
| | | .objectKey(OssConfiguration.objectDirPrefix + "/" + filename) |
| | | .name(filename.substring(0, filename.lastIndexOf(WAYLINE_FILE_SUFFIX))) |
| | | .sign(DigestUtils.md5DigestAsHex(file.getInputStream())) |
| | | .templateTypes(List.of(WaylineTemplateTypeEnum.find(templateType).map(WaylineTemplateTypeEnum::getVal).orElse(-1))) |
| | | .build()); |
| | | } |
| | | |
| | | } catch (IOException | DocumentException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return Optional.empty(); |
| | | } |
| | | |
| | | /** |
| | | * Convert database entity objects into wayline data transfer object. |
| | | * |
| | | * @param entity |
| | | * @return |
| | | */ |
| | | private WaylineFileDTO entityConvertToDTO(WaylineFileEntity entity) { |
| | | WaylineFileDTO.WaylineFileDTOBuilder builder = WaylineFileDTO.builder(); |
| | | |
| | | if (entity != null) { |
| | | builder.droneModelKey(entity.getDroneModelKey()) |
| | | .favorited(entity.getFavorited()) |
| | | .name(entity.getName()) |
| | | .payloadModelKeys(entity.getPayloadModelKeys() != null ? |
| | | Arrays.asList(entity.getPayloadModelKeys().split(",")) : null) |
| | | .templateTypes(Arrays.stream(entity.getTemplateTypes().split(",")) |
| | | .map(Integer::parseInt) |
| | | .collect(Collectors.toList())) |
| | | .username(entity.getUsername()) |
| | | .objectKey(entity.getObjectKey()) |
| | | .updateTime(entity.getUpdateTime()) |
| | | .waylineId(entity.getWaylineId()); |
| | | if (entity == null) { |
| | | return null; |
| | | } |
| | | return WaylineFileDTO.builder() |
| | | .droneModelKey(entity.getDroneModelKey()) |
| | | .favorited(entity.getFavorited()) |
| | | .name(entity.getName()) |
| | | .patchesId(entity.getPatchesId()) |
| | | .payloadModelKeys(entity.getPayloadModelKeys() != null ? |
| | | Arrays.asList(entity.getPayloadModelKeys().split(",")) : null) |
| | | .templateTypes(Arrays.stream(entity.getTemplateTypes().split(",")) |
| | | .map(Integer::parseInt) |
| | | .collect(Collectors.toList())) |
| | | .username(entity.getUsername()) |
| | | .objectKey(entity.getObjectKey()) |
| | | .sign(entity.getSign()) |
| | | .updateTime(entity.getUpdateTime()) |
| | | .waylineId(entity.getWaylineId()) |
| | | .build(); |
| | | |
| | | return builder.build(); |
| | | } |
| | | |
| | | /** |
| | | * Convert the received wayline object into a database entity object. |
| | | * |
| | | * @param file |
| | | * @return |
| | | */ |
| | |
| | | .map(String::valueOf) |
| | | .collect(Collectors.joining(","))) |
| | | .favorited(file.getFavorited()) |
| | | .sign(file.getSign()) |
| | | .patchesId(file.getPatchesId()) |
| | | .spotInFreckle(file.getSpotInFreckle()) |
| | | .build(); |
| | | } |
| | | |
| | | return builder.build(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public int updateWayline(WaylineFileEntity entity) { |
| | | return mapper.update(entity, new LambdaQueryWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWaylineId, entity.getWaylineId())); |
| | | } |
| | | } |