Подтвердить что ты не робот

Можно ли подключить проводник Spring MVC Interceptor с помощью аннотаций?

Можно ли связать проводник Spring MVC Interceptor с аннотациями, и если да, то может ли кто-нибудь предоставить мне пример того, как это сделать?

По проводке через аннотацию я имею в виду как можно меньше в XML-конфигурации, насколько это возможно. Например, в этом файле конфигурации я нашел в http://www.vaannila.com/spring/spring-interceptors.html;

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" p:interceptors-ref="loggerInterceptor" />
<bean id="loggerInterceptor" class="com.vaannila.interceptor.LoggerInterceptor" />

Какую небольшую конфигурацию вы могли бы избежать? Я полагаю, что @Autowired устранит необходимость явного объявления bean в строке 2, но можно ли также избавиться от строки 1 с помощью аннотации?

4b9b3361

Ответ 1

Насколько я знаю, нет способов настроить Spring перехватчики MVC без XML вообще.

Однако существуют некоторые упрощения с пространством имен mvc в последних версиях Spring 3.0.x(не Spring 3.0.0!):

<mvc:interceptors>
    <bean class="com.vaannila.interceptor.LoggerInterceptor" />
</mvc:interceptors>

См. также:

Ответ 2

Наткнулся на этот вопрос, ища именно это. Наконец, я узнал, что он работает в Spring 3.1, используя @EnableWebMVC в сочетании с WebMvcConfigurerAdapter.

Простой пример:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages="webapp.base.package")
public class WebApplicationConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggerInterceptor());
    }

}

Ответ 3

Я не знаю о spring -AOP, но если вы используете AspectJ через Spring, вы можете использовать @Aspect, @Pointcut, @Advise и многое другое...

там также хорошая статья о том, как использовать эту аннотацию с Spring AOP здесь: http://java-x.blogspot.com/2009/07/spring-aop-with-aspecj-annotations.html

Ответ 4

Я реализовал рабочее решение с использованием пользовательской аннотации @Interceptor в духе аннотации Spring @Controller:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Component
public @interface Interceptor {
  String[] pathPatterns() default {};
  String[] excludePathPatterns() default {};
}

Эта аннотация должна применяться к типам HandlerInterceptor следующим образом:

@Interceptor
public class BuildTimestampInterceptor extends HandlerInterceptorAdapter {
  private final String buildTimestamp;

  public BuildTimestampInterceptor(@Value("${build.timestamp}") String buildTimestamp) {
    this.buildTimestamp = buildTimestamp;
  }

  @Override
  public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
    req.setAttribute("buildTimestamp", buildTimestamp);
    return true;
  }
}

Наконец, класс процессора InterceptorProcessor представляет собой Spring bean, который расширяет WebMvcConfigurerAdapter и реализует BeanPostProcessor для сканирования пользовательских аннотаций @Interceptor и регистрации beans, имеющих эту антацию как HandlerInterceptor внутри переопределенного метода addInterceptors:

@Component
public class InterceptorProcessor extends WebMvcConfigurerAdapter implements BeanPostProcessor {
  private final Map<HandlerInterceptor,Interceptor> interceptors = new HashMap<>();

  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    scanForInterceptorAnnotation(bean, beanName);
    return bean;
  }

  @Override
  public Object postProcessAfterInitialization(Object bean, String string) throws BeansException {
    return bean;
  }

  protected void scanForInterceptorAnnotation(Object bean, String beanName) {
    Optional<Interceptor> optionalInterceptor = getInterceptorAnnotation(bean.getClass());
    if (optionalInterceptor.isPresent() && bean instanceof HandlerInterceptor) {
      interceptors.put((HandlerInterceptor) bean, optionalInterceptor.get());
    }
  }

  private Optional<Interceptor> getInterceptorAnnotation(Class cls) {
    Annotation[] annotations = cls.getAnnotationsByType(Interceptor.class);
    if (hasValue(annotations)) {
      return Optional.of((Interceptor) annotations[0]);
    }
    return Optional.empty();
  }

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    interceptors.forEach((HandlerInterceptor key, Interceptor val) -> {
      InterceptorRegistration registration = registry.addInterceptor(key);
      if (hasValue(val.pathPatterns())) {
        registration.addPathPatterns(val.pathPatterns());
      }

      if (hasValue(val.excludePathPatterns())) {
        registration.excludePathPatterns(val.excludePathPatterns());
      }
    });
  }

  private static <T> boolean hasValue(T[] array) {
    return array != null && array.length > 0;
  }
}

Просто запомните, что ваш сканер приложений Spring для этого процессора bean, чтобы он действительно зарегистрировал ваш @Interceptor s. Что-то вроде:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"org.my.controller", "org.my.utils.processor"})
public class WebConfig extends WebMvcConfigurerAdapter {...

Ответ 5

как Markus Kreusch'answers, он также мог бы работать следующим образом

@Configuration
@EnableWebMvc
@ComponentScan(basePackages="webapp.base.package")
public class WebApplicationConfig extends WebMvcConfigurerAdapter {

    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping RequestMappingHandlerMapping=  super.requestMappingHandlerMapping();
        Object[] interceptors = new Object[1];
        interceptors[0] = new RoleInterceptor();
        RequestMappingHandlerMapping.setInterceptors(interceptors);
        return RequestMappingHandlerMapping;
    }

}