Spring WebMVC 5 - Annotation based Interceptor - java

How to configure an Interceptor, through Annotation only(I do NOT like to register the interceptor in .XML file, I do not use .XML based configuration)?
Note : I see in example on internet it is suggesting to use org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter, when I tried to use it, I found it is DEPRECATED
I am testing on SpringWebMVC-5 with SpringBoot-2

In Spring5 you can use org.springframework.web.servlet.config.annotation.WebMvcConfigurer:
#EnableWebMvc
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(....);
}
}

Related

How does Spring configuration class get instance of objects expected by its methods?

There are several features in Spring that are sort of black box for me.
In this case, I'm playing with websockets and there is #Configuration class implementing or extending something with overrided methods that expects instantiated objects as parameters.
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
Method configureMessageBroker expects instance of MessageBrokerRegistry class, but there isn't any bean configuration in the whole project.
My question is, where does Spring get an instance of those classes?
This is not only for #EnableWebSocketMessageBroker but for any other spring configuration. What you need to understand is when you run the project, spring creates the required objects, in this case MessageBrokerRegistry, inject it, then pass it to configureMessageBroker and call the method. This is the reason you add #Configuration annotation to a class. This annotation tells spring to initialize the related environment during spring initialization.
Another example:
#Configuration
#EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Now here we need DefaultServletHandlerConfigurer and it is created and managed completely by spring.The configureDefaultServletHandling() method is overridden and we enable default servlet handler. This will let other http request such as .css, .js slip through the usual DispatcherServlet and let the container process them. So now we can serve the static files css and javascript from our WebApp folder.
In short, #Configuration tells spring to set up the environment, so all the method in a class annotated with #Configuration are for initialization and are only and only for spring to manage.
As pointed out by Esther Álvarez Feijoo, you can understand it better by debugging.
#Configuration annotates that class also as a #Component (See the code of #Configuration, it has that annotation). This way, an instance of your WebSocketConfig is available in the IoC container.
The method "configureMessageBroker" is not magically invoked just because of that, and the argument "MessageBrokerRegistry registry" is not injected. It's just a regular method, that anybody with the class instance can invoke, passing the suitable argument
When running your app, in some step of spring initialization, spring will need to configure the web socket utilities, and will look for a implementation of "AbstractWebSocketMessageBrokerConfigurer", or some or its interfaces. It'll find your class instance, and use it for that configuration, passing the necessary parameters to the methods, because Spring already have them.
You can see this behaviour much better with the debugger. Put a break point in your method, and see the call stack. You can do reverse engineering and see how your method is invoked.

Webjars + Springboot. Custom resource path

I have a Spring Boot application which acts as a server for my frontend, built by webpack and included into my spring boot web archive.
I use webjars to access my frontend scripts and contents.
But there is one problem. To access webjars resources I need to use pathes like:
/webjars/jar-file-name/resource-name.ext
When in my react-js frontend code I use relateve pathes:
/resource-name.ext
I want to rebind paths of webjars to serve all resources /** from /webjars/jar-file-name
I have used this do to do it https://www.webjars.org/documentation#springmvc, but this seems to not work with Spring Boot
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/webjars/jar-file-name/");
}
}
It should work with Spring MVC, but don't work in Spring Boot.
Could you please advice the right way to do it?
I think the following code would resolve your issue:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Here is my static content serving URL for bootstrap 3.1.0 from tutorial: http://localhost:8080/bootstrap/3.1.0/css/bootstrap.min.css

confuse between WebMvcConfigurationSupport and WebMvcConfigurerAdapter

I would like to add resource handlers using WebMvcConfigurerAdapter in Windows, but in Linux it doesn't work, so I add WebMvcConfigurationSupport.
After debug and test I find two bean will be create in both OS, but the override function of WebMvcConfigurerAdapter will be executed only at Windows and the override function of WebMvcConfigurationSupport will be executed only at Linux.
I can't find out the reason. The two configuration classes are shown below:
#Configuration
public class JxWebAppConfigurer extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("file:"+System.getProperty("user.dir")+"/src/main/webapp/");
super.addResourceHandlers(registry);
}
}
This is the other one:
#Configuration
public class JxWebConfiguration extends WebMvcConfigurationSupport {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("file:"+System.getProperty("user.dir")+"/src/main/webapp/");
super.addResourceHandlers(registry);
}
}
#EnalbeMvc is already been added at the main class
As mentioned in the #EnableWebMvc Documentation:
Adding this annotation to an #Configuration class imports the Spring
MVC configuration from WebMvcConfigurationSupport
{..}
To customize the imported configuration, implement the interface
WebMvcConfigurer or more likely extend the empty method base class
WebMvcConfigurerAdapter and override individual methods
{..}
If WebMvcConfigurer does not expose some advanced setting that needs
to be configured, consider removing the #EnableWebMvc annotation and
extending directly from WebMvcConfigurationSupport
So in effect either:
#EnableWebMvc + extending WebMvcConfigurerAdapter (suggested first option)
Extending directly from WebMvcConfigurationSupport (fallback alternative for full control)
(on both cases needed #Configuration)
The alternative solution for org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapteris org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport (I am using Spring Framework 5.0.2.RELEASE).
WebMvcConfigurerAdapter has been deprecated.
I know the reasons. As mentioned above,you should choose one select(extends WebMvcConfigurerAdapter+#EnableWebMvc or just extends WebMvcConfigurationSupport ) ;
Never use #EnableWebMvc and extending WebMvcConfigurationSupport
together!!
if use spring-boot's #EnableAutoConfiguration ,you can just extends WebMvcConfigurerAdapter and don't use #EnableMvc
Behavior differences on OS are not clear to me (classpath order?) so I'll just talk about WebMvcConfigurationSupport vs WebMvcConfigurer. Let's start with WebMvcConfigurerAdapter that implements WebMvcConfigurer, but now is deprecated because the interface has the functionality via default methods.
Now to the "support" (extending WebMvcConfigurationSupport) vs "configurer" (implementing WebMvcConfigurer). These classes have very similar methods but it works roughly like this:
Support component finds all the configurers and combines them into the final configuration.
I recently wrote quite a long post about this with code examples and I recommend experimenting with small Spring Boot applications and debug them - it's eye opening.
Boot has a default implementation of WebMvcConfigurationSupport and it does a lot of stuff - including finding beans implementing WebMvcConfigurer and using them. If you take over and implement the support class, Boot will find it, disables the default one and you're in full control. But then a lot of default auto-magic is gone and you have to use it if needed.

Annotation Configuration Replacement for mvc:resources - Spring

I'm trying to upgrade my spring mvc project to utilize the new annotations and get rid of my xml. Previously I was loading my static resources in my web.xml with the line:
<mvc:resources mapping="/resources/**" location="/resources/" />
Now, I'm utilizing the WebApplicationInitializer class and #EnableWebMvc annotation to startup my service without any xml files, but can't seem to figure out how to load my resources.
Is there an annotation or new configuration to pull these resources back in without having to use xml?
For Spring 3 & 4:
One way to do this is to have your configuration class extend WebMvcConfigurerAdapter, then override the following method as such:
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
Spring 5
As of Spring 5, the correct way to do this is to simply implement the WebMvcConfigurer interface.
For example:
#Configuration
#EnableWebMvc
public class MyApplication implements WebMvcConfigurer {
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
See deprecated message in: WebMvcConfigurerAdapter

Properties with Spring #Configuration

If I have a PropertyPlaceholderConfigurer coming via an XML file, is it possible to have my Spring #Configuration use that as its source of properties for all the beans it handles?
#Configuration
#ComponentScan(value = { "x.y.z })
#ImportResource({ "classpath:remote-properties/applicationContext.xml",})
public class CoreConfiguration implements TransactionManagementConfigurer {
#Resource(name = "com.c.h.c.PropertyPlaceholderConfigurer")
public PropertyPlaceholderConfigurer pp;
#Bean
public PropertyPlaceholderConfigurer propertiesFactoryBean() {
return pp;
}
}
With the above, it never hits my breakpoint on pp. If I remove the #Bean and the method, I can verify that pp is populated. So how I can I register it with the configuration?
I feel pretty stupid. I was missing a right curly brace on one of my #Value annotations. I can't imagine how many times I looked at that and missed it.
So, having a PropertyPlaceHolderConfigurer in an app context you #ImportResource on will work without any problems. You don't even need to bring it in as a #Resource.

Categories