feat:飞行日志接入

This commit is contained in:
sugus 2025-10-09 17:20:01 +08:00
parent c87eed4ce8
commit 792a230d61
9 changed files with 394 additions and 156 deletions

View File

@ -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<PageResult<AircraftLog>> 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));
}
}

View File

@ -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;
}

View File

@ -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<AircraftLog> findByUavUUID(String uavUUID, int page, int size);
}

View File

@ -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<AircraftLog> 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<AircraftLog> 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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -1,6 +1,15 @@
#配置数据源 #配置数据源
spring: spring:
data:
mongodb:
host: 8.130.155.168
port: 27017
database: aircraft
username: aircraft
password: rGisFzT8PDtHYftL
authentication-database: aircraft
datasource: datasource:
druid: druid:
db-type: com.alibaba.druid.pool.DruidDataSource db-type: com.alibaba.druid.pool.DruidDataSource

View File

@ -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

View File

@ -1,3 +1,5 @@
#测试环境配置文件dev生产环境配置文件prod以根目录挂载的形式放在服务器修改配置时务必到相应位置调整
server: server:
port: 8084 port: 8084
http2: http2:
@ -31,7 +33,7 @@ spring:
check-template-location: false check-template-location: false
profiles: profiles:
# 激活的环境,如果需要 quartz 分布式支持,需要修改 active: dev,quartz # 激活的环境,如果需要 quartz 分布式支持,需要修改 active: dev,quartz
active: dev,quartz active: local,quartz
data: data:
redis: redis:
repositories: repositories:
@ -76,4 +78,9 @@ code:
#密码加密传输,前端公钥加密,后端私钥解密 #密码加密传输,前端公钥加密,后端私钥解密
rsa: rsa:
private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
udp:
receive-port: 8088

15
pom.xml
View File

@ -156,7 +156,22 @@
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- spring-integration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
<version>2.5.15</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-ip</artifactId>
<version>5.5.18</version>
</dependency>
<!-- druid数据源驱动 --> <!-- druid数据源驱动 -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>