增加国标直播接口,完成人工图片与图斑绑定,修改图片获取接口,获取前更新人工图片的图斑绑定
14 files modified
2 files added
480 ■■■■ changed files
pom.xml 8 ●●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/manage/controller/LiveStreamController.java 5 ●●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/manage/dao/IDeviceSetMapper.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/manage/model/entity/DeviceSetEntity.java 53 ●●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/manage/service/ILiveStreamService.java 2 ●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java 118 ●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/media/model/MediaFileMarkEntity.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/media/service/IFileService.java 2 ●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java 239 ●●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/patches/controller/PatchesController.java 4 ●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/patches/service/impl/GetPatchesServiceImpl.java 19 ●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/wayline/controller/WaylineFileController.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/wayline/model/dto/WaylineFileDTO.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/wayline/model/entity/WaylineFileEntity.java 4 ●●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/wayline/service/IWaylineFileService.java 2 ●●● patch | view | raw | blame | history
src/main/java/com/dji/sample/wayline/service/impl/WaylineFileServiceImpl.java 5 ●●●●● patch | view | raw | blame | history
pom.xml
@@ -318,6 +318,14 @@
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>16</source>
                    <target>16</target>
                </configuration>
            </plugin>
        </plugins>
        <!--配置后才可以扫描到xml文件-->
src/main/java/com/dji/sample/manage/controller/LiveStreamController.java
@@ -73,6 +73,11 @@
        return liveStreamService.liveStart(liveParam);
    }
    @PostMapping("/streams/address")
    public ResponseResult liveAddress(@RequestParam String deviceSn,@RequestParam String deviceId) {
        return liveStreamService.liveAddress(deviceSn,deviceId);
    }
    /**
     * Stop live streaming according to the parameters passed in from the web side.
     * 根据从web端传入的参数停止直播。
src/main/java/com/dji/sample/manage/dao/IDeviceSetMapper.java
New file
@@ -0,0 +1,8 @@
package com.dji.sample.manage.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dji.sample.manage.model.entity.DevicePayloadEntity;
import com.dji.sample.manage.model.entity.DeviceSetEntity;
public interface IDeviceSetMapper extends BaseMapper<DeviceSetEntity> {
}
src/main/java/com/dji/sample/manage/model/entity/DeviceSetEntity.java
New file
@@ -0,0 +1,53 @@
package com.dji.sample.manage.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "device_set")
public class DeviceSetEntity {
    @TableId(type = IdType.AUTO)
    private Integer id;
    @TableField(value = "device_sn")
    private String deviceSn;
    @TableField(value = "agent_id")
    private String agentId;
    @TableField(value = "channel")
    private String channel;
    @TableField(value = "server_ip")
    private String serverIp;
    @TableField(value = "server_port")
    private String serverPort;
    @TableField(value = "agent_password")
    private String agentPassword;
    @TableField(value = "local_port")
    private String localPort;
    @TableField(value = "gbServer_id")
    private String gbServerId;
    @TableField(value = "device_id")
    private String deviceId;
    @TableField(value = "workspace_id")
    private String workspaceId;
}
src/main/java/com/dji/sample/manage/service/ILiveStreamService.java
@@ -36,7 +36,7 @@
     * @return
     */
    ResponseResult liveStart(LiveTypeDTO liveParam);
    ResponseResult liveAddress(String deviceSn,String deviceId);
    /**
     * Stop the live streaming by publishing mqtt message.
     * 通过发布mqtt消息来停止实时流。
src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java
@@ -1,5 +1,6 @@
package com.dji.sample.manage.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dji.sample.common.error.LiveErrorEnum;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.component.mqtt.model.CommonTopicResponse;
@@ -7,7 +8,9 @@
import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.dji.sample.component.redis.RedisConst;
import com.dji.sample.component.redis.RedisOpsUtils;
import com.dji.sample.manage.dao.IDeviceSetMapper;
import com.dji.sample.manage.model.dto.*;
import com.dji.sample.manage.model.entity.DeviceSetEntity;
import com.dji.sample.manage.model.enums.DeviceDomainEnum;
import com.dji.sample.manage.model.enums.LiveStreamMethodEnum;
import com.dji.sample.manage.model.enums.LiveUrlTypeEnum;
@@ -16,6 +19,8 @@
import com.dji.sample.manage.model.receiver.CapacityDeviceReceiver;
import com.dji.sample.manage.model.receiver.LiveCapacityReceiver;
import com.dji.sample.manage.service.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -24,6 +29,8 @@
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.dji.sample.component.mqtt.model.TopicConst.*;
@@ -42,6 +49,8 @@
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private IDeviceSetMapper deviceSetMapper;
    @Autowired
    private IWorkspaceService workspaceService;
@@ -51,7 +60,6 @@
    @Autowired
    private IDeviceRedisService deviceRedisService;
    @Override
    public List<CapacityDeviceDTO> getLiveCapacity(String workspaceId,String sn) {
@@ -117,15 +125,15 @@
        //相机已经在直播中,请勿重复开启直播
        if(receiveReply.getResult() == 513003) {
            LiveDTO live = new LiveDTO();
            live.setUrl(liveParam.getUrl().replace("rtmp", "https").replace("735","700") + ".flv");
//            LiveUrlGB28181DTO gb28181 = urlToGB28181(liveParam.getUrl());
//            live.setUrl(new StringBuilder()
//                    .append("https://wrj.shuixiongit.com/zb/rtp/")
//                    .append(gb28181.getAgentID())
//                    .append("_")
//                    .append(gb28181.getChannel())
//                    .append(".live.flv")
//                    .toString());
//            live.setUrl(liveParam.getUrl().replace("rtmp", "https").replace("735","700") + ".flv");
            LiveUrlGB28181DTO gb28181 = urlToGB28181(liveParam.getUrl());
            live.setUrl(new StringBuilder()
                    .append("https://wrj.shuixiongit.com/zb/rtp/")
                    .append(gb28181.getAgentID())
                    .append("_")
                    .append(gb28181.getChannel())
                    .append(".live.flv")
                    .toString());
            return ResponseResult.success(live);
        }
@@ -142,27 +150,27 @@
//                live.setUrl(liveParam.getUrl().replace("rtmp", "webrtc"));
                live.setUrl(liveParam.getUrl().replace("rtmp", "https").replace("735","700") + ".flv");
                break;
            case GB28181:
                LiveUrlGB28181DTO gb28181 = urlToGB28181(liveParam.getUrl());
                live.setUrl(new StringBuilder()
                        .append("webrtc://")
                        .append(gb28181.getServerIP())
                        .append("/live/")
                        .append(gb28181.getAgentID())
                        .append("@")
                        .append(gb28181.getChannel())
                        .toString());
                break;
//            case GB28181:
//                LiveUrlGB28181DTO gb28181 = urlToGB28181(liveParam.getUrl());
//                live.setUrl(new StringBuilder()
//                        .append("https://wrj.shuixiongit.com/zb/rtp/")
//                        .append("webrtc://")
//                        .append(gb28181.getServerIP())
//                        .append("/live/")
//                        .append(gb28181.getAgentID())
//                        .append("_")
//                        .append("@")
//                        .append(gb28181.getChannel())
//                        .append(".live.flv")
//                        .toString());
//                break;
            case GB28181:
                LiveUrlGB28181DTO gb28181 = urlToGB28181(liveParam.getUrl());
                live.setUrl(new StringBuilder()
                        .append("https://wrj.shuixiongit.com/zb/rtp/")
                        .append(gb28181.getAgentID())
                        .append("_")
                        .append(gb28181.getChannel())
                        .append(".live.flv")
                        .toString());
                break;
            case RTSP:
                String url = receiveReply.getOutput().toString();
                this.resolveUrlUser(url, live);
@@ -172,7 +180,63 @@
        }
        return ResponseResult.success(live);
    }
    @Override
    public ResponseResult liveAddress(String deviceSn,String deviceId) {
       DeviceSetEntity deviceSet= deviceSetMapper.selectOne(new LambdaQueryWrapper<DeviceSetEntity>()
                .eq(DeviceSetEntity::getDeviceSn,deviceSn)
                .eq(DeviceSetEntity::getDeviceId,deviceId)
        );
        String workspaceId=getIdBySn(deviceSn);
        List<CapacityDeviceDTO> dto=getLiveCapacity(workspaceId,deviceSn);
        String vedioId=deviceSn+"/165-0-7/normal-0";
        String url="https://"+deviceSet.getServerIp()+"/zb/rtp/"+deviceSet.getAgentId()+"_"+deviceSet.getChannel()+".live.flv";
        LiveTypeDTO liveParam=new LiveTypeDTO();
        liveParam.setUrl(url);
        liveParam.setUrlType(3);
        liveParam.setVideoId(vedioId);
        liveParam.setVideoQuality(0);
        ResponseResult responseResult = this.checkBeforeLive(liveParam.getVideoId());
        if (ResponseResult.CODE_SUCCESS != responseResult.getCode()) {
            return responseResult;
        }
        DeviceDTO data = (DeviceDTO)responseResult.getData();
        String respTopic = THING_MODEL_PRE + PRODUCT +
                data.getDeviceSn() + SERVICES_SUF;
        //获取返回结果
        ServiceReply receiveReply = this.publishLiveStart(respTopic, liveParam);
        System.out.println(receiveReply.getResult());
        LiveDTO live = new LiveDTO();
        live.setUrl(url);
        //相机已经在直播中,请勿重复开启直播
        if(receiveReply.getResult() == 513003) {
            return ResponseResult.success(live);
        }
        return ResponseResult.success(live);
    }
        public static String getVedioId(String data,String sn) {
            return findDeviceBySn(data, sn);
        }
        public static String findDeviceBySn(String dtoListString, String snToFind) {
            String regex = "CapacityDeviceDTO\\(sn=" + snToFind + ", .*? index=([\\w\\-]+).*? index=([\\w\\-]+).*?\\)";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(dtoListString);
            if (matcher.find()) {
                String index1 = matcher.group(1);
                String index2 = matcher.group(2);
                return snToFind + "/" + index1 + "/" + index2;
            }
            return null; // 如果未找到匹配的sn,则返回null或者适当的默认值
        }
    @Override
    public ResponseResult liveStop(String videoId) {
@@ -180,10 +244,8 @@
        if (responseResult.getCode() != 0) {
            return responseResult;
        }
        //thing/product/{gateway_sn}/services
        String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().getDeviceSn() + SERVICES_SUF;
        videoId = videoId.replace("_","/");
        ServiceReply receiveReply = this.publishLiveStop(respTopic, videoId);
@@ -351,6 +413,10 @@
        return messageSender.publishWithReply(ServiceReply.class, topic, response);
    }
    private String getIdBySn(String dockSn){
        DeviceSetEntity entity=deviceSetMapper.selectOne(new LambdaQueryWrapper<DeviceSetEntity>().eq(DeviceSetEntity::getDeviceSn,dockSn));
        return entity.getWorkspaceId();
    }
    /**
     * Send a message to the pilot via mqtt to set quality.
     * @param respTopic
src/main/java/com/dji/sample/media/model/MediaFileMarkEntity.java
@@ -72,6 +72,9 @@
    @TableField("user_id")
    private String userId;
    @TableField("isadd")
    private Integer isadd;
    @TableField(value = "metadata", typeHandler = FastjsonTypeHandler.class)
    private Object metadata;
src/main/java/com/dji/sample/media/service/IFileService.java
@@ -48,7 +48,7 @@
     * @throws ImageProcessingException
     */
    void saveMarkFile(String workspaceId, FileUploadDTO file) throws IOException, FontFormatException, ImageProcessingException;
    void updateMarkMediaFileNames(String jobId);
    /**
     * 获取媒体文件状态
     * @param fileId
src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java
@@ -1,6 +1,9 @@
package com.dji.sample.media.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
@@ -28,8 +31,12 @@
import com.dji.sample.wayline.service.IWaylineFileService;
import com.dji.sample.wayline.service.IWaylineJobService;
import com.drew.imaging.ImageProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -72,6 +79,9 @@
    @Autowired
    private IWaylineFileService waylineFileService;
    private ObjectMapper objectMapper = new ObjectMapper();
    private Optional<MediaFileEntity> getMediaByFingerprint(String workspaceId, String fingerprint) {
        MediaFileEntity fileEntity = mapper.selectOne(new LambdaQueryWrapper<MediaFileEntity>()
                .eq(MediaFileEntity::getWorkspaceId, workspaceId)
@@ -96,7 +106,6 @@
        MediaFileEntity fileEntity = this.fileUploadConvertToEntity(file);
        fileEntity.setWorkspaceId(workspaceId);
        fileEntity.setFileId(UUID.randomUUID().toString());
        updateInvestigate(file.getExt().getFlightId());
        return mapper.insert(fileEntity);
    }
@@ -120,7 +129,6 @@
                    patchesMapper.update(null, updateWrapper);
                }
            }
            MediaFileMarkEntity mediaFileMarkEntity = this.fileUploadConvertToMarkEntity(file);
            String url = "http://dev.jxpskj.com:9000/cloud-bucket" + file.getObjectKey();
            File file1 = TbFjServiceImpl.downloadFile(url);
@@ -130,6 +138,7 @@
            Object data = ImgUtil.getInfo(file1);
            mediaFileMarkEntity.setDronedata(data);
            mediaFileMarkEntity.setWorkspaceId(workspaceId);
            mediaFileMarkEntity.setIsadd(0);
            mediaFileMarkEntity.setFileId(UUID.randomUUID().toString());
            mediaFileMarkEntity.setObjectKey("/mark" + file.getPath() + "/" + file.getName());
            mediaFileMarkEntity.setFileName("mark" + file.getName());
@@ -143,6 +152,7 @@
            markMapper.insert(mediaFileMarkEntity);
        }
    }
    @Override
    public Object mediaInfo(String filename) {
@@ -162,7 +172,7 @@
    }
    @Override
    public PaginationData<MediaFileEntity> MediaQuery(Integer page, Integer pageSize, Long updateStart, Long updateEnd, Long photoStart, Long photoEnd, String jobName, String workspaceId,String type) {
    public PaginationData<MediaFileEntity> MediaQuery(Integer page, Integer pageSize, Long updateStart, Long updateEnd, Long photoStart, Long photoEnd, String jobName, String workspaceId, String type) {
        // 创建分页对象
        Page<MediaFileEntity> pageObj = new Page<>(page, pageSize);
@@ -170,7 +180,7 @@
        LambdaQueryWrapper<MediaFileEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件
        queryWrapper.eq(MediaFileEntity::getWorkspaceId,workspaceId);
        queryWrapper.eq(MediaFileEntity::getWorkspaceId, workspaceId);
        if (updateStart != null && updateEnd != null) {
            queryWrapper.between(MediaFileEntity::getCreateTime, updateStart, updateEnd);
@@ -217,22 +227,6 @@
    }
    public void updateInvestigate(String jobId){
        String waylineId=waylineJobService.getWaylineId(jobId);
        String patchesId=waylineFileService.getPatchesId(waylineId);
        if (patchesId==null){
            return;
        }
        List<Long> ids = Arrays.stream(patchesId.split(","))
                .map(Long::parseLong)
                .collect(Collectors.toList());
        LambdaUpdateWrapper<LotInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(LotInfo::getId, ids)
                .set(LotInfo::getInvestigate, 1)
                .set(LotInfo::getIsPlan,1);
        patchesMapper.update(null, updateWrapper);
    }
    @Override
    public List<MediaFileEntity> listMediaFileEntity(String workspaceId, String jobId) {
@@ -268,6 +262,12 @@
        MediaFileEntity entity = mapper.selectOne(new LambdaQueryWrapper<MediaFileEntity>()
                .eq(MediaFileEntity::getFileId, fileId));
        return entity.getExamine();
    }
    public String getDkbhName(String name) {
        int startIndex = name.indexOf("点") + 1;
        int endIndex = name.indexOf(".");
        return name.substring(startIndex, endIndex);
    }
    @Override
@@ -420,7 +420,7 @@
        return builder.build();
    }
    public static void uploadFile(String endpoint, String accessKey, String secretKey, String bucketName, String objectName, File file ) {
    public static void uploadFile(String endpoint, String accessKey, String secretKey, String bucketName, String objectName, File file) {
        try {
            // 创建MinIO客户端实例
            MinioClient minioClient = MinioClient.builder()
@@ -447,6 +447,203 @@
        // 获取时间戳(毫秒级别)
        return date.getTime();
    }
    public List<MediaFileEntity> getSameJobId(String jobId) {
        return mapper.selectList(new LambdaQueryWrapper<MediaFileEntity>()
                .eq(MediaFileEntity::getJobId, jobId));
    }
    public void updateMediaFileNames(String jobId) {
        // 查询符合条件的数据
        List<MediaFileEntity> mediaFiles = mapper.selectList(new LambdaQueryWrapper<MediaFileEntity>()
                        .eq(MediaFileEntity::getJobId, jobId)
//                .eq(MediaFileMarkEntity::getIsadd, 0)
        );
        // 筛选出name字段不包含'~'的数据
        List<MediaFileEntity> filteredFiles = mediaFiles.stream()
                .filter(file -> !file.getFileName().contains("~"))
                .toList();
        for (MediaFileEntity currentFile : filteredFiles) {
            String currentName = currentFile.getFileName();
            Map<String, Object> currentMetadata = JSON.parseObject(JSON.toJSONString(currentFile.getMetadata()), Map.class);
            Long currentCreatedTime = (Long) currentMetadata.get("createdTime");
            // 找到metadata中的createdTime小于当前数据的createdTime且最接近的那条数据
            Optional<MediaFileEntity> closestFileOpt = mediaFiles.stream()
                    .filter(file -> {
                        Map<String, Object> metadata = JSON.parseObject(JSON.toJSONString(file.getMetadata()), Map.class);
                        Long createdTime = (Long) metadata.get("createdTime");
                        String filename = file.getFileName();
                        return createdTime < currentCreatedTime && filename.contains("~");
                    })
                    .min((file1, file2) -> {
                        Map<String, Object> metadata1 = JSON.parseObject(JSON.toJSONString(file1.getMetadata()), Map.class);
                        Map<String, Object> metadata2 = JSON.parseObject(JSON.toJSONString(file2.getMetadata()), Map.class);
                        Long time1 = (Long) metadata1.get("createdTime");
                        Long time2 = (Long) metadata2.get("createdTime");
                        return Long.compare(currentCreatedTime - time1, currentCreatedTime - time2);
                    });
            if (closestFileOpt.isEmpty()) {
                // 找不到小于的文件,尝试找大于且最接近的文件
                closestFileOpt = mediaFiles.stream()
                        .filter(file -> {
                            Map<String, Object> metadata = JSON.parseObject(JSON.toJSONString(file.getMetadata()), Map.class);
                            Long createdTime = (Long) metadata.get("createdTime");
                            String filename = file.getFileName();
                            return createdTime > currentCreatedTime && filename.contains("~");
                        })
                        .min((file1, file2) -> {
                            Map<String, Object> metadata1 = JSON.parseObject(JSON.toJSONString(file1.getMetadata()), Map.class);
                            Map<String, Object> metadata2 = JSON.parseObject(JSON.toJSONString(file2.getMetadata()), Map.class);
                            Long time1 = (Long) metadata1.get("createdTime");
                            Long time2 = (Long) metadata2.get("createdTime");
                            return Long.compare(time1 - currentCreatedTime, time2 - currentCreatedTime);
                        });}
            if (closestFileOpt.isEmpty()) {
                throw new RuntimeException("当前图片无法绑定图斑");
            }
            // 提取并替换name字段
            closestFileOpt.ifPresent(closestFile -> {
                String closestName = closestFile.getFileName();
                int startIndex = closestName.indexOf("V");
                if (closestName.contains("W")) {
                    startIndex = closestName.indexOf("W");
                }
                if (closestName.contains("Z")) {
                    startIndex = closestName.indexOf("Z");
                }
                int endIndex = closestName.indexOf(".", startIndex);
                String replacement = closestName.substring(startIndex, endIndex);
                int currentStartIndex = currentName.indexOf("V");
                if (currentName.contains("W")) {
                    currentStartIndex = closestName.indexOf("W");
                }
                if (currentName.contains("Z")) {
                    currentStartIndex = closestName.indexOf("Z");
                }
                int currentEndIndex = currentName.indexOf(".", currentStartIndex);
                String newName = currentName.substring(0, currentStartIndex)
                        + replacement
                        + currentName.substring(currentEndIndex);
                currentFile.setFileName(newName);
                updateMediaById(currentFile.getId(), currentFile);
            });
        }
    }
    @Override
    public void updateMarkMediaFileNames(String jobId) {
        try {
            // 查询符合条件的数据
            List<MediaFileMarkEntity> mediaFiles = markMapper.selectList(new LambdaQueryWrapper<MediaFileMarkEntity>()
                            .eq(MediaFileMarkEntity::getJobId, jobId)
//                .eq(MediaFileMarkEntity::getIsadd, 0)
            );
            // 筛选出name字段不包含'~'的数据
            List<MediaFileMarkEntity> filteredFiles = mediaFiles.stream()
                    .filter(file -> !file.getFileName().contains("~"))
                    .toList();
            for (MediaFileMarkEntity currentFile : filteredFiles) {
                String currentName = currentFile.getFileName();
                Map<String, Object> currentMetadata = JSON.parseObject(JSON.toJSONString(currentFile.getMetadata()), Map.class);
                Long currentCreatedTime = (Long) currentMetadata.get("createdTime");
                // 找到metadata中的createdTime小于当前数据的createdTime且最接近的那条数据
                Optional<MediaFileMarkEntity> closestFileOpt = mediaFiles.stream()
                        .filter(file -> {
                            Map<String, Object> metadata = JSON.parseObject(JSON.toJSONString(file.getMetadata()), Map.class);
                            Long createdTime = (Long) metadata.get("createdTime");
                            String filename = file.getFileName();
                            return createdTime < currentCreatedTime && filename.contains("~");
                        })
                        .min((file1, file2) -> {
                            Map<String, Object> metadata1 = JSON.parseObject(JSON.toJSONString(file1.getMetadata()), Map.class);
                            Map<String, Object> metadata2 = JSON.parseObject(JSON.toJSONString(file2.getMetadata()), Map.class);
                            Long time1 = (Long) metadata1.get("createdTime");
                            Long time2 = (Long) metadata2.get("createdTime");
                            return Long.compare(currentCreatedTime - time1, currentCreatedTime - time2);
                        });
                if (closestFileOpt.isEmpty()) {
                    // 找不到小于的文件,尝试找大于且最接近的文件
                    closestFileOpt = mediaFiles.stream()
                            .filter(file -> {
                                Map<String, Object> metadata = JSON.parseObject(JSON.toJSONString(file.getMetadata()), Map.class);
                                Long createdTime = (Long) metadata.get("createdTime");
                                String filename = file.getFileName();
                                return createdTime > currentCreatedTime && filename.contains("~");
                            })
                            .min((file1, file2) -> {
                                Map<String, Object> metadata1 = JSON.parseObject(JSON.toJSONString(file1.getMetadata()), Map.class);
                                Map<String, Object> metadata2 = JSON.parseObject(JSON.toJSONString(file2.getMetadata()), Map.class);
                                Long time1 = (Long) metadata1.get("createdTime");
                                Long time2 = (Long) metadata2.get("createdTime");
                                return Long.compare(time1 - currentCreatedTime, time2 - currentCreatedTime);
                            });
                }
                if (closestFileOpt.isEmpty()) {
                    throw new RuntimeException("没有符合时间的对象");
                }
                // 提取并替换name字段
                closestFileOpt.ifPresent(closestFile -> {
                    String closestName = closestFile.getFileName();
                    int startIndex = closestName.indexOf("V");
                    if (closestName.contains("W")) {
                        startIndex = closestName.indexOf("W");
                    }
                    if (closestName.contains("Z")) {
                        startIndex = closestName.indexOf("Z");
                    }
                    int endIndex = closestName.indexOf(".", startIndex);
                    String replacement = closestName.substring(startIndex, endIndex);
                    int currentStartIndex = currentName.indexOf("V");
                    if (currentName.contains("W")) {
                        currentStartIndex = closestName.indexOf("W");
                    }
                    if (currentName.contains("Z")) {
                        currentStartIndex = closestName.indexOf("Z");
                    }
                    int currentEndIndex = currentName.indexOf(".", currentStartIndex);
                    String newName = currentName.substring(0, currentStartIndex)
                            + replacement
                            + currentName.substring(currentEndIndex);
                    currentFile.setFileName(newName);
                    updateById(currentFile.getId(), currentFile);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void updateById(Integer id, MediaFileMarkEntity entity) {
        entity.setIsadd(1);
        UpdateWrapper<MediaFileMarkEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        markMapper.update(entity, updateWrapper);
    }
    public void updateMediaById(Integer id, MediaFileEntity entity) {
        UpdateWrapper<MediaFileEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        mapper.update(entity, updateWrapper);
    }
    public void getNoaddFile() {
        List<MediaFileMarkEntity> markEntities = markMapper.selectList(new LambdaQueryWrapper<MediaFileMarkEntity>().eq(MediaFileMarkEntity::getIsadd, 0));
        for (MediaFileMarkEntity mark : markEntities) {
            updateMarkMediaFileNames(mark.getJobId());
            updateMediaFileNames(mark.getJobId());
        }
    }
}
src/main/java/com/dji/sample/patches/controller/PatchesController.java
@@ -6,6 +6,7 @@
import com.dji.sample.common.util.MinioUrlUtils;
import com.dji.sample.log.aspect.SysLogAnnotation;
import com.dji.sample.media.model.MediaFileEntity;
import com.dji.sample.media.service.impl.FileServiceImpl;
import com.dji.sample.patches.model.Param.PatchesParam;
import com.dji.sample.patches.model.entity.LotInfo;
import com.dji.sample.patches.service.GetPatchesService;
@@ -46,6 +47,8 @@
    private IWaylineJobService waylineJobService;
    @Autowired
    private TbDkjbxxServiceImpl tbDkjbxxService;
    @Autowired
    private FileServiceImpl fileService;
    @Autowired
    private TimerUtil timerUtil;
@@ -199,6 +202,7 @@
                                                                           @RequestParam(name = "page_size", defaultValue = "10") Integer pageSize,
                                                                           @RequestParam String workspaceId,
                                                                           @RequestParam String dkbh) {
        fileService.getNoaddFile();
        try {
            PatchesParam param = PatchesParam.builder()
                    .page(page)
src/main/java/com/dji/sample/patches/service/impl/GetPatchesServiceImpl.java
@@ -7,7 +7,9 @@
import com.dji.sample.common.model.Pagination;
import com.dji.sample.common.model.PaginationData;
import com.dji.sample.media.dao.IFileMapper;
import com.dji.sample.media.dao.IMarkMapper;
import com.dji.sample.media.model.MediaFileEntity;
import com.dji.sample.media.model.MediaFileMarkEntity;
import com.dji.sample.patches.dao.GetPatchesMapper;
import com.dji.sample.patches.model.Param.PatchesParam;
import com.dji.sample.patches.model.entity.LotInfo;
@@ -27,6 +29,8 @@
    private GetPatchesMapper mapper;
    @Autowired
    private IFileMapper fileMapper;
    @Autowired
    private IMarkMapper markMapper;
    /**
     * 分页获取数据的接口实现。
@@ -90,13 +94,24 @@
    }
    @Override
    public PaginationData<MediaFileEntity> getPhoto(PatchesParam param, String dkbh) {
    public PaginationData getPhoto(PatchesParam param, String dkbh) {
        LotInfo lotInfo=getLotinfoToDb(dkbh);
        int statue=lotInfo.getIsPush();
        if (statue==0){
        Page<MediaFileEntity> page = fileMapper.selectPage(new Page<MediaFileEntity>(param.getPage(), param.getPageSize()),
                new LambdaQueryWrapper<MediaFileEntity>().like(MediaFileEntity::getFileName, "%" + dkbh + "~" + "%"));
        List<MediaFileEntity> records = page.getRecords()
                .stream()
                .collect(Collectors.toList());
        return new PaginationData<MediaFileEntity>(records, new Pagination(page));
        return new PaginationData<MediaFileEntity>(records, new Pagination(page));}
        else {
            Page<MediaFileMarkEntity> page = markMapper.selectPage(new Page<MediaFileMarkEntity>(param.getPage(), param.getPageSize()),
                    new LambdaQueryWrapper<MediaFileMarkEntity>().like(MediaFileMarkEntity::getFileName, "%" + dkbh + "~" + "%"));
            List<MediaFileMarkEntity> records = page.getRecords()
                    .stream()
                    .collect(Collectors.toList());
            return new PaginationData<MediaFileMarkEntity>(records, new Pagination(page));}
    }
    public List<MediaFileEntity> listPohto(String dkbh, String workspaceId) {
src/main/java/com/dji/sample/wayline/controller/WaylineFileController.java
@@ -197,13 +197,15 @@
    @SysLogAnnotation(operModul = "航线库", operType = "上传", operDesc = "上传kmz航线文件")
    public ResponseResult importKmzFile(@PathVariable(name = "workspace_id") String workspaceId,
                                        HttpServletRequest request, MultipartFile file,
                                        @RequestParam(required = false) String patchesId) {
                                        @RequestParam(required = false) String patchesId,
                                        @RequestParam(required = false) String spotInFreckle
    ) {
        if (Objects.isNull(file)) {
            return ResponseResult.error("未上传文件");
        }
        CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM);
        String creator = customClaim.getUsername();
        waylineFileService.importKmzFile(file, workspaceId, creator,patchesId);
        waylineFileService.importKmzFile(file, workspaceId, creator,patchesId,spotInFreckle);
        return ResponseResult.success();
    }
src/main/java/com/dji/sample/wayline/model/dto/WaylineFileDTO.java
@@ -42,4 +42,6 @@
    private Long updateTime;
    private String patchesId;
    private String spotInFreckle;
}
src/main/java/com/dji/sample/wayline/model/entity/WaylineFileEntity.java
@@ -7,6 +7,7 @@
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
 * @author sean
@@ -56,6 +57,9 @@
    @TableField("patches_id")
    private String patchesId;
    @TableField("spotIn_freckle")
    private String spotInFreckle;
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Long createTime;
src/main/java/com/dji/sample/wayline/service/IWaylineFileService.java
@@ -83,7 +83,7 @@
     * @param creator
     * @return
     */
    void importKmzFile(MultipartFile file, String workspaceId, String creator,String patchesId);
    void importKmzFile(MultipartFile file, String workspaceId, String creator,String patchesId,String spotInFreckle);
    /**
     * 创建航线,返回航线对象
src/main/java/com/dji/sample/wayline/service/impl/WaylineFileServiceImpl.java
@@ -192,7 +192,7 @@
    }
    @Override
    public void importKmzFile(MultipartFile file, String workspaceId, String creator, String patchesId) {
    public void importKmzFile(MultipartFile file, String workspaceId, String creator, String patchesId,String spotInFreckle) {
        Optional<WaylineFileDTO> waylineFileOpt = validKmzFile(file);
        if (waylineFileOpt.isEmpty()) {
            throw new RuntimeException("文件格式错误");
@@ -202,7 +202,7 @@
            WaylineFileDTO waylineFile = waylineFileOpt.get();
            waylineFile.setWaylineId(workspaceId);
            waylineFile.setUsername(creator);
            waylineFile.setSpotInFreckle(spotInFreckle);
            ossService.putObject(OssConfiguration.bucket, waylineFile.getObjectKey(), file.getInputStream());
            this.saveWaylineFiles(workspaceId, waylineFile, patchesId);
        } catch (IOException e) {
@@ -355,6 +355,7 @@
                    .favorited(file.getFavorited())
                    .sign(file.getSign())
                    .patchesId(file.getPatchesId())
                    .spotInFreckle(file.getSpotInFreckle())
                    .build();
        }