使用AOP拦截controller层方法时,通过监控方法上的注解(@Annotation)达到业务上的隔离或验证
我认为这是一种更简单\方便的设计思路,可以有很多的适用场景。
用到了Spring框架的特性,所以先将相关特性的开关打开
开启注解:
切面代理:
1. 先创建两个注解 NeedLogin验证登录 SignFree验签处理
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Controller层的方法注解,表示该方法需要用户登录验证
*/
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface NeedLogin {
//空
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Controller层的方法注解,表示该方法不需要数字签名
*/
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface SignFree {
//空
}
2. 定义AOP切面类
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Aspect
@Component
@Order(5)
public class AspectAdvice {
private static final Logger logger = LoggerFactory.getLogger(AspectAdvice.class);
private static final Logger warnLogger = LoggerFactory.getLogger("warning");
/**
* 拦截项目中包名为xxx.controller.*的相关前端控制器
*/
@Around(value = "execution(* com.xxx.xx.x.controller..*.*(..))")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
try {
//禁止爬虫
//禁止IP
//检查业务
//上面是开始业务的前置检验
//下面是业务检验
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
// 检查auth
if (method.getAnnotation(NeedLogin.class) != null) {
if (!checkAuth(response, request)) {
// 测试环境打印日志
recordLog(request, response, pjp.getArgs(), paramMap,
start, null, !commonConfig.isOnline());
return response;
}
} else if (method.getAnnotation(SignFree.class) == null) {
// 检查sign
if (!checkSign(response, request)) {
recordLog(request, response, pjp.getArgs(), paramMap,
start, null, false);
return response;
}
}
if (method.getAnnotation(CheckPartnerSign.class) != null) {
checkPartnerSign(pjp);
}
Object result = pjp.proceed();
recordLog(request, result, pjp.getArgs(), paramMap, start, null,
false);
return result;
} catch (ServiceException e) {
response.setCode(e.getCode());
response.setMessage(e.getMessage());
recordLog(request, response, pjp.getArgs(), paramMap, start, e,
false);
return response;
} finally {
//业务处理
}
}
}
通过注解判断当前方法是否需要验证、登录等操作
3. Controller层的使用
根据业务需要增加不同的注解
@RequestMapping(value = "/isshow", method = RequestMethod.GET)
@ResponseBody
@NeedLogin //是否需要登录
@SignFree //是否需要验签
public BaseResponse checkCondition() {
CommonResponse() response = new CommonResponse();
......
return response;
}
我之前的处理方式简便性就不如这个。
如登录验证
之前是在controller层中的每个方法内部,代码段开始处做个方法的调用boolean bool = XxxService.checkLogin(XXX);
虽然说两种方式在代码上差不了多少。但是设计思路的优越性上,我更喜欢注解方式。写代码时间越久,越觉得它好. 哈哈哈
原创文章,转载请标明本文链接: 使用AOP拦截controller层方法时,通过监控方法上的注解(@Annotation)达到业务上的隔离或验证