package cn.lihu.jh.module.ecg.aspect;
|
|
import cn.lihu.jh.module.ecg.annotation.RequireBedOwner;
|
import cn.lihu.jh.module.ecg.service.room.RoomService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Before;
|
import org.aspectj.lang.reflect.MethodSignature;
|
import org.springframework.stereotype.Component;
|
import org.springframework.web.bind.annotation.RequestParam;
|
|
import javax.annotation.Resource;
|
import java.lang.annotation.Annotation;
|
import java.lang.reflect.Method;
|
|
/**
|
* 「必须是工位主人」的写操作鉴权切面(主/围观模型的核心)。
|
*
|
* <p>处理被 {@link RequireBedOwner} 标注的 Controller 方法:解析出 roomId / bedNo,
|
* 交给 {@link RoomService#assertBedOwner(Long, String)} 校验;
|
* 围观人或无座者调用写接口时直接抛 {@code ROOM_NOT_OWNER}("您处于围观模式,不能执行该操作")。
|
*
|
* <p><b>为什么解析不到就放行</b>:只带 rentId 之类的接口拿不到 roomId/bedNo,
|
* 若一律拒绝会把正常业务也挡掉(例如确费)。这类接口记警告日志,并由业务自行校验。
|
*/
|
@Aspect
|
@Component
|
@Slf4j
|
public class BedOwnerAspect {
|
|
@Resource
|
private RoomService roomService;
|
|
@Before("@annotation(requireBedOwner)")
|
public void checkBedOwner(JoinPoint joinPoint, RequireBedOwner requireBedOwner) {
|
Long roomId = null;
|
String bedNo = null;
|
|
Object[] args = joinPoint.getArgs();
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
Method method = signature.getMethod();
|
Annotation[][] paramAnnotations = method.getParameterAnnotations();
|
|
for (int i = 0; i < args.length; i++) {
|
Object arg = args[i];
|
if (null == arg) {
|
continue;
|
}
|
// ① @RequestParam("roomId"/"bedNo") 直接参数
|
Annotation[] annotations = (i < paramAnnotations.length) ? paramAnnotations[i] : null;
|
if (null != annotations) {
|
for (Annotation annotation : annotations) {
|
if (!(annotation instanceof RequestParam)) {
|
continue;
|
}
|
String name = ((RequestParam) annotation).value();
|
if (name.isEmpty()) {
|
name = ((RequestParam) annotation).name();
|
}
|
if ("roomId".equals(name) && arg instanceof Number) {
|
roomId = ((Number) arg).longValue();
|
} else if ("bedNo".equals(name)) {
|
bedNo = String.valueOf(arg);
|
}
|
}
|
}
|
// ② 请求体 VO:反射读 getRoomId() / getBedNo()
|
if (isSimpleValue(arg)) {
|
continue;
|
}
|
if (null == roomId) {
|
Object v = readGetter(arg, "getRoomId");
|
if (v instanceof Number) {
|
roomId = ((Number) v).longValue();
|
}
|
}
|
if (null == bedNo) {
|
Object v = readGetter(arg, "getBedNo");
|
if (null != v) {
|
bedNo = String.valueOf(v);
|
}
|
}
|
}
|
|
if (null == roomId || null == bedNo || bedNo.isEmpty() || "null".equals(bedNo)) {
|
log.warn("[RequireBedOwner] 未能从参数解析 roomId/bedNo,跳过主人校验(该接口需自行校验). 接口={} 标记={}",
|
signature.getName(), requireBedOwner.value());
|
return;
|
}
|
roomService.assertBedOwner(roomId, bedNo);
|
}
|
|
/** 简单类型(数字/字符串/集合等)不需要做 getter 反射 */
|
private boolean isSimpleValue(Object arg) {
|
return arg instanceof Number || arg instanceof CharSequence || arg instanceof Boolean
|
|| arg instanceof java.util.Collection || arg instanceof java.util.Map;
|
}
|
|
private Object readGetter(Object target, String getterName) {
|
try {
|
Method getter = target.getClass().getMethod(getterName);
|
return getter.invoke(target);
|
} catch (Exception e) {
|
return null;
|
}
|
}
|
}
|