Est-il possible de câbler un intercepteur Spring MVC à l'aide d'annotations et, dans l'affirmative, quelqu'un pourrait-il me donner un exemple de procédure?
Par fil via des annotations, je parle de faire le moins possible dans la configuration XML. Par exemple, dans ce fichier de configuration, j'ai trouvé à 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" />
Comment peu de configuration pourriez-vous sortir avec là? J'imagine qu'un @Autowired
supprimerait la nécessité de déclarer explicitement le bean dans la ligne 2, mais serait-il possible de supprimer également la ligne 1 avec une annotation?
Autant que je sache, il n'y a aucun moyen de configurer des intercepteurs Spring MVC sans XML.
Cependant, il existe certaines simplifications avec l'espace de noms mvc
dans les dernières versions de Spring 3.0.x (et non de Spring 3.0.0!):
<mvc:interceptors>
<bean class="com.vaannila.interceptor.LoggerInterceptor" />
</mvc:interceptors>
Voir également:
Je suis tombé sur cette question en cherchant exactement ceci. Enfin, j'ai découvert que cela fonctionnait dans Spring 3.1 en utilisant @EnableWebMVC conjointement avec WebMvcConfigurerAdapter.
Exemple simple:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages="webapp.base.package")
public class WebApplicationConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor());
}
}
J'ai implémenté une solution de travail utilisant une annotation @Interceptor
personnalisée dans l'esprit de l'annotation @Controller
de Spring:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Component
public @interface Interceptor {
String[] pathPatterns() default {};
String[] excludePathPatterns() default {};
}
Cette annotation doit être appliquée aux types HandlerInterceptor
comme ceci:
@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;
}
}
Enfin, la classe de processeur, InterceptorProcessor
, est un bean Spring qui étend WebMvcConfigurerAdapter
et implémente BeanPostProcessor
afin de rechercher les annotations @Interceptor
personnalisées et d'enregistrer les beans ayant cette annotation comme étant HandlerInterceptor
s à l'intérieur de la méthode addInterceptors
remplacée:
@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;
}
}
Rappelez-vous simplement que votre application Spring doit rechercher ce bean de processeur afin qu’il enregistre réellement votre @Interceptor
s. Quelque chose comme:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"org.my.controller", "org.my.utils.processor"})
public class WebConfig extends WebMvcConfigurerAdapter {...
Je ne connais pas Spring-AOP, mais si vous utilisez AspectJ via Spring, vous pouvez utiliser @Aspect, @Pointcut, @Advise et plus encore ...
vous trouverez également un article de Nice sur l'utilisation de ces annotations avec Spring AOP: http://Java-x.blogspot.com/2009/07/spring-aop-with-aspecj-annotations.html