zhaowenyu
2025-10-20 fc365c426e431a73d116e5d51deaec667f4864de
Merge remote-tracking branch 'origin/dev' into dev
13 files added
26 files modified
1401 ■■■■■ changed files
ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFileController.java 111 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFolderController.java 120 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java 6 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/core/config/ApiGroup.java 41 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/core/config/SwaggerConfig.java 159 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/domain/ArdRouteFile.java 45 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/domain/ArdRouteFolder.java 29 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/mapper/ArdRouteFileMapper.java 69 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/mapper/ArdRouteFolderMapper.java 62 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/service/IArdRouteFileService.java 62 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/service/IArdRouteFolderService.java 63 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFileServiceImpl.java 97 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFolderServiceImpl.java 131 ●●●●● patch | view | raw | blame | history
ard-route/src/main/resources/mapper/ArdRouteFileMapper.xml 108 ●●●●● patch | view | raw | blame | history
ard-route/src/main/resources/mapper/ArdRouteFolderMapper.xml 84 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/aspect/UavControlAspect.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/forest/MyAddressSource.java 10 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/TyTcpClientManager.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/cache/TyTcpServerCache.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/handler/ClientHandler.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/BaseSubscriptionManager.java 9 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java 4 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavAllManager.java 6 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java 7 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavSignalManager.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStateManager.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStreamManager.java 19 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavTelemetryManager.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/cache/UavSignalInfoCache.java 24 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/cache/UavStateCache.java 24 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/cache/UavTelemetryDataCache.java 24 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/dto/signal/SignalInfo.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/dto/state/UavState.java 6 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/dto/telemetry/TelemetryData.java 6 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/receiver/BoxStreamUrlReceiver.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/receiver/TyHttpCommonReceiver.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/ITyService.java 4 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java 49 ●●●●● patch | view | raw | blame | history
ard-work/src/main/resources/mapper/ArdDroneInfoMapper.xml 2 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFileController.java
New file
@@ -0,0 +1,111 @@
package com.ard.web.controller.route;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.ard.common.annotation.Log;
import com.ard.common.core.controller.BaseController;
import com.ard.common.core.domain.AjaxResult;
import com.ard.common.core.page.TableDataInfo;
import com.ard.common.enums.BusinessType;
import com.ard.common.utils.poi.ExcelUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ard.route.domain.ArdRouteFile;
import com.ard.route.service.IArdRouteFileService;
/**
 * 文件Controller
 *
 * @author xia
 * @date 2025-10-18
 */
@Api(tags = "文件")
@RestController
@RequestMapping("/file")
public class ArdRouteFileController extends BaseController {
    @Autowired
    private IArdRouteFileService ardRouteFileService;
    /**
     * 查询文件列表
     */
    @ApiOperation("查询文件列表")
    @PreAuthorize("@ss.hasPermi('route:file:list')")
    @GetMapping("/list")
    public TableDataInfo list(ArdRouteFile ardRouteFile) {
        startPage();
        List<ArdRouteFile> list = ardRouteFileService.selectArdRouteFileList(ardRouteFile);
        return getDataTable(list);
    }
    /**
     * 导出文件列表
     */
    @ApiOperation("导出文件列表")
    @PreAuthorize("@ss.hasPermi('route:file:export')")
    @Log(title = "文件", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ArdRouteFile ardRouteFile) {
        List<ArdRouteFile> list = ardRouteFileService.selectArdRouteFileList(ardRouteFile);
        ExcelUtil<ArdRouteFile> util = new ExcelUtil<ArdRouteFile>(ArdRouteFile.class);
        util.exportExcel(response, list, "文件数据");
    }
    /**
     * 获取文件详细信息
     */
    @ApiOperation("获取文件详细信息")
    @PreAuthorize("@ss.hasPermi('route:file:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") String id) {
        return success(ardRouteFileService.selectArdRouteFileById(id));
    }
    /**
     * 新增文件
     */
    @ApiOperation("新增文件")
    @PreAuthorize("@ss.hasPermi('route:file:add')")
    @Log(title = "文件", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody ArdRouteFile ardRouteFile) {
        ardRouteFile.setCreateBy(getUsername());
        return toAjax(ardRouteFileService.insertArdRouteFile(ardRouteFile));
    }
    /**
     * 修改文件
     */
    @ApiOperation("修改文件")
    @PreAuthorize("@ss.hasPermi('route:file:edit')")
    @Log(title = "文件", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody ArdRouteFile ardRouteFile) {
        ardRouteFile.setUpdateBy(getUsername());
        return toAjax(ardRouteFileService.updateArdRouteFile(ardRouteFile));
    }
    /**
     * 删除文件
     */
    @ApiOperation("删除文件")
    @PreAuthorize("@ss.hasPermi('route:file:remove')")
    @Log(title = "文件", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable String[] ids) {
        return toAjax(ardRouteFileService.deleteArdRouteFileByIds(ids));
    }
}
ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFolderController.java
New file
@@ -0,0 +1,120 @@
package com.ard.web.controller.route;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import com.ard.common.annotation.Log;
import com.ard.common.core.controller.BaseController;
import com.ard.common.core.domain.AjaxResult;
import com.ard.common.core.page.TableDataInfo;
import com.ard.common.enums.BusinessType;
import com.ard.common.utils.poi.ExcelUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ard.route.domain.ArdRouteFolder;
import com.ard.route.service.IArdRouteFolderService;
/**
 * 文件夹Controller
 *
 * @author xia
 * @date 2025-10-18
 */
@Api(tags = "文件夹")
@RestController
@RequestMapping("/folder")
public class ArdRouteFolderController extends BaseController {
    @Autowired
    private IArdRouteFolderService ardRouteFolderService;
    /**
     * 查询文件夹列表
     */
    @ApiOperation("查询文件夹列表")
    @PreAuthorize("@ss.hasPermi('route:folder:list')")
    @GetMapping("/list")
    public TableDataInfo list(ArdRouteFolder ardRouteFolder) {
        startPage();
        List<ArdRouteFolder> list = ardRouteFolderService.selectArdRouteFolderList(ardRouteFolder);
        return getDataTable(list);
    }
    /**
     * 导出文件夹列表
     */
    @ApiOperation("导出文件夹列表")
    @PreAuthorize("@ss.hasPermi('route:folder:export')")
    @Log(title = "文件夹", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ArdRouteFolder ardRouteFolder) {
        List<ArdRouteFolder> list = ardRouteFolderService.selectArdRouteFolderList(ardRouteFolder);
        ExcelUtil<ArdRouteFolder> util = new ExcelUtil<ArdRouteFolder>(ArdRouteFolder.class);
        util.exportExcel(response, list, "文件夹数据");
    }
    /**
     * 获取文件夹详细信息
     */
    @ApiOperation("获取文件夹详细信息")
    @PreAuthorize("@ss.hasPermi('route:folder:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") String id) {
        return success(ardRouteFolderService.selectArdRouteFolderById(id));
    }
    /**
     * 新增文件夹
     */
    @ApiOperation("新增文件夹")
    @PreAuthorize("@ss.hasPermi('route:folder:add')")
    @Log(title = "文件夹", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody ArdRouteFolder ardRouteFolder) {
        ardRouteFolder.setCreateBy(getUsername());
        return toAjax(ardRouteFolderService.insertArdRouteFolder(ardRouteFolder));
    }
    /**
     * 修改文件夹
     */
    @ApiOperation("修改文件夹")
    @PreAuthorize("@ss.hasPermi('route:folder:edit')")
    @Log(title = "文件夹", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody ArdRouteFolder ardRouteFolder) {
        ardRouteFolder.setUpdateBy(getUsername());
        return toAjax(ardRouteFolderService.updateArdRouteFolder(ardRouteFolder));
    }
    /**
     * 删除文件夹
     */
    @ApiOperation("删除文件夹")
    @PreAuthorize("@ss.hasPermi('route:folder:remove')")
    @Log(title = "文件夹", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable String[] ids) {
        try {
            Map<String, Integer> result = ardRouteFolderService.deleteArdRouteFolderByIds(ids);
            if (!result.isEmpty()) {
                return AjaxResult.success("删除成功.文件夹删除" + result.get("folder") + "文件删除" + result.get("file"));
            } else {
                return AjaxResult.success("没有删除文件夹信息。");
            }
        } catch(Exception e){
            return AjaxResult.error(e.getMessage());
        }
    }
}
ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
@@ -36,7 +36,7 @@
    @Resource
    private ITyService tyService;
    @ApiOperation("获取六合token信息")
    @ApiOperation("获取边缘服务器token信息")
    @ApiOperationSupport(order = 1)
    @GetMapping("/getToken/{serverId}")
    public AjaxResult getToken(@PathVariable("serverId") String serverId) {
@@ -72,7 +72,7 @@
    @ApiOperation("获取直播地址")
    @ApiOperationSupport(order = 6)
    @GetMapping("/getBoxList/{boxSn}")
    @GetMapping("/getBoxLiveUrl/{boxSn}")
    public AjaxResult getBoxLiveUrl(@PathVariable("boxSn") String boxSn) {
        BoxStreamUrlReceiver boxLiveUrl = tyService.getBoxLiveUrl(boxSn);
        return AjaxResult.success(boxLiveUrl);
@@ -86,7 +86,7 @@
        return AjaxResult.success(state);
    }
    @ApiOperation("根据[服务器id]获取六合盒子列表")
    @ApiOperation("根据[服务器id]获取边缘服务器盒子列表")
    @ApiOperationSupport(order = 8)
    @GetMapping("/getBoxSnToList/{id}")
    public TableDataInfo getBoxSnToList(@PathVariable("id") String id) {
ard-admin/src/main/java/com/ard/web/core/config/ApiGroup.java
New file
@@ -0,0 +1,41 @@
package com.ard.web.core.config;
/**
 * API分组配置枚举
 */
public enum ApiGroup {
    SYSTEM("系统接口", "com.ard.web.controller.system", "系统接口"),
    DRONE("无人机接口", "com.ard.web.controller.work", "无人机管理接口"),
    SAMPLE("机场接口", "com.ard.web.controller.sample", "机场管理接口"),
    MEDIA_MTX("流媒体接口", "com.ard.web.controller.vtdu", "流媒体管理接口"),
    DEVICE("设备接口", "com.ard.web.controller.device", "设备管理接口"),
    DATA("数据接口", "com.ard.web.controller.data", "数据管理接口"),
    STORAGE("存储接口", "com.ard.web.controller.storage", "存储管理接口"),
    ROUTE("航线接口", "com.ard.web.controller.route", "航线管理接口");
    // 分组名
    private final String groupName;
    // 包路径
    private final String packagePath;
    // API文档标题
    private final String title;
    ApiGroup(String groupName, String packagePath, String title) {
        this.groupName = groupName;
        this.packagePath = packagePath;
        this.title = title;
    }
    public String getGroupName() {
        return groupName;
    }
    public String getPackagePath() {
        return packagePath;
    }
    public String getTitle() {
        return title;
    }
}
ard-admin/src/main/java/com/ard/web/core/config/SwaggerConfig.java
@@ -27,151 +27,73 @@
 * @author ruoyi
 */
@Configuration
public class SwaggerConfig
{
public class SwaggerConfig {
    /** 系统基础配置 */
    @Autowired
    private UavConfig uavConfig;
    /**
     * 创建API
     */
    private Docket createApiDocket(ApiGroup apiGroup) {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .groupName(apiGroup.getGroupName())
                .apiInfo(apiInfo(apiGroup.getTitle()))
                .select()
                .apis(requestHandler ->
                        requestHandler.declaringClass().getPackage().getName()
                                .startsWith(apiGroup.getPackagePath()) &&
                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
                )
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }
    @Bean
    public Docket systemApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .groupName("系统接口")   // 分组名
                .apiInfo(apiInfo("系统接口"))
                .select()
                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
                .apis(requestHandler ->
                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller.system") &&
                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
                )
                .paths(PathSelectors.any())
                .build()
                /* 设置安全模式,swagger可以设置访问token */
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
        return createApiDocket(ApiGroup.SYSTEM);
    }
    @Bean
    public Docket droneApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .groupName("无人机接口")   // 分组名
                .apiInfo(apiInfo("无人机管理接口"))
                .select()
                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
                .apis(requestHandler ->
                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller.work") &&
                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
                )
                .paths(PathSelectors.any())
                .build()
                /* 设置安全模式,swagger可以设置访问token */
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
        return createApiDocket(ApiGroup.DRONE);
    }
    @Bean
    public Docket sampleApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .groupName("机场接口")   // 分组名
                .apiInfo(apiInfo("机场管理接口"))
                .select()
                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
                .apis(requestHandler ->
                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
                                ".sample") &&
                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
                )
                .paths(PathSelectors.any())
                .build()
                /* 设置安全模式,swagger可以设置访问token */
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
        return createApiDocket(ApiGroup.SAMPLE);
    }
    @Bean
    public Docket mediaMTXApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .groupName("流媒体接口")   // 分组名
                .apiInfo(apiInfo("流媒体管理接口"))
                .select()
                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
                .apis(requestHandler ->
                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
                                ".vtdu") &&
                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
                )
                .paths(PathSelectors.any())
                .build()
                /* 设置安全模式,swagger可以设置访问token */
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
        return createApiDocket(ApiGroup.MEDIA_MTX);
    }
    @Bean
    public Docket deviceApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .groupName("设备接口")   // 分组名
                .apiInfo(apiInfo("设备管理接口"))
                .select()
                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
                .apis(requestHandler ->
                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
                                ".device") &&
                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
                )
                .paths(PathSelectors.any())
                .build()
                /* 设置安全模式,swagger可以设置访问token */
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
        return createApiDocket(ApiGroup.DEVICE);
    }
    @Bean
    public Docket dataApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .groupName("数据接口")   // 分组名
                .apiInfo(apiInfo("数据管理接口"))
                .select()
                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
                .apis(requestHandler ->
                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
                                ".data") &&
                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
                )
                .paths(PathSelectors.any())
                .build()
                /* 设置安全模式,swagger可以设置访问token */
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
        return createApiDocket(ApiGroup.DATA);
    }
    @Bean
    public Docket storageApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .groupName("存储接口")   // 分组名
                .apiInfo(apiInfo("存储管理接口"))
                .select()
                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
                .apis(requestHandler ->
                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
                                ".storage") &&
                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
                )
                .paths(PathSelectors.any())
                .build()
                /* 设置安全模式,swagger可以设置访问token */
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
        return createApiDocket(ApiGroup.STORAGE);
    }
    @Bean
    public Docket routeApi() {
        return createApiDocket(ApiGroup.ROUTE);
    }
    /**
     * 安全模式,这里指定token通过Authorization头请求头传递
     */
    private List<SecurityScheme> securitySchemes()
    {
    private List<SecurityScheme> securitySchemes() {
        List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
        apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
        return apiKeyList;
@@ -207,8 +129,7 @@
    /**
     * 添加摘要信息
     */
    private ApiInfo apiInfo()
    {
    private ApiInfo apiInfo() {
        // 用ApiInfoBuilder进行定制
        return new ApiInfoBuilder()
                // 设置标题
ard-route/src/main/java/com/ard/route/domain/ArdRouteFile.java
New file
@@ -0,0 +1,45 @@
package com.ard.route.domain;
import java.util.Date;
import java.util.List;
import com.ard.common.annotation.Excel;
import com.ard.common.core.domain.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
 * 文件对象 ard_route_file
 *
 * @author xia
 * @date 2025-10-18
 */
@Data
public class ArdRouteFile extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /** ID */
    private String id;
    /** 文件名称 */
    @Excel(name = "文件名称")
    private String name;
    /** 所属文件夹ID */
    @Excel(name = "所属文件夹ID")
    private String folderId;
    /** 文件类型 */
    @Excel(name = "文件类型")
    private String fileType;
    /** 文件大小(字节) */
    @Excel(name = "文件大小(字节)")
    private Long fileSize;
    /** 文件存储路径 */
    @Excel(name = "文件存储路径")
    private String filePath;
}
ard-route/src/main/java/com/ard/route/domain/ArdRouteFolder.java
New file
@@ -0,0 +1,29 @@
package com.ard.route.domain;
import java.util.List;
import com.ard.common.annotation.Excel;
import com.ard.common.core.domain.BaseEntity;
import lombok.Data;
/**
 * 文件夹对象 ard_route_folder
 *
 * @author xia
 * @date 2025-10-18
 */
@Data
public class ArdRouteFolder extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /** ID */
    private String id;
    /** 文件夹名称 */
    @Excel(name = "文件夹名称")
    private String fileName;
    private List<ArdRouteFile> ardRouteFileLs;
}
ard-route/src/main/java/com/ard/route/mapper/ArdRouteFileMapper.java
New file
@@ -0,0 +1,69 @@
package com.ard.route.mapper;
import java.util.List;
import com.ard.route.domain.ArdRouteFile;
/**
 * 文件Mapper接口
 *
 * @author xia
 * @date 2025-10-18
 */
public interface ArdRouteFileMapper {
    /**
     * 查询文件
     *
     * @param id 文件主键
     * @return 文件
     */
    public ArdRouteFile selectArdRouteFileById(String id);
    /**
     * 查询文件列表
     *
     * @param ardRouteFile 文件
     * @return 文件集合
     */
    public List<ArdRouteFile> selectArdRouteFileList(ArdRouteFile ardRouteFile);
    /**
     * 新增文件
     *
     * @param ardRouteFile 文件
     * @return 结果
     */
    public int insertArdRouteFile(ArdRouteFile ardRouteFile);
    /**
     * 修改文件
     *
     * @param ardRouteFile 文件
     * @return 结果
     */
    public int updateArdRouteFile(ArdRouteFile ardRouteFile);
    /**
     * 删除文件
     *
     * @param id 文件主键
     * @return 结果
     */
    public int deleteArdRouteFileById(String id);
    /**
     * 批量删除文件
     *
     * @param ids 需要删除的数据主键集合
     * @return 结果
     */
    public int deleteArdRouteFileByIds(String[] ids);
    /**
     * 根据所属文件夹ID,删除文件
     *
     * @param folderId 所属文件夹ID
     * @return 结果
     */
    public int deleteArdRouteFileByFolderId(String folderId);
}
ard-route/src/main/java/com/ard/route/mapper/ArdRouteFolderMapper.java
New file
@@ -0,0 +1,62 @@
package com.ard.route.mapper;
import java.util.List;
import com.ard.route.domain.ArdRouteFolder;
/**
 * 文件夹Mapper接口
 *
 * @author xia
 * @date 2025-10-18
 */
public interface ArdRouteFolderMapper {
    /**
     * 查询文件夹
     *
     * @param id 文件夹主键
     * @return 文件夹
     */
    public ArdRouteFolder selectArdRouteFolderById(String id);
    /**
     * 查询文件夹列表
     *
     * @param ardRouteFolder 文件夹
     * @return 文件夹集合
     */
    public List<ArdRouteFolder> selectArdRouteFolderList(ArdRouteFolder ardRouteFolder);
    /**
     * 新增文件夹
     *
     * @param ardRouteFolder 文件夹
     * @return 结果
     */
    public int insertArdRouteFolder(ArdRouteFolder ardRouteFolder);
    /**
     * 修改文件夹
     *
     * @param ardRouteFolder 文件夹
     * @return 结果
     */
    public int updateArdRouteFolder(ArdRouteFolder ardRouteFolder);
    /**
     * 删除文件夹
     *
     * @param id 文件夹主键
     * @return 结果
     */
    public int deleteArdRouteFolderById(String id);
    /**
     * 批量删除文件夹
     *
     * @param ids 需要删除的数据主键集合
     * @return 结果
     */
    public int deleteArdRouteFolderByIds(String[] ids);
}
ard-route/src/main/java/com/ard/route/service/IArdRouteFileService.java
New file
@@ -0,0 +1,62 @@
package com.ard.route.service;
import java.util.List;
import com.ard.route.domain.ArdRouteFile;
/**
 * 文件Service接口
 *
 * @author xia
 * @date 2025-10-18
 */
public interface IArdRouteFileService {
    /**
     * 查询文件
     *
     * @param id 文件主键
     * @return 文件
     */
    public ArdRouteFile selectArdRouteFileById(String id);
    /**
     * 查询文件列表
     *
     * @param ardRouteFile 文件
     * @return 文件集合
     */
    public List<ArdRouteFile> selectArdRouteFileList(ArdRouteFile ardRouteFile);
    /**
     * 新增文件
     *
     * @param ardRouteFile 文件
     * @return 结果
     */
    public int insertArdRouteFile(ArdRouteFile ardRouteFile);
    /**
     * 修改文件
     *
     * @param ardRouteFile 文件
     * @return 结果
     */
    public int updateArdRouteFile(ArdRouteFile ardRouteFile);
    /**
     * 批量删除文件
     *
     * @param ids 需要删除的文件主键集合
     * @return 结果
     */
    public int deleteArdRouteFileByIds(String[] ids);
    /**
     * 删除文件信息
     *
     * @param id 文件主键
     * @return 结果
     */
    public int deleteArdRouteFileById(String id);
}
ard-route/src/main/java/com/ard/route/service/IArdRouteFolderService.java
New file
@@ -0,0 +1,63 @@
package com.ard.route.service;
import java.util.List;
import java.util.Map;
import com.ard.route.domain.ArdRouteFolder;
/**
 * 文件夹Service接口
 *
 * @author xia
 * @date 2025-10-18
 */
public interface IArdRouteFolderService {
    /**
     * 查询文件夹
     *
     * @param id 文件夹主键
     * @return 文件夹
     */
    public ArdRouteFolder selectArdRouteFolderById(String id);
    /**
     * 查询文件夹列表
     *
     * @param ardRouteFolder 文件夹
     * @return 文件夹集合
     */
    public List<ArdRouteFolder> selectArdRouteFolderList(ArdRouteFolder ardRouteFolder);
    /**
     * 新增文件夹
     *
     * @param ardRouteFolder 文件夹
     * @return 结果
     */
    public int insertArdRouteFolder(ArdRouteFolder ardRouteFolder);
    /**
     * 修改文件夹
     *
     * @param ardRouteFolder 文件夹
     * @return 结果
     */
    public int updateArdRouteFolder(ArdRouteFolder ardRouteFolder);
    /**
     * 批量删除文件夹
     *
     * @param ids 需要删除的文件夹主键集合
     * @return 结果
     */
    public Map<String, Integer> deleteArdRouteFolderByIds(String[] ids);
    /**
     * 删除文件夹信息
     *
     * @param id 文件夹主键
     * @return 结果
     */
    public int deleteArdRouteFolderById(String id);
}
ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFileServiceImpl.java
New file
@@ -0,0 +1,97 @@
package com.ard.route.service.impl;
import java.util.List;
import java.util.UUID;
import com.ard.common.annotation.DataScope;
import com.ard.common.utils.DateUtils;
import com.ard.common.utils.SecurityUtils;
import com.ard.common.utils.uuid.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ard.route.mapper.ArdRouteFileMapper;
import com.ard.route.domain.ArdRouteFile;
import com.ard.route.service.IArdRouteFileService;
/**
 * 文件Service业务层处理
 *
 * @author xia
 * @date 2025-10-18
 */
@Service
public class ArdRouteFileServiceImpl implements IArdRouteFileService {
    @Autowired
    private ArdRouteFileMapper ardRouteFileMapper;
    /**
     * 查询文件
     *
     * @param id 文件主键
     * @return 文件
     */
    @Override
    public ArdRouteFile selectArdRouteFileById(String id) {
        return ardRouteFileMapper.selectArdRouteFileById(id);
    }
    /**
     * 查询文件列表
     *
     * @param ardRouteFile 文件
     * @return 文件
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<ArdRouteFile> selectArdRouteFileList(ArdRouteFile ardRouteFile) {
        return ardRouteFileMapper.selectArdRouteFileList(ardRouteFile);
    }
    /**
     * 新增文件
     *
     * @param ardRouteFile 文件
     * @return 结果
     */
    @Override
    public int insertArdRouteFile(ArdRouteFile ardRouteFile) {
        ardRouteFile.setId(IdUtils.simpleUUID());
        ardRouteFile.setCreateTime(DateUtils.getNowDate());
        return ardRouteFileMapper.insertArdRouteFile(ardRouteFile);
    }
    /**
     * 修改文件
     *
     * @param ardRouteFile 文件
     * @return 结果
     */
    @Override
    public int updateArdRouteFile(ArdRouteFile ardRouteFile) {
        ardRouteFile.setUpdateTime(DateUtils.getNowDate());
        return ardRouteFileMapper.updateArdRouteFile(ardRouteFile);
    }
    /**
     * 批量删除文件
     *
     * @param ids 需要删除的文件主键
     * @return 结果
     */
    @Override
    public int deleteArdRouteFileByIds(String[] ids) {
        return ardRouteFileMapper.deleteArdRouteFileByIds(ids);
    }
    /**
     * 删除文件信息
     *
     * @param id 文件主键
     * @return 结果
     */
    @Override
    public int deleteArdRouteFileById(String id) {
        return ardRouteFileMapper.deleteArdRouteFileById(id);
    }
}
ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFolderServiceImpl.java
New file
@@ -0,0 +1,131 @@
package com.ard.route.service.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.ard.common.annotation.DataScope;
import com.ard.common.utils.DateUtils;
import com.ard.common.utils.SecurityUtils;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.route.domain.ArdRouteFile;
import com.ard.route.mapper.ArdRouteFileMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ard.route.mapper.ArdRouteFolderMapper;
import com.ard.route.domain.ArdRouteFolder;
import com.ard.route.service.IArdRouteFolderService;
import org.springframework.transaction.annotation.Transactional;
/**
 * 文件夹Service业务层处理
 *
 * @author xia
 * @date 2025-10-18
 */
@Service
public class ArdRouteFolderServiceImpl implements IArdRouteFolderService {
    @Autowired
    private ArdRouteFolderMapper ardRouteFolderMapper;
    @Autowired
    private ArdRouteFileMapper ardRouteFileMapper;
    /**
     * 查询文件夹
     *
     * @param id 文件夹主键
     * @return 文件夹
     */
    @Override
    public ArdRouteFolder selectArdRouteFolderById(String id) {
        ArdRouteFolder ardRouteFolder = ardRouteFolderMapper.selectArdRouteFolderById(id);
        ardRouteFolder.setArdRouteFileLs(getArdRouteFiles(id));
        return ardRouteFolder;
    }
    /**
     * 查询文件夹列表
     *
     * @param ardRouteFolder 文件夹
     * @return 文件夹
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<ArdRouteFolder> selectArdRouteFolderList(ArdRouteFolder ardRouteFolder) {
        List<ArdRouteFolder> list = ardRouteFolderMapper.selectArdRouteFolderList(ardRouteFolder);
        for (ArdRouteFolder routeFolder : list) {
            routeFolder.setArdRouteFileLs(getArdRouteFiles(routeFolder.getId()));
        }
        return list;
    }
    /**
     * 查询文件列表
     */
    private List<ArdRouteFile> getArdRouteFiles(String folderId) {
        ArdRouteFile ardRouteFile = new ArdRouteFile();
        ardRouteFile.setFolderId(folderId);
        return ardRouteFileMapper.selectArdRouteFileList(ardRouteFile);
    }
    /**
     * 新增文件夹
     *
     * @param ardRouteFolder 文件夹
     * @return 结果
     */
    @Override
    public int insertArdRouteFolder(ArdRouteFolder ardRouteFolder) {
        ardRouteFolder.setId(IdUtils.simpleUUID());
        ardRouteFolder.setCreateTime(DateUtils.getNowDate());
        return ardRouteFolderMapper.insertArdRouteFolder(ardRouteFolder);
    }
    /**
     * 修改文件夹
     *
     * @param ardRouteFolder 文件夹
     * @return 结果
     */
    @Override
    public int updateArdRouteFolder(ArdRouteFolder ardRouteFolder) {
        ardRouteFolder.setUpdateTime(DateUtils.getNowDate());
        return ardRouteFolderMapper.updateArdRouteFolder(ardRouteFolder);
    }
    /**
     * 批量删除文件夹
     *
     * @param ids 需要删除的文件夹主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Integer> deleteArdRouteFolderByIds(String[] ids) {
        Map<String, Integer> result = new HashMap<>();
        int fileAdd = 0;
        // 删除文件夹的同时也删除文件夹下的所有文件
        for (String folderId : ids) {
            ardRouteFileMapper.deleteArdRouteFileByFolderId(folderId);
            fileAdd ++;
        }
        result.put("file", fileAdd);
        int folderCount = ardRouteFolderMapper.deleteArdRouteFolderByIds(ids);
        result.put("folder", folderCount);
        return result;
    }
    /**
     * 删除文件夹信息
     *
     * @param id 文件夹主键
     * @return 结果
     */
    @Override
    public int deleteArdRouteFolderById(String id) {
        return ardRouteFolderMapper.deleteArdRouteFolderById(id);
    }
}
ard-route/src/main/resources/mapper/ArdRouteFileMapper.xml
New file
@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ard.route.mapper.ArdRouteFileMapper">
    <resultMap type="ArdRouteFile" id="ArdRouteFileResult">
        <result property="id"    column="id"    />
        <result property="name"    column="name"    />
        <result property="folderId"    column="folder_id"    />
        <result property="fileType"    column="file_type"    />
        <result property="fileSize"    column="file_size"    />
        <result property="filePath"    column="file_path"    />
        <result property="createBy"    column="create_by"    />
        <result property="createTime"    column="create_time"    />
        <result property="updateBy"    column="update_by"    />
        <result property="updateTime"    column="update_time"    />
    </resultMap>
    <sql id="selectArdRouteFileVo">
        select id,
               name,
               folder_id,
               file_type,
               file_size,
               file_path,
               create_by,
               create_time,
               update_by,
               update_time
        from ard_route_file
    </sql>
    <select id="selectArdRouteFileList" parameterType="ArdRouteFile" resultMap="ArdRouteFileResult">
        <include refid="selectArdRouteFileVo"/>
        <where>
            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
            <if test="folderId != null  and folderId != ''"> and folder_id = #{folderId}</if>
            <if test="fileType != null  and fileType != ''"> and file_type = #{fileType}</if>
            <if test="fileSize != null "> and file_size = #{fileSize}</if>
            <if test="filePath != null  and filePath != ''"> and file_path = #{filePath}</if>
        </where>
    </select>
    <select id="selectArdRouteFileById" parameterType="String" resultMap="ArdRouteFileResult">
        <include refid="selectArdRouteFileVo"/>
        where id = #{id}
    </select>
    <insert id="insertArdRouteFile" parameterType="ArdRouteFile">
        insert into ard_route_file
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">id,</if>
            <if test="name != null">name,</if>
            <if test="folderId != null">folder_id,</if>
            <if test="fileType != null">file_type,</if>
            <if test="fileSize != null">file_size,</if>
            <if test="filePath != null">file_path,</if>
            <if test="createBy != null">create_by,</if>
            <if test="createTime != null">create_time,</if>
            <if test="updateBy != null">update_by,</if>
            <if test="updateTime != null">update_time,</if>
         </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">#{id},</if>
            <if test="name != null">#{name},</if>
            <if test="folderId != null">#{folderId},</if>
            <if test="fileType != null">#{fileType},</if>
            <if test="fileSize != null">#{fileSize},</if>
            <if test="filePath != null">#{filePath},</if>
            <if test="createBy != null">#{createBy},</if>
            <if test="createTime != null">#{createTime},</if>
            <if test="updateBy != null">#{updateBy},</if>
            <if test="updateTime != null">#{updateTime},</if>
         </trim>
    </insert>
    <update id="updateArdRouteFile" parameterType="ArdRouteFile">
        update ard_route_file
        <trim prefix="SET" suffixOverrides=",">
            <if test="name != null">name = #{name},</if>
            <if test="folderId != null">folder_id = #{folderId},</if>
            <if test="fileType != null">file_type = #{fileType},</if>
            <if test="fileSize != null">file_size = #{fileSize},</if>
            <if test="filePath != null">file_path = #{filePath},</if>
            <if test="createBy != null">create_by = #{createBy},</if>
            <if test="createTime != null">create_time = #{createTime},</if>
            <if test="updateBy != null">update_by = #{updateBy},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
        </trim>
        where id = #{id}
    </update>
    <delete id="deleteArdRouteFileById" parameterType="String">
        delete from ard_route_file where id = #{id}
    </delete>
    <delete id="deleteArdRouteFileByFolderId" parameterType="String">
        delete from ard_route_file where folder_id = #{folderId}
    </delete>
    <delete id="deleteArdRouteFileByIds" parameterType="String">
        delete from ard_route_file where id in
        <foreach item="id" collection="array" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>
</mapper>
ard-route/src/main/resources/mapper/ArdRouteFolderMapper.xml
New file
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ard.route.mapper.ArdRouteFolderMapper">
    <resultMap type="ArdRouteFolder" id="ArdRouteFolderResult">
        <result property="id"    column="id"    />
        <result property="fileName"    column="file_name"    />
        <result property="createBy"    column="create_by"    />
        <result property="createTime"    column="create_time"    />
        <result property="updateBy"    column="update_by"    />
        <result property="updateTime"    column="update_time"    />
    </resultMap>
    <select id="selectArdRouteFile" resultType="com.ard.route.domain.ArdRouteFile">
        select * from ard_route_file where id = #{folderId}
    </select>
    <sql id="selectArdRouteFolderVo">
        select id,
               file_name,
               create_by,
               create_time,
               update_by,
               update_time
        from ard_route_folder
    </sql>
    <select id="selectArdRouteFolderList" parameterType="ArdRouteFolder" resultMap="ArdRouteFolderResult">
        <include refid="selectArdRouteFolderVo"/>
        <where>
            <if test="fileName != null  and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
        </where>
    </select>
    <select id="selectArdRouteFolderById" parameterType="String" resultMap="ArdRouteFolderResult">
        <include refid="selectArdRouteFolderVo"/>
        where id = #{id}
    </select>
    <insert id="insertArdRouteFolder" parameterType="ArdRouteFolder">
        insert into ard_route_folder
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">id,</if>
            <if test="fileName != null">file_name,</if>
            <if test="createBy != null">create_by,</if>
            <if test="createTime != null">create_time,</if>
            <if test="updateBy != null">update_by,</if>
            <if test="updateTime != null">update_time,</if>
         </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">#{id},</if>
            <if test="fileName != null">#{fileName},</if>
            <if test="createBy != null">#{createBy},</if>
            <if test="createTime != null">#{createTime},</if>
            <if test="updateBy != null">#{updateBy},</if>
            <if test="updateTime != null">#{updateTime},</if>
         </trim>
    </insert>
    <update id="updateArdRouteFolder" parameterType="ArdRouteFolder">
        update ard_route_folder
        <trim prefix="SET" suffixOverrides=",">
            <if test="fileName != null">file_name = #{fileName},</if>
            <if test="createBy != null">create_by = #{createBy},</if>
            <if test="createTime != null">create_time = #{createTime},</if>
            <if test="updateBy != null">update_by = #{updateBy},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
        </trim>
        where id = #{id}
    </update>
    <delete id="deleteArdRouteFolderById" parameterType="String">
        delete from ard_route_folder where id = #{id}
    </delete>
    <delete id="deleteArdRouteFolderByIds" parameterType="String">
        delete from ard_route_folder where id in
        <foreach item="id" collection="array" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>
</mapper>
ard-work/src/main/java/com/ard/work/aspect/UavControlAspect.java
@@ -70,7 +70,7 @@
        for (Object arg : args) {
            String boxSn = getBoxSn(arg);  // 调用之前实现的 getBoxSn 方法
            if (boxSn != null) {
                TelemetryData uavTelemetryData = UavTelemetryDataCache.getUavTelemetryData(boxSn);
                TelemetryData uavTelemetryData = UavTelemetryDataCache.get(boxSn);
                if (uavTelemetryData == null) {
                    throw new ControlException("遥测数据异常,无法执行!");
                }
ard-work/src/main/java/com/ard/work/component/forest/MyAddressSource.java
@@ -5,10 +5,12 @@
import com.dtflys.forest.callback.AddressSource;
import com.dtflys.forest.http.ForestAddress;
import com.dtflys.forest.http.ForestRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Slf4j
@Component
public class MyAddressSource implements AddressSource {
@@ -17,7 +19,15 @@
    @Override
    public ForestAddress getAddress(ForestRequest request) {
        String serverKey = request.varAsString("serverId");
        if(serverKey == null){
            log.warn("请求属性serverId为空");
            return null;
        }
        ArdServerInfo serverInfo = ardServerService.selectArdServerInfoById(serverKey);
        if(serverInfo == null){
            log.warn("边缘服务器不存在");
            return null;
        }
        // 返回 Forest 地址对象
        return new ForestAddress(serverInfo.getHost(), serverInfo.getHttpPort());
    }
ard-work/src/main/java/com/ard/work/component/netty/TyTcpClientManager.java
@@ -143,7 +143,7 @@
    }
    /**
     * 定时向所有已连接的六合服务器发送心跳
     * 定时向所有已连接的边缘服务器服务器发送心跳
     */
    @Scheduled(fixedRate = 5000) // 每5秒执行一次
    public void sendHeartBeat() {
ard-work/src/main/java/com/ard/work/component/netty/cache/TyTcpServerCache.java
@@ -9,7 +9,7 @@
import java.util.concurrent.ConcurrentHashMap;
/**
 * 六合tcp服务器缓存
 * 边缘服务器tcp服务器缓存
 *
 * @author liusuyi
 * @date 2024年11月01日13:53
ard-work/src/main/java/com/ard/work/component/netty/handler/ClientHandler.java
@@ -86,7 +86,7 @@
        InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();
        String host = remoteAddress.getHostString();
        int port = remoteAddress.getPort();
        log.error("与六合服务{}:{}连接断开!", host, port);
        log.error("与边缘服务器服务{}:{}连接断开!", host, port);
        TyTcpServerCache.putTcpServerCache(serverId, false);
        super.channelInactive(ctx);
    }
ard-work/src/main/java/com/ard/work/component/websocket/handler/BaseSubscriptionManager.java
@@ -23,10 +23,10 @@
    /**
     * 订阅指定设备的数据
     */
    public void subscribe(String boxSn, Long userId,Integer period) {
    public void subscribe(String boxSn, Long userId, Integer period) {
        subscriptions.computeIfAbsent(boxSn, k -> new HashSet<>()).add(userId);
        if (subscriptions.get(boxSn).size() == 1) {
            startPushTask(boxSn,period);
            startPushTask(boxSn, period);
        }
    }
@@ -46,7 +46,7 @@
    /**
     * 启动推送任务
     */
    private void startPushTask(String boxSn,Integer period) {
    private void startPushTask(String boxSn, Integer period) {
        // 如果已经存在任务,则不再创建
        if (pushTasks.containsKey(boxSn)) {
            return;
@@ -79,7 +79,6 @@
    }
    /**
     * 向订阅者发送数据
     */
@@ -90,7 +89,7 @@
        if (userIds != null) {
            for (Long userId : userIds) {
                try {
                    log.warn("给用户{}定时推送",userId);
                    log.debug("给用户{}定时推送", userId);
                    WebSocketUtil.sendMessage(userId, JSON.toJSONString(baseMessage));
                } catch (Exception e) {
                    log.error("Error sending message to session {}", userId, e);
ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java
@@ -192,8 +192,8 @@
    }
    /**
     * 处理无人机控制
     * 根据接收到的消息内容,决定无人机控制信息的订阅或退订
     * 处理无人机控制者
     * 根据接收到的消息内容,决定无人机控制者信息的订阅或退订
     *
     * @param payload 消息负载,包含控制信息
     * @param userId  用户ID,用于标识用户
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavAllManager.java
@@ -22,15 +22,15 @@
    @Override
    protected Map<String,Object> getData(String boxSn) {
        Map<String,Object> map=new HashMap<>();
        UavState uavState = UavStateCache.getUavState(boxSn);
        UavState uavState = UavStateCache.get(boxSn);
        if (uavState != null) {
            uavState.calculateFieldAngle();// 计算当前无人机的FieldAngle
        }
        map.put("boxSn", uavState.getBoxSn());
        map.put("state", uavState);
        TelemetryData uavTelemetryData = UavTelemetryDataCache.getUavTelemetryData(boxSn);
        TelemetryData uavTelemetryData = UavTelemetryDataCache.get(boxSn);
        map.put("telemetry", uavTelemetryData);
        SignalInfo uavSignalInfo = UavSignalInfoCache.getUavSignalInfo(boxSn);
        SignalInfo uavSignalInfo = UavSignalInfoCache.get(boxSn);
        map.put("signal", uavSignalInfo);
        // 获取当前控制飞行的用户ID
        Long flyUserId = uavControlService.getCurrentController(boxSn, "fly");
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java
@@ -12,7 +12,7 @@
import java.util.Map;
@Service
public class UavControlManager  extends BaseSubscriptionManager<Map<String, Long>> {
public class UavControlManager  extends BaseSubscriptionManager<Map<String, Object>> {
    @Resource
    private UavControlService uavControlService;
@@ -60,13 +60,14 @@
     * @return 返回一个映射,包含无人机(fly)和载荷(payload)的当前控制者用户ID
     */
    @Override
    protected Map<String, Long> getData(String boxSn) {
    protected Map<String, Object> getData(String boxSn) {
        // 获取当前控制飞行的用户ID
        Long flyUserId = uavControlService.getCurrentController(boxSn, "fly");
        // 获取当前控制载荷的用户ID
        Long payloadUserId = uavControlService.getCurrentController(boxSn, "payload");
        // 创建一个映射,用于存储飞行和载荷的当前控制者用户ID
        Map<String, Long> map=new HashMap<>();
        Map<String, Object> map=new HashMap<>();
        map.put("boxSn", boxSn);
        // 将飞行当前控制者用户ID添加到映射中
        map.put("flyController", flyUserId);
        // 将载荷当前控制者用户ID添加到映射中
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavSignalManager.java
@@ -10,7 +10,7 @@
    @Override
    protected SignalInfo getData(String boxSn) {
        return UavSignalInfoCache.getUavSignalInfo(boxSn);
        return UavSignalInfoCache.get(boxSn);
    }
    @Override
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStateManager.java
@@ -10,7 +10,7 @@
    @Override
    protected UavState getData(String boxSn) {
        UavState uavState = UavStateCache.getUavState(boxSn);
        UavState uavState = UavStateCache.get(boxSn);
        if (uavState != null) {
            uavState.calculateFieldAngle();// 计算当前无人机的FieldAngle
        }
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStreamManager.java
@@ -42,14 +42,15 @@
    public void subscribe(String boxSn, Long userId) {
        STREAM_USER_MAP.computeIfAbsent(boxSn, k -> ConcurrentHashMap.newKeySet()).add(userId);
        String webrtcUrl = getWebrtcUrl(boxSn);
        BoxStreamUrlReceiver streamReceiver = getWebrtcUrl(boxSn);
        String webrtcUrl = streamReceiver.getRtc();
        if (Objects.equals(webrtcUrl, "")) {
            log.warn("{}{}{}", STREAM_LOG_PREFIX, STREAM_NOT_FOUND_MSG, boxSn);
            BaseMessage<String> baseMessage = new BaseMessage<>("stream", STREAM_NOT_FOUND_MSG + boxSn);
            sendMessageToUser(userId, JSON.toJSONString(baseMessage));
        }
        BOX_STREAM_PULL_MAP.put(boxSn, webrtcUrl);
        BaseMessage<String> baseMessage = new BaseMessage<>("stream", webrtcUrl);
        BaseMessage<BoxStreamUrlReceiver> baseMessage = new BaseMessage<>("stream", streamReceiver);
        sendMessageToUser(userId, JSON.toJSONString(baseMessage));
    }
@@ -117,15 +118,9 @@
     * @param boxSn 盒子编号
     * @return String webrtcUrl
     */
    private String getWebrtcUrl(String boxSn) {
        try {
            BoxStreamUrlReceiver boxLiveUrl = tyService.getBoxLiveUrl(boxSn);
            if (boxLiveUrl != null) {
                return boxLiveUrl.getRtc();
            }
        } catch (Exception e) {
            log.error("获取媒体地址异常:{}", e.getMessage());
        }
        return "";
    private BoxStreamUrlReceiver getWebrtcUrl(String boxSn) {
        BoxStreamUrlReceiver boxLiveUrl = tyService.getBoxLiveUrl(boxSn);
        boxLiveUrl.setBoxSn(boxSn);
        return boxLiveUrl;
    }
}
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavTelemetryManager.java
@@ -10,7 +10,7 @@
    @Override
    protected TelemetryData getData(String boxSn) {
        return UavTelemetryDataCache.getUavTelemetryData(boxSn);
        return UavTelemetryDataCache.get(boxSn);
    }
    @Override
ard-work/src/main/java/com/ard/work/domain/cache/UavSignalInfoCache.java
@@ -1,6 +1,7 @@
package com.ard.work.domain.cache;
import com.ard.work.domain.dto.signal.SignalInfo;
import com.ard.work.domain.dto.telemetry.TelemetryData;
import java.util.concurrent.ConcurrentHashMap;
@@ -13,20 +14,29 @@
public class UavSignalInfoCache {
    // 使用 ConcurrentHashMap 来缓存无人机信道质量数据,key 是 boxSn(无人机序列号)
    private static final ConcurrentHashMap<String, SignalInfo> uavSignalInfoCache = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<String, SignalInfo> cache = new ConcurrentHashMap<>();
    // 存储无人机信道质量数据到缓存
    public static void putUavSignalInfoCache(SignalInfo signalInfo) {
        uavSignalInfoCache.put(signalInfo.getBoxSn(), signalInfo);
    public static void put(SignalInfo signalInfo) {
        cache.put(signalInfo.getBoxSn(), signalInfo);
    }
    // 从缓存中获取信道质量数据
    public static SignalInfo getUavSignalInfo(String boxSn) {
        return uavSignalInfoCache.get(boxSn);
    public static SignalInfo get(String boxSn) {
        return cache.get(boxSn);
    }
    // 删除缓存中的信道质量数据
    public static void removeUavSignalInfo(String boxSn) {
        uavSignalInfoCache.remove(boxSn);
    public static void remove(String boxSn) {
        cache.remove(boxSn);
    }
    // 定时任务使用:判断状遥测数据是否变化,但不更新缓存
    public static boolean hasChanged(String boxSn, SignalInfo signalInfo) {
        SignalInfo oldSignalInfo= cache.get(boxSn);
        if (oldSignalInfo == null) {
            return true; // 没有缓存,算作变化
        }
        return !oldSignalInfo.equals(signalInfo); // true = 有变化
    }
}
ard-work/src/main/java/com/ard/work/domain/cache/UavStateCache.java
@@ -1,6 +1,7 @@
package com.ard.work.domain.cache;
import com.ard.work.domain.dto.state.UavState;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -12,20 +13,27 @@
public class UavStateCache {
    // 使用 ConcurrentHashMap 来缓存无人机状态数据,key 是 boxSn(无人机序列号)
    private static final ConcurrentHashMap<String, UavState> uavStateCache = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<String, UavState> cache = new ConcurrentHashMap<>();
    // 存储无人机状态数据到缓存
    public static void putUavState(UavState uavState) {
        uavStateCache.put(uavState.getBoxSn(), uavState);
    }
    public static void put(UavState uavState) {cache.put(uavState.getBoxSn(), uavState);}
    // 从缓存中获取无人机状态数据
    public static UavState getUavState(String boxSn) {
        return uavStateCache.get(boxSn);
    public static UavState get(String boxSn) {
        return cache.get(boxSn);
    }
    // 删除缓存中的无人机状态数据
    public static void removeUavState(String boxSn) {
        uavStateCache.remove(boxSn);
    public static void remove(String boxSn) {
        cache.remove(boxSn);
    }
    // 定时任务使用:判断状态是否变化,但不更新缓存
    public static boolean hasChanged(String boxSn, UavState newState) {
        UavState oldState = cache.get(boxSn);
        if (oldState == null) {
            return true; // 没有缓存,算作变化
        }
        return !oldState.equals(newState); // true = 有变化
    }
}
ard-work/src/main/java/com/ard/work/domain/cache/UavTelemetryDataCache.java
@@ -1,5 +1,6 @@
package com.ard.work.domain.cache;
import com.ard.work.domain.dto.state.UavState;
import com.ard.work.domain.dto.telemetry.TelemetryData;
import java.util.concurrent.ConcurrentHashMap;
@@ -13,20 +14,29 @@
public class UavTelemetryDataCache {
    // 使用 ConcurrentHashMap 来缓存无人机遥测数据,key 是 boxSn(无人机序列号)
    private static final ConcurrentHashMap<String, TelemetryData> uavTelemetryDataCache = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<String, TelemetryData> cache = new ConcurrentHashMap<>();
    // 存储无人机遥测数据到缓存
    public static void putUavTelemetryData(TelemetryData telemetryData) {
        uavTelemetryDataCache.put(telemetryData.getBoxSn(), telemetryData);
    public static void put(TelemetryData telemetryData) {
        cache.put(telemetryData.getBoxSn(), telemetryData);
    }
    // 从缓存中获取无人机遥测数据
    public static TelemetryData getUavTelemetryData(String boxSn) {
        return uavTelemetryDataCache.get(boxSn);
    public static TelemetryData get(String boxSn) {
        return cache.get(boxSn);
    }
    // 删除缓存中的无人机遥测数据
    public static void removeUavTelemetryData(String boxSn) {
        uavTelemetryDataCache.remove(boxSn);
    public static void remove(String boxSn) {
        cache.remove(boxSn);
    }
    // 定时任务使用:判断状遥测数据是否变化,但不更新缓存
    public static boolean hasChanged(String boxSn, TelemetryData telemetryData) {
        TelemetryData oldTelemetryData= cache.get(boxSn);
        if (oldTelemetryData == null) {
            return true; // 没有缓存,算作变化
        }
        return !oldTelemetryData.equals(telemetryData); // true = 有变化
    }
}
ard-work/src/main/java/com/ard/work/domain/dto/signal/SignalInfo.java
@@ -2,8 +2,10 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode
public class SignalInfo {
    private String mode;               // 入网模式: NR5G-SA, NR5G-NSA,LTE
    private String mcc;                // NR5G-SA, NR5G-NSA, LTE
ard-work/src/main/java/com/ard/work/domain/dto/state/UavState.java
@@ -1,10 +1,7 @@
package com.ard.work.domain.dto.state;
import com.ard.work.util.CameraUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.*;
import java.util.List;
@@ -12,6 +9,7 @@
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class UavState {
    private FlightControllerState flightControllerState;  // 飞控状态
ard-work/src/main/java/com/ard/work/domain/dto/telemetry/TelemetryData.java
@@ -1,14 +1,12 @@
package com.ard.work.domain.dto.telemetry;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.*;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class TelemetryData {
    private double lng;              // 经度
ard-work/src/main/java/com/ard/work/domain/receiver/BoxStreamUrlReceiver.java
@@ -8,6 +8,8 @@
@JsonIgnoreProperties(ignoreUnknown = true)
public class BoxStreamUrlReceiver {
    private String boxSn;
    @JsonProperty("rtsp")
    private String rtsp;
ard-work/src/main/java/com/ard/work/domain/receiver/TyHttpCommonReceiver.java
@@ -8,7 +8,7 @@
@JsonIgnoreProperties(ignoreUnknown = true)
public class TyHttpCommonReceiver<T> {
    /**
     * 六合http请求返回信息
     * 边缘服务器http请求返回信息
     */
    @JsonProperty("state")
    private Integer state;
ard-work/src/main/java/com/ard/work/service/ITyService.java
@@ -31,7 +31,7 @@
public interface ITyService {
    /**
     * 获取六合token信息
     * 获取边缘服务器token信息
     * @return
     */
    AccessTokenReceiver getAccessToken(String ServerId);
@@ -288,7 +288,7 @@
    void processReplyMessage(String key, BaseCmd tyMessage);
    /**
     * 根据[服务器id]获取六合盒子列表
     * 根据[服务器id]获取边缘服务器盒子列表
     */
    List<BoxInfoReceiver> getBoxSnToList(String id);
ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java
@@ -52,6 +52,7 @@
import com.ard.work.service.ITyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@@ -74,7 +75,7 @@
    private TyClient tyClient;
    /**
     * 获取六合token信息
     * 获取边缘服务器token信息
     *
     * @return AccessTokenReceiver
     */
@@ -93,6 +94,7 @@
        List<ArdServerInfo> ardServerInfos = ardServerService.selectArdServerInfoList(new ArdServerInfo());
        return getBoxList(ardServerInfos);
    }
    /**
     * 获取指定服务器云盒列表
     *
@@ -101,8 +103,9 @@
    @Override
    public List<BoxInfoReceiver> getBoxList(String serverId) {
        TyHttpCommonReceiver<List<BoxInfoReceiver>> boxList = tyClient.getBoxList(serverId);
        return boxList.getContent();
        return boxList == null ? null : boxList.getContent();
    }
    /**
     * 获取直播地址
     *
@@ -111,8 +114,13 @@
    @Override
    public BoxStreamUrlReceiver getBoxLiveUrl(String boxSn) {
        ArdDroneInfo ardDroneInfo = ardDroneService.selectArdDroneByboxSn(boxSn);
        TyHttpCommonReceiver<BoxStreamUrlReceiver> boxLiveUrl = tyClient.getBoxLiveUrl(ardDroneInfo.getServerId(),boxSn);
        return boxLiveUrl.getContent();
        if (ardDroneInfo == null) {
            log.warn("未找到对应的飞行器信息,boxSn:{}", boxSn);
            return null;
        }
        TyHttpCommonReceiver<BoxStreamUrlReceiver> boxLiveUrl = tyClient.getBoxLiveUrl(ardDroneInfo.getServerId(),
                boxSn);
        return boxLiveUrl == null ? null : boxLiveUrl.getContent();
    }
    /**
@@ -125,7 +133,7 @@
        ArdDroneInfo ardDroneInfo = ardDroneService.selectArdDroneByboxSn(boxHistoryDTO.getBoxSn());
        TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(ardDroneInfo.getServerId(),
                boxHistoryDTO);
        return boxHistory.getContent();
        return boxHistory == null ? null : boxHistory.getContent();
    }
    /**
@@ -136,8 +144,9 @@
    @Override
    public List<BoxPhotosReceiver> getBoxPhotos(BoxPhotosDTO boxPhotosDTO) {
        ArdDroneInfo ardDroneInfo = ardDroneService.selectArdDroneByboxSn(boxPhotosDTO.getBoxSn());
        TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(ardDroneInfo.getServerId(),boxPhotosDTO);
        return boxPhotos.getContent();
        TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(ardDroneInfo.getServerId(),
                boxPhotosDTO);
        return boxPhotos == null ? null : boxPhotos.getContent();
    }
    /**
@@ -146,7 +155,7 @@
    @Override
    public Boolean updateBoxSettings(BoxSettingsDTO boxSettingsDTO) {
        ArdDroneInfo ardDroneInfo = ardDroneService.selectArdDroneByboxSn(boxSettingsDTO.getBoxSn());
        TyHttpCommonReceiver<?> result = tyClient.updateBoxSettings(ardDroneInfo.getServerId(),boxSettingsDTO);
        TyHttpCommonReceiver<?> result = tyClient.updateBoxSettings(ardDroneInfo.getServerId(), boxSettingsDTO);
        return result.getState() == 1;
    }
@@ -184,7 +193,7 @@
    }
    /**
     * 注册六合平台
     * 注册边缘服务器平台
     */
    @Override
    public Boolean registerMessage(String serverId) {
@@ -193,7 +202,7 @@
            RegisterCmd registerMessage = new RegisterCmd(tyToken.getCompanyId(), tyToken.getAccessToken().getBytes());
            this.sendMessage(serverId, registerMessage);
        } catch (Exception e) {
            log.error("注册六合平台失败:{}", e.getMessage());
            log.error("注册边缘服务器平台失败:{}", e.getMessage());
        }
        return true;
    }
@@ -472,7 +481,7 @@
     */
    @Override
    public UavState getUavState(String boxSn) {
        return UavStateCache.getUavState(boxSn);
        return UavStateCache.get(boxSn);
    }
    /**
@@ -480,7 +489,7 @@
     */
    @Override
    public TelemetryData getUavTelemetryData(String boxSn) {
        return UavTelemetryDataCache.getUavTelemetryData(boxSn);
        return UavTelemetryDataCache.get(boxSn);
    }
    /**
@@ -488,7 +497,7 @@
     */
    @Override
    public SignalInfo getSignalInfo(String boxSn) {
        return UavSignalInfoCache.getUavSignalInfo(boxSn);
        return UavSignalInfoCache.get(boxSn);
    }
    /**
@@ -651,7 +660,7 @@
    }
    /**
     * 处理六合服务器返回的消息
     * 处理边缘服务器返回的消息
     */
    @Override
    public void processReplyMessage(String key, BaseCmd tyCommand) {
@@ -669,8 +678,8 @@
                break;
            case 0x02:
                // 处理注册消息
                 HeartbeatReplyCmd heartbeatReplyCmd = (HeartbeatReplyCmd) tyCommand;
                 logPrint("心跳消息", heartbeatReplyCmd.getTimestamp());
                HeartbeatReplyCmd heartbeatReplyCmd = (HeartbeatReplyCmd) tyCommand;
                logPrint("心跳消息", heartbeatReplyCmd.getTimestamp());
                break;
            case 0x03:
                // 处理订阅消息
@@ -691,14 +700,14 @@
            case (byte) 0xA8:
                // 处理无人机状态消息
                UavStateCmd uavStateCmd = (UavStateCmd) tyCommand;
                UavStateCache.putUavState(uavStateCmd.getUavState());
                UavStateCache.put(uavStateCmd.getUavState());
                //logPrint("无人机状态", uavStateCmd.getUavState().getBoxSn());
                // WebSocketUtil.sendMessageAll(uavStateCmd.getUavState());
                break;
            case (byte) 0xA9:
                // 处理无人机遥测消息
                UavTelemetryDataCmd uavTelemetryDataCmd = (UavTelemetryDataCmd) tyCommand;
                UavTelemetryDataCache.putUavTelemetryData(uavTelemetryDataCmd.getTelemetryData());
                UavTelemetryDataCache.put(uavTelemetryDataCmd.getTelemetryData());
                //logPrint("无人机遥测", uavTelemetryDataCmd.getTelemetryData().getBoxSn());
                //WebSocketUtil.sendMessageAll(uavTelemetryDataCmd.getTelemetryData());
                break;
@@ -706,7 +715,7 @@
            case (byte) 0x0C:
                // 处理无人机信道质量数据
                SignalInfoCmd signalInfoCmd = (SignalInfoCmd) tyCommand;
                UavSignalInfoCache.putUavSignalInfoCache(signalInfoCmd.getSignalInfo());
                UavSignalInfoCache.put(signalInfoCmd.getSignalInfo());
                //logPrint("无人机信道质量", signalInfoCmd.getSignalInfo().getBoxSn());
                break;
            case (byte) 0xD1:
@@ -835,7 +844,7 @@
    }
    /**
     * 根据[服务器id]获取六合盒子列表
     * 根据[服务器id]获取边缘服务器盒子列表
     */
    @Override
    public List<BoxInfoReceiver> getBoxSnToList(String id) {
ard-work/src/main/resources/mapper/ArdDroneInfoMapper.xml
@@ -10,7 +10,7 @@
        <result property="boxName"    column="box_name"    />
        <result property="boxVersion"    column="box_version"    />
        <result property="startTime"    column="start_time"    />
        <result property="onLine"    column="onLine"    />
        <result property="onLine"    column="on_line"    />
        <result property="videoServer"    column="video_server"    />
        <result property="videoPort"    column="video_port"    />
        <result property="lastTaskId"    column="last_task_id"    />