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.CheckControlRight; 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.domain.cache.UavTelemetryDataCache; import com.ard.work.domain.dto.telemetry.TelemetryData; import com.ard.work.domain.message.UavControlType; import com.ard.work.domain.receiver.BoxInfoReceiver; import com.ard.work.service.control.UavControlService; 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; /** * 无人机控制切面 *

* 注意切面顺序:同类方法注解按字母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️⃣ 检查在线状态 BoxInfoReceiver obj = redisCache.getCacheObject(CacheConstants.UAV_ONLINE_KEY + boxSn); if (obj == null || !obj.getOnLine().equals(1)) { 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()) { // 3️⃣ 检查在线状态 BoxInfoReceiver obj = redisCache.getCacheObject(CacheConstants.UAV_ONLINE_KEY + boxSn); if (obj == null || !obj.getOnLine().equals(1)) { 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; } // ① 提取 boxSn(无人机编号)和目标点坐标 String boxSn = null; Double targetLon = null, targetLat = null; for (Object arg : args) { if (arg == null) continue; if (boxSn == null) { String sn = ReflectUtils.getFieldValue(arg, "boxSn"); if (sn != null) boxSn = sn; } if (targetLon == null || targetLat == null) { Double lon = ReflectUtils.getFieldValue(arg, "longitude"); Double lat = ReflectUtils.getFieldValue(arg, "latitude"); if (lon != null && lat != null) { targetLon = lon; targetLat = lat; } } } if (targetLon == null || targetLat == null) { throw new ControlException("方法参数中未找到有效目标经纬度字段,无法判断禁飞区!"); } // ② 获取无人机当前位置(从缓存) Vertex current = null; if (boxSn != null) { TelemetryData telemetry = UavTelemetryDataCache.get(boxSn); if (telemetry != null) { current = new Vertex(telemetry.getLng(), telemetry.getLat()); //current = new Vertex(125.03, 46.58); } } Vertex target = new Vertex(targetLon, targetLat); // ③ 查询禁飞区 List zones = ardNoFlyZoneService.selectArdNoFlyZoneList(new ArdNoFlyZone()); if (zones.isEmpty()) return; for (ArdNoFlyZone zone : zones) { List polygon = zone.getVertices(); if (polygon == null || polygon.size() < 3) continue; // 检查目标点是否在禁飞区 if (NoFlyZoneUtils.isPointInPolygon(target, polygon)) { throw new ControlException("目标点在禁飞区【" + zone.getName() + "】内,无法执行操作!"); } // 检查路径是否穿越禁飞区 if (current != null && NoFlyZoneUtils.isLineIntersectPolygon(current, target, polygon)) { throw new ControlException("路径穿越禁飞区【" + zone.getName() + "】,无法执行操作!"); } } } }