package com.ard.work.aspect;
|
|
import com.ard.common.exception.ControlException;
|
import com.ard.common.utils.SecurityUtils;
|
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.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.lang.reflect.Field;
|
|
/**
|
* AOP 切面:拦截 @RequireUavControl,检查用户是否拥有 UAV 控制权限
|
*
|
* 注意切面顺序:同类方法注解按字母ABCD顺序,不同类注解按order(1)顺序 越小优先级越高
|
*/
|
@Aspect
|
@Component
|
public class UavControlAspect {
|
|
@Resource
|
private UavControlService uavControlService;
|
|
/**
|
* 前置通知:控制权检测
|
*/
|
@Before("@annotation(checkControlRight)")
|
public void checkUavControl(JoinPoint joinPoint, CheckControlRight checkControlRight) {
|
// 获取当前用户 ID
|
Long userId = SecurityUtils.getUserId();
|
|
// 获取控制类型
|
UavControlType controlType = checkControlRight.value();
|
|
// 获取方法参数
|
Object[] args = joinPoint.getArgs();
|
|
// 遍历参数,使用反射获取每个参数中的 boxSn
|
for (Object arg : args) {
|
String boxSn = getBoxSn(arg); // 调用之前实现的 getBoxSn 方法
|
if (boxSn != null) {
|
// 检查当前用户是否拥有该设备的控制权限
|
Long currentController = uavControlService.getCurrentController(boxSn,
|
controlType.name().toLowerCase());
|
if (currentController == null || !currentController.equals(userId)) {
|
throw new ControlException("无权执行该操作,需要 " + controlType + " 控制权限");
|
}
|
}
|
}
|
}
|
|
/**
|
* 前置通知:高度检查
|
*/
|
@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 = getBoxSn(arg); // 调用之前实现的 getBoxSn 方法
|
if (boxSn != null) {
|
TelemetryData uavTelemetryData = UavTelemetryDataCache.get(boxSn);
|
if (uavTelemetryData == null) {
|
throw new ControlException("遥测数据异常,无法执行!");
|
}
|
// 检查高度
|
if (uavTelemetryData.getAltitude() < minAltitude) {
|
throw new ControlException("高度太低,无法执行!最低高度: " + minAltitude);
|
}
|
}
|
}
|
}
|
|
/**
|
* 通过反射获取对象中的 boxSn 字段
|
*
|
* @param dto 要反射的对象
|
* @return boxSn 字段的值,如果没有找到则返回 null
|
*/
|
public static String getBoxSn(Object dto) {
|
if (dto == null) {
|
return null; // 如果对象为空,直接返回 null
|
}
|
|
try {
|
// 获取类的所有字段
|
Field[] fields = dto.getClass().getDeclaredFields();
|
for (Field field : fields) {
|
// 设置字段可访问
|
field.setAccessible(true);
|
|
// 判断是否是 boxSn 字段
|
if ("boxSn".equals(field.getName())) {
|
// 检查字段类型是否是 String 类型
|
if (field.getType().equals(String.class)) {
|
// 获取并返回 boxSn 字段的值
|
return (String) field.get(dto);
|
} else {
|
// 如果字段类型不是 String,返回 null
|
return null;
|
}
|
}
|
}
|
} catch (IllegalAccessException e) {
|
// 捕获异常并打印日志
|
System.err.println("反射访问失败: " + e.getMessage());
|
e.printStackTrace();
|
}
|
|
return null; // 如果没有找到 boxSn 字段,返回 null
|
}
|
}
|