package com.ard.work.aspect;
|
|
import com.ard.common.constant.CacheConstants;
|
import com.ard.common.core.redis.RedisCache;
|
import com.ard.common.exception.ControlException;
|
import com.ard.common.utils.SecurityUtils;
|
import com.ard.common.utils.StringUtils;
|
import com.ard.common.utils.reflect.ReflectUtils;
|
import com.ard.data.noflyzone.domain.ArdNoFlyZone;
|
import com.ard.data.noflyzone.domain.Vertex;
|
import com.ard.data.noflyzone.service.IArdNoFlyZoneService;
|
import com.ard.data.noflyzone.utils.NoFlyZoneUtils;
|
import com.ard.work.aspect.annotation.CheckDroneStatus;
|
import com.ard.work.aspect.annotation.CheckNoFlyZone;
|
import com.ard.work.aspect.annotation.CheckTakeoffAltitude;
|
import com.ard.work.aspect.annotation.CheckControlRight;
|
import com.ard.work.domain.cache.UavTelemetryDataCache;
|
import com.ard.work.domain.dto.telemetry.TelemetryData;
|
import com.ard.work.domain.entity.ArdDroneInfo;
|
import com.ard.work.service.IArdDroneInfoService;
|
import com.ard.work.service.control.UavControlService;
|
import com.ard.work.domain.message.UavControlType;
|
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Before;
|
import org.springframework.stereotype.Component;
|
|
import javax.annotation.Resource;
|
import java.util.List;
|
|
/**
|
* 无人机控制切面
|
* <p>
|
* 注意切面顺序:同类方法注解按字母ABCD顺序,不同类注解按order(1)顺序 越小优先级越高
|
*/
|
@Aspect
|
@Component
|
public class UavControlAspect {
|
|
@Resource
|
private UavControlService uavControlService;
|
@Resource
|
private IArdNoFlyZoneService ardNoFlyZoneService;
|
@Resource
|
private RedisCache redisCache;
|
|
/**
|
* 控制权检查
|
*/
|
@Before("@annotation(checkControlRight)")
|
public void checkUavControl(JoinPoint joinPoint, CheckControlRight checkControlRight) {
|
// 获取当前用户 ID
|
Long userId = SecurityUtils.getUserId();
|
|
// 获取控制类型
|
UavControlType controlType = checkControlRight.value();
|
|
// 获取方法参数
|
Object[] args = joinPoint.getArgs();
|
|
for (Object arg : args) {
|
if (arg == null) {
|
continue;
|
}
|
|
// 1️⃣ 获取 boxSn
|
String boxSn = ReflectUtils.getFieldValue(arg, "boxSn");
|
if (StringUtils.isBlank(boxSn)) {
|
continue;
|
}
|
|
// 2️⃣ 检查控制权
|
Long currentController = uavControlService.getCurrentController(boxSn,
|
controlType.name().toLowerCase());
|
if (currentController == null || !currentController.equals(userId)) {
|
throw new ControlException("无权执行该操作,需要 " + controlType + " 控制权限");
|
}
|
|
// 3️⃣ 检查在线状态
|
Boolean online = redisCache.getCacheObject(CacheConstants.UAV_ONLINE_KEY + boxSn);
|
if (online == null || !online) {
|
throw new ControlException("无人机离线,无法执行操作!boxSn: " + boxSn);
|
}
|
|
}
|
}
|
|
/**
|
* 高度检查
|
*/
|
@Before("@annotation(checkTakeoffAltitude)")
|
public void takeoffAltitudeCheck(JoinPoint joinPoint, CheckTakeoffAltitude checkTakeoffAltitude) {
|
// 获取最小高度
|
double minAltitude = checkTakeoffAltitude.minAltitude();
|
// 获取方法参数
|
Object[] args = joinPoint.getArgs();
|
|
// 遍历参数,使用反射获取每个参数中的 boxSn
|
for (Object arg : args) {
|
String boxSn = ReflectUtils.getFieldValue(arg, "boxSn"); // 调用之前实现的 getBoxSn 方法
|
if (boxSn != null) {
|
TelemetryData uavTelemetryData = UavTelemetryDataCache.get(boxSn);
|
if (uavTelemetryData == null) {
|
throw new ControlException("遥测数据异常,无法执行!");
|
}
|
// 检查高度
|
if (uavTelemetryData.getAltitude() < minAltitude) {
|
throw new ControlException("高度太低,无法执行!最低高度: " + minAltitude);
|
}
|
}
|
}
|
}
|
|
/**
|
* 状态检查
|
*/
|
@Before("@annotation(checkDroneStatus)")
|
public void checkDroneStatus(JoinPoint joinPoint, CheckDroneStatus checkDroneStatus) {
|
for (Object arg : joinPoint.getArgs()) {
|
if (arg == null) {
|
continue;
|
}
|
|
String boxSn = ReflectUtils.getFieldValue(arg, "boxSn");
|
if (boxSn == null) {
|
continue;
|
}
|
// 检查在线状态
|
if (checkDroneStatus.checkOnline()) {
|
Boolean online = redisCache.getCacheObject(CacheConstants.UAV_ONLINE_KEY + boxSn);
|
if (online == null || !online) {
|
throw new ControlException("无人机离线,无法执行操作!boxSn: " + boxSn);
|
}
|
}
|
}
|
}
|
|
/**
|
* 禁飞区检查
|
*/
|
@Before("@annotation(checkNoFlyZone)")
|
public void checkNoFlyZone(JoinPoint joinPoint, CheckNoFlyZone checkNoFlyZone) {
|
Object[] args = joinPoint.getArgs();
|
if (args == null || args.length == 0) {
|
return;
|
}
|
|
Double longitude = null;
|
Double latitude = null;
|
|
for (Object arg : args) {
|
if (arg == null) {
|
continue;
|
}
|
Double lon = ReflectUtils.getFieldValue(arg, "longitude");
|
Double lat = ReflectUtils.getFieldValue(arg, "latitude");
|
if (lon != null && lat != null) {
|
longitude = lon;
|
latitude = lat;
|
break;
|
}
|
}
|
|
if (longitude == null || latitude == null) {
|
throw new ControlException("方法参数中未找到有效经纬度字段,无法判断禁飞区!");
|
}
|
|
List<ArdNoFlyZone> ardNoFlyZones = ardNoFlyZoneService.selectArdNoFlyZoneList(new ArdNoFlyZone());
|
if (!ardNoFlyZones.isEmpty()) {
|
Vertex vertex = new Vertex(longitude, latitude);
|
boolean inNoFlyZones = NoFlyZoneUtils.isInNoFlyZones(vertex, ardNoFlyZones);
|
if (inNoFlyZones) {
|
throw new ControlException("目标点在禁飞区内,无法执行操作!");
|
}
|
}
|
}
|
|
}
|