diff --git a/aircraft-system/src/main/java/com/aircraft/modules/aircraft/controller/AircraftLogController.java b/aircraft-system/src/main/java/com/aircraft/modules/aircraft/controller/AircraftLogController.java new file mode 100644 index 0000000..386fc4c --- /dev/null +++ b/aircraft-system/src/main/java/com/aircraft/modules/aircraft/controller/AircraftLogController.java @@ -0,0 +1,39 @@ +package com.aircraft.modules.aircraft.controller; + + +import com.aircraft.modules.aircraft.domain.AircraftLog; +import com.aircraft.modules.aircraft.domain.dto.AircraftDevicePageDTO; +import com.aircraft.modules.aircraft.domain.vo.AircraftDevicePageVO; +import com.aircraft.modules.aircraft.service.AircraftLogService; +import com.aircraft.utils.PageResult; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.annotations.*; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@Api(tags = "飞行器日志管理") +@RequiredArgsConstructor +@RestController +@RequestMapping("/aircraft/log") +public class AircraftLogController { + + private final AircraftLogService aircraftLogService; + + /** + * 分页查询飞行器日志 + */ + @ApiOperation("分页查询飞行器日志") + @GetMapping("/page") + public ResponseEntity> page( + @ApiParam(value = "型号", required = true) + @RequestParam("model")String model, + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size) + { + return ResponseEntity.ok(aircraftLogService.findByUavUUID(model, page,size)); + } + + +} diff --git a/aircraft-system/src/main/java/com/aircraft/modules/aircraft/domain/AircraftLog.java b/aircraft-system/src/main/java/com/aircraft/modules/aircraft/domain/AircraftLog.java new file mode 100644 index 0000000..4e6422a --- /dev/null +++ b/aircraft-system/src/main/java/com/aircraft/modules/aircraft/domain/AircraftLog.java @@ -0,0 +1,173 @@ +package com.aircraft.modules.aircraft.domain; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.CompoundIndex; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.io.Serializable; + +/** + * 无人机状态信息DTO + */ +@Data +@Document(collection = "aircraft_log") +@CompoundIndex(name = "uavUUID_timestamp_idx", def = "{'uavUUID': 1, 'timestampString': -1}") +@ApiModel(description = "无人机状态信息") +public class AircraftLog implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @ApiModelProperty(value = "MongoDB主键ID") + private String id; + + @ApiModelProperty(value = "测向传感器角度 0 – 360,无效值:-1000", example = "45.5") + private Double rtkdao; + + @ApiModelProperty(value = "无人机上升速度", example = "1.2") + private Double climbRate; + + @ApiModelProperty(value = "罗盘1角度 0 – 360,无效值:-1000", example = "90.0") + private Double compass1Angle; + + @ApiModelProperty(value = "罗盘2角度 0 – 360,无效值:-1000", example = "90.0") + private Double compass2Angle; + + @ApiModelProperty(value = "罗盘3角度 0 – 360,无效值:-1000", example = "90.0") + private Double compass3Angle; + + @ApiModelProperty(value = "无人机总电流", example = "15.5") + private Double current; + + @ApiModelProperty(value = "设备类型", example = "vehicle") + private String device; + + @ApiModelProperty(value = "无人机海拔高度", example = "100.5") + private Double elevation; + + @ApiModelProperty(value = "错误消息") + private String error; + + @ApiModelProperty(value = "无人机飞行距离", example = "1500.0") + private Double flyDistance; + + @ApiModelProperty(value = "飞行模式:定点、定高、任务、定点避障、返航、Offboard、跟踪", + example = "定点") + private String flyMode; + + @ApiModelProperty(value = "无人机飞行时间", example = "00:00:00") + private String flyTime; + + @ApiModelProperty(value = "RTK海拔高度", example = "100.5") + private Double gps1Alt; + + @ApiModelProperty(value = "RTK水平定位精度", example = "0.5") + private Double gps1Hdop; + + @ApiModelProperty(value = "RTK纬度坐标", example = "21.1234567") + private Double gps1Lat; + + @ApiModelProperty(value = "RTK定位类型:None,2D Lock,3D Lock,3D DGPS Lock,3D RTK GPS Lock (float),3D RTK GPS Lock (fixed),Static (fixed)", + example = "3D RTK GPS Lock (fixed)") + private String gps1Lock; + + @ApiModelProperty(value = "RTK经度坐标", example = "113.1234567") + private Double gps1Lon; + + @ApiModelProperty(value = "RTK搜星数量", example = "15") + private Integer gps1Satellite; + + @ApiModelProperty(value = "RTK垂直定位精度", example = "0.8") + private Double gps1Vdop; + + @ApiModelProperty(value = "GPS海拔高度", example = "100.0") + private Double gps2Alt; + + @ApiModelProperty(value = "GPS水平定位精度", example = "1.2") + private Double gps2Hdop; + + @ApiModelProperty(value = "GPS纬度坐标", example = "21.1234567") + private Double gps2Lat; + + @ApiModelProperty(value = "GPS定位类型:None,2D Lock,3D Lock,3D DGPS Lock,3D RTK GPS Lock (float),3D RTK GPS Lock (fixed),Static (fixed)", + example = "3D Lock") + private String gps2Lock; + + @ApiModelProperty(value = "GPS经度坐标", example = "113.1234567") + private Double gps2Lon; + + @ApiModelProperty(value = "GPS搜星数量", example = "12") + private Integer gps2Satellite; + + @ApiModelProperty(value = "GPS垂直定位精度", example = "1.5") + private Double gps2Vdop; + + @ApiModelProperty(value = "无人机水平速度", example = "5.5") + private Double groundSpeed; + + @ApiModelProperty(value = "无人机距家距离", example = "500.0") + private Double homeDistance; + + @ApiModelProperty(value = "无人机纬度坐标", example = "21.1234567") + private Double latitude; + + @ApiModelProperty(value = "无人机经度坐标", example = "113.1234567") + private Double longitude; + + @ApiModelProperty(value = "无人机俯仰角度", example = "2.5") + private Double pitch; + + @ApiModelProperty(value = "无人机俯仰角速度", example = "0.5") + private Double pitchRate; + + @ApiModelProperty(value = "无人机相对高度", example = "50.0") + private Double relativeAlt; + + @ApiModelProperty(value = "无人机横滚角度", example = "1.5") + private Double roll; + + @ApiModelProperty(value = "无人机横滚角速度", example = "0.3") + private Double rollRate; + + @ApiModelProperty(value = "无人机SD卡剩余容量", example = "32.5") + private Double sdcardRemain; + + @ApiModelProperty(value = "无人机状态:flying-飞行中, armed-解锁, disarmed-上锁", + example = "flying") + private String state; + + @ApiModelProperty(value = "无人机ID", example = "1") + private Integer uavSysID; + + @ApiModelProperty(value = "无人机机型:四旋翼、四旋翼+、六旋翼、六旋翼+、八旋翼、共轴双桨、三旋翼Y、四旋翼共轴双桨、直升机", + example = "四旋翼") + private String uavType; + + @Indexed + @ApiModelProperty(value = "飞控序列号,无人机唯一识别码", example = "UAV-123456789") + private String uavUUID; + + @ApiModelProperty(value = "无人机电压1", example = "22.5") + private Double voltage1; + + @ApiModelProperty(value = "无人机电压2", example = "22.5") + private Double voltage2; + + @ApiModelProperty(value = "无人机航向角", example = "180.0") + private Double yaw; + + @ApiModelProperty(value = "无人机航向角速度", example = "1.2") + private Double yawRate; + + @ApiModelProperty(value = "当前时间戳(毫秒)", example = "1725935401123") + private Long timestampSinceEpoch; + + @Indexed + @ApiModelProperty(value = "格式化时间戳:yyyy-MM-dd hh:mm:ss:zzz", + example = "2024-09-10 08:30:01:123") + private String timestampString; +} \ No newline at end of file diff --git a/aircraft-system/src/main/java/com/aircraft/modules/aircraft/service/AircraftLogService.java b/aircraft-system/src/main/java/com/aircraft/modules/aircraft/service/AircraftLogService.java new file mode 100644 index 0000000..a3050e2 --- /dev/null +++ b/aircraft-system/src/main/java/com/aircraft/modules/aircraft/service/AircraftLogService.java @@ -0,0 +1,14 @@ +package com.aircraft.modules.aircraft.service; + +import com.aircraft.modules.aircraft.domain.AircraftLog; +import com.aircraft.utils.PageResult; +import org.springframework.messaging.Message; + +public interface AircraftLogService { + + void saveLog(String message); + + + + PageResult findByUavUUID(String uavUUID, int page, int size); +} diff --git a/aircraft-system/src/main/java/com/aircraft/modules/aircraft/service/impl/AircraftLogServiceImpl.java b/aircraft-system/src/main/java/com/aircraft/modules/aircraft/service/impl/AircraftLogServiceImpl.java new file mode 100644 index 0000000..2b8b2f7 --- /dev/null +++ b/aircraft-system/src/main/java/com/aircraft/modules/aircraft/service/impl/AircraftLogServiceImpl.java @@ -0,0 +1,74 @@ +package com.aircraft.modules.aircraft.service.impl; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.aircraft.modules.aircraft.domain.AircraftLog; +import com.aircraft.modules.aircraft.service.AircraftLogService; +import com.aircraft.utils.PageResult; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + + +@Service +@Slf4j +@RequiredArgsConstructor +public class AircraftLogServiceImpl implements AircraftLogService { + + + + private final MongoTemplate mongotemplate; + + + @Override + public void saveLog(String message) { + + try { + JSONObject result = JSONUtil.parseObj(message); + String dataStr = result.getStr("data"); + if (null != dataStr) { + AircraftLog aircraftLog = com.alibaba.fastjson.JSONObject.parseObject(result.getStr("data"), AircraftLog.class); + mongotemplate.insert(aircraftLog); + } + } catch (Exception e) { + log.error("飞行器日志解析异常", e); + } + } + + @Override + public PageResult findByUavUUID(String uavUUID, int page, int size) { + try { + // 构建查询条件 + Query query = new Query(Criteria.where("uavUUID").is(uavUUID)); + + // 获取总数 + long total = mongotemplate.count(query, AircraftLog.class); + + List content = new ArrayList<>(); + // 执行查询 + if (total > 0){ + // 设置分页和排序 + query.with(Sort.by(Sort.Direction.DESC, "timestampString")) + .skip((long) (page - 1) * size) + .limit(size); + + content = mongotemplate.find(query, AircraftLog.class); + } + + + return new PageResult<>(content, total); + } catch (Exception e) { + log.error("根据uavUUID分页查询无人机日志失败 - uavUUID: {}, page: {}, size: {}", + uavUUID, page, size, e); + throw new RuntimeException("查询无人机日志失败", e); + } + } +} diff --git a/aircraft-system/src/main/java/com/aircraft/udp/UdpListener.java b/aircraft-system/src/main/java/com/aircraft/udp/UdpListener.java new file mode 100644 index 0000000..4714107 --- /dev/null +++ b/aircraft-system/src/main/java/com/aircraft/udp/UdpListener.java @@ -0,0 +1,61 @@ +package com.aircraft.udp; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.aircraft.modules.aircraft.service.AircraftLogService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.dsl.IntegrationFlow; +import org.springframework.integration.dsl.IntegrationFlows; +import org.springframework.integration.ip.dsl.Udp; +import org.springframework.messaging.handler.annotation.Payload; + +import javax.annotation.Resource; +import java.nio.charset.StandardCharsets; + +@Slf4j +@Configuration +@EnableIntegration +public class UdpListener { + + @Value("${udp.receive-port}") + private Integer receivePort; + + @Resource + private AircraftLogService aircraftLogService; + + + /** + * 定义接收流程 + */ + @Bean + public IntegrationFlow udpInboundFlow() { + return IntegrationFlows + .from(Udp.inboundAdapter(receivePort)) + .handle(message -> { + handleMessage((byte[]) message.getPayload()); + }) + .get(); + } + + + public void handleMessage(@Payload byte[] payload) { + String message = new String(payload, StandardCharsets.UTF_8); // 指定编码,避免乱码 + log.info("Received UDP data:{} ", message); + try { + JSONObject result = JSONUtil.parseObj(message); + if ("status".equals(result.getStr("command"))) { + //目前只有飞行日志 + aircraftLogService.saveLog(message); + } + } catch (Exception e) { + log.error("UDP Message 解析异常!", e); + } + + } + + +} diff --git a/aircraft-system/src/main/resources/config/application-dev.yml b/aircraft-system/src/main/resources/config/application-local.yml similarity index 96% rename from aircraft-system/src/main/resources/config/application-dev.yml rename to aircraft-system/src/main/resources/config/application-local.yml index bb817bc..64395e5 100644 --- a/aircraft-system/src/main/resources/config/application-dev.yml +++ b/aircraft-system/src/main/resources/config/application-local.yml @@ -1,6 +1,15 @@ #配置数据源 spring: + data: + mongodb: + host: 8.130.155.168 + port: 27017 + database: aircraft + username: aircraft + password: rGisFzT8PDtHYftL + authentication-database: aircraft + datasource: druid: db-type: com.alibaba.druid.pool.DruidDataSource diff --git a/aircraft-system/src/main/resources/config/application-prod.yml b/aircraft-system/src/main/resources/config/application-prod.yml deleted file mode 100644 index 3348de6..0000000 --- a/aircraft-system/src/main/resources/config/application-prod.yml +++ /dev/null @@ -1,154 +0,0 @@ -#配置数据源 -spring: - datasource: - druid: - db-type: com.alibaba.druid.pool.DruidDataSource - driverClassName: com.p6spy.engine.spy.P6SpyDriver - url: jdbc:p6spy:mysql://172.31.108.89:3306/aircraft-mp?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false - username: aishangyun_dev - password: asyfx@123dev - # 初始连接数,建议设置为与最小空闲连接数相同 - initial-size: 20 - # 最小空闲连接数,保持足够的空闲连接以应对请求 - min-idle: 20 - # 最大连接数,根据并发需求适当增加 - max-active: 50 - # 获取连接超时时间(毫秒),调整以满足响应时间要求 - max-wait: 3000 - # 启用KeepAlive机制,保持长连接 - keep-alive: true - # 连接有效性检测间隔时间(毫秒),定期检查连接的健康状态 - time-between-eviction-runs-millis: 60000 - # 连接在池中最小生存时间(毫秒),确保连接在池中至少存在一段时间 - min-evictable-idle-time-millis: 300000 - # 连接在池中最大生存时间(毫秒),防止连接在池中停留过长 - max-evictable-idle-time-millis: 900000 - # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 - test-while-idle: true - # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 - test-on-borrow: true - # 是否在归还到池中前进行检验 - test-on-return: false - # 停用 com_ping 探活机制 - use-ping-method: false - # 检测连接是否有效 - validation-query: SELECT 1 - # 配置监控统计 - webStatFilter: - enabled: true - stat-view-servlet: - allow: - enabled: true - # 控制台管理用户名和密码 - url-pattern: /druid/* - reset-enable: false - login-username: admin - login-password: 123456 - filter: - stat: - enabled: true - # 记录慢SQL - log-slow-sql: true - slow-sql-millis: 1000 - merge-sql: true - wall: - config: - multi-statement-allow: true - redis: - #数据库索引 - database: ${REDIS_DB:1} - host: ${REDIS_HOST:172.31.108.89} - port: ${REDIS_PORT:6334} - password: ${REDIS_PWD:aircraft.redis.@2025} - -# 登录相关配置 -login: - # 是否限制单用户登录 - single-login: false - # Redis用户登录缓存配置 - user-cache: - # 存活时间/秒 - idle-time: 21600 - # 验证码 - code: - # 验证码类型配置 查看 LoginProperties 类 - code-type: arithmetic - # 登录图形验证码有效时间/分钟 - expiration: 2 - # 验证码高度 - width: 111 - # 验证码宽度 - height: 36 - # 内容长度 - length: 2 - # 字体名称,为空则使用默认字体,如遇到线上乱码,设置其他字体即可 - font-name: - # 字体大小 - font-size: 25 - -#jwt -jwt: - header: Authorization - # 令牌前缀 - token-start-with: Bearer - # 必须使用最少88位的Base64对该令牌进行编码 - base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= - # 令牌过期时间 此处单位/毫秒 ,默认2小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html - token-validity-in-seconds: 7200000 - # 在线用户key - online-key: "online_token:" - # 验证码 - code-key: "captcha_code:" - # token 续期检查时间范围(默认30分钟,单位默认毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 - detect: 1800000 - # 续期时间范围,默认 1小时,这里单位毫秒 - renew: 3600000 - -#是否允许生成代码,生产环境设置为false -generator: - enabled: false - -#如果生产环境要开启swagger,需要配置请求地址 -#springfox: -# documentation: -# swagger: -# v2: -# host: # 接口域名或外网ip - -#是否开启 swagger-ui -swagger: - enabled: false - -# 文件存储路径 -file: - mac: - path: ~/file/ - avatar: ~/avatar/ - linux: - path: /home/eladmin/file/ - avatar: /home/eladmin/avatar/ - windows: - path: C:\eladmin\file\ - avatar: C:\eladmin\avatar\ - # 文件大小 /M - maxSize: 100 - avatarMaxSize: 5 - -# 亚马逊S3协议云存储配置 -#支持七牛云,阿里云OSS,腾讯云COS,华为云OBS,移动云EOS等 -amz: - s3: - # 地域 - region: cn-wulanchabu - # 地域对应的 endpoint - endPoint: https://oss-cn-wulanchabu.aliyuncs.com - # 访问的域名 - domain: https://oss.aishangfeixing.com - # 账号的认证信息,或者子账号的认证信息 - accessKey: LTAI5tRK1mszQC82s2rCkowq - secretKey: Ns8VAkRBauIuC207s3eGiqMrLbpF4e - # 存储桶(Bucket) - defaultBucket: aishangyun - - # 文件存储路径 - timeformat: yyyy-MM \ No newline at end of file diff --git a/aircraft-system/src/main/resources/config/application.yml b/aircraft-system/src/main/resources/config/application.yml index 1219d4e..da54d97 100644 --- a/aircraft-system/src/main/resources/config/application.yml +++ b/aircraft-system/src/main/resources/config/application.yml @@ -1,3 +1,5 @@ +#测试环境配置文件dev,生产环境配置文件prod以根目录挂载的形式放在服务器,修改配置时务必到相应位置调整!!! + server: port: 8084 http2: @@ -31,7 +33,7 @@ spring: check-template-location: false profiles: # 激活的环境,如果需要 quartz 分布式支持,需要修改 active: dev,quartz - active: dev,quartz + active: local,quartz data: redis: repositories: @@ -76,4 +78,9 @@ code: #密码加密传输,前端公钥加密,后端私钥解密 rsa: - private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== \ No newline at end of file + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== + + + +udp: + receive-port: 8088 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 99b590d..57450e8 100644 --- a/pom.xml +++ b/pom.xml @@ -156,7 +156,22 @@ runtime + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + org.springframework.boot + spring-boot-starter-integration + 2.5.15 + + + org.springframework.integration + spring-integration-ip + 5.5.18 + com.alibaba