1.背景
最近项目中使用了数据字典,在写订单模块时会经常在映射方法中将订单的类型和订单的状态放到request域或model域中。
由于订单模块业务映射很多,一个个添加太麻烦,所以想到AOP来实现。
2.问题描述
自己写了一个AOP,访问时发现,有些映射访问错误,属性注入为空
3.aop代码
package com.chongdong.web.common.aspect;
import com.chongdong.common.dict.ListTypeParameter;
import com.chongdong.common.log.Log;
import com.chongdong.common.log.LogFactory;
import com.chongdong.web.common.annotation.OrderDictData;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* @Description 加载订单相关字典表数据
* @Author: yanxh<br>
* @Date 2019/11/4 9:57<br>
* @Version 1.0<br>
*/
@Aspect
@Component("orderDictDataAspect")
public class OrderDictDataAspect {
final static Log log = LogFactory.getLogger(OrderDictDataAspect.class);
public OrderDictDataAspect() {log.info("加载订单字典数据的切面");}
/**
* @Description 配置切入点
* @Author: yanxh<br>
* @Date 2019/11/4 9:59<br>
* @Version 1.0<br>
*/
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void pointCut() {}
/**
* 后置通知
* @param joinPoint
*/
@AfterReturning(returning="returnValue",value="pointCut()")
public void afterReturning(JoinPoint joinPoint, Object returnValue) {
setOrderDictData(joinPoint, null, returnValue);
}
/**
* 拦截异常操作,有异常时执行
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "pointCut()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Exception e) {
setOrderDictData(joinPoint, e, null);
}
/**
* @Description 设置订单数据字典
* @Author: yanxh<br>
* @Date 2019/11/4 13:54<br>
* @Version 1.0<br>
*/
private void setOrderDictData(JoinPoint joinPoint, Exception e, Object returnValue) {
try {
// 获取切入的类
Object target = joinPoint.getTarget();
// 非注解引用类,直接跳过
if(!target.getClass().isAnnotationPresent(OrderDictData.class)){
return;
}
// 获得注解
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
// 获取目标类的方法
Method method = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
// 获取拦截的请求参数
Object[] args = joinPoint.getArgs();
/**
* 加载订单相关字典表数据
*/
// 这里获取所有的参数
Class<?>[] clas = method.getParameterTypes();
for (int i=0; i<clas.length; i++){
//根据参数名称,做某些处理
String requestParam = clas[i].getSimpleName();
// 获取request请求
if ("HttpServletRequest".equals(requestParam)){
HttpServletRequest request = (HttpServletRequest)args[i];
// 订单类型
request.setAttribute("orderTypeList", ListTypeParameter.ORDER_TYPE);
// 订单状态
request.setAttribute("orderStatusList", ListTypeParameter.ORDER_STATUS);
break;
}
// 获取model请求
if ("ModelMap".equals(requestParam)){
ModelMap model = (ModelMap)args[i];
// 订单类型
model.addAttribute("orderTypeList", ListTypeParameter.ORDER_TYPE);
// 订单状态
model.addAttribute("orderStatusList", ListTypeParameter.ORDER_STATUS);
break;
}
}
} catch (Exception exp) {
// 记录本地异常日志
log.error("设置订单字典数据出错,异常信息:{"+exp.getMessage()+"}");
exp.printStackTrace();
}
}
}
4.原因
对比发现,映射的方法用private进行了访问限制,改为public即可
5.总结
AOP切入的方法,其访问权限为protected/public,如果匹配private时,会导致其方法中所有的属性注入 注入失败。