Spring Extension (4) — AOP based Interceptor for Controller

来源:互联网 发布:岛风go软件打不开 编辑:程序博客网 时间:2024/04/29 01:04

场景:

SpringMVC HandlerInterceptor只能提供基于http url requestAOP拦截,如果Controller中某些RequestMapping handler method需要权限才能访问----当然可以通过handler method对应urlHandlerInterceptor来完成这个要求,这样就比较麻烦:HandlerInterceptor配置文件中设置了一堆的url字符串,而且不停的增长、膨胀。。。

如果通过能用handler method 级别的aop来完成这个功能,只需要在handler method上添加一个Annotation表示当前方法需要权限验证即可,然后通过 AOP Advice来做这些判断。

代码:

1、定义Annotation

  /**   * true:user should be authed before the action.false:needn't.   */  @Documented  @Target({ElementType.TYPE,ElementType.METHOD})  @Retention(RetentionPolicy.RUNTIME)  public @interface AuthRequired {      public boolean value() default true;   }


2、在目标方法上定义:

@Controller@RequestMapping("/")public class UserController{@RequestMapping(value="/demo")  @AuthRequired //http访问表示当前方法,需要用户先登陆public @ResponseBody Map<String, String>> demo(@RequestAttribute("loginUserId") long loginUserId){return Collections.emptyMap();}}

3AOP定义

1Advice


  /**   * verify whether user is authed   *    */  @Component("authAdvice")  public class AuthAdvice implements MethodBeforeAdvice {      private static final Logger logger = LoggerFactory.getLogger(AuthAdvice.class);      @Override      public void before(Method method, Object[] args, Object target) throws Throwable {          HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder                  .getRequestAttributes()).getRequest();//获取request                    Long userId = (Long) request.getAttribute("loginUserId");                    AuthRequired needAuth = AnnotationUtils.findAnnotation(method, AuthRequired.class);          if (needAuth != null&&needAuth.value) {              if(userId == null)              throw new NotLoginException("not login");          }              }


2、PointcutAdvisor

  /**   * aspect pointcut for the controller and verifying whether is logined.   *    */  @Component("authAdvisor")  public class AuthPointcutAdvisor extends StaticMethodMatcherPointcutAdvisor {      /**       * must be the {@link RequestMapping}       */      @Override      public boolean matches(Method method, Class<?> targetClass) {          RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);          if (mapping != null) {// 只拦截RequestMapping修饰的方法              return true;          }          return false;      }      /**       * must be {@link Controller}       */      public ClassFilter getClassFilter() {          return new ClassFilter() {              @Override              public boolean matches(Class<?> clazz) {                  return AnnotationUtils.isAnnotationDeclaredLocally(Controller.class, clazz);                               }          };      }        @Resource(name = "authAdvice")      public void setAdvice(Advice advice) {          super.setAdvice(advice);      }  }



4、启用AOP


  <!-- 必须在MethodValidationPostProcessor之前初始化,否则在authAdvice执行之前会优先执行Spring Validation,导致权限认证服务执行之前就执行parameter validation 操作-->  <bean id="autoProxyCreator"  class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>  <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />  <bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor" depends-on="autoProxyCreator"/>

注:

Spring Request Scope

SpringMVC中,如果使用DispatcherServlet初始SpringMVC容器,那么spring web application context默认启用request scope。故((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();能够正常获取HttpServletRequest对象。


Spring AOP

DefaultAdvisorAutoProxyCreator 比使用AspectJSchema-based AOP的好处是能够获取当前被拦截方法method对象相关的信息,例如method 上的Annotationargs上的annotation