I just migrate to spring mvc version 5.0.1.RELEASE but suddenly in eclipse STS WebMvcConfigurerAdapter is marked as deprecated
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
// to serve static .html pages...
registry.addResourceHandler("/static/**").addResourceLocations("/resources/static/");
}
....
}
How can i remove this!
Since Spring 5 you just need to implement the interface WebMvcConfigurer:
public class MvcConfig implements WebMvcConfigurer {
This is because Java 8 introduced default methods on interfaces which cover the functionality of the WebMvcConfigurerAdapter class
See here:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.html
I have been working on Swagger equivalent documentation library called Springfox nowadays and I found that in the Spring 5.0.8 (running at present), interface WebMvcConfigurer has been implemented by class WebMvcConfigurationSupport class which we can directly extend.
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
public class WebConfig extends WebMvcConfigurationSupport { }
And this is how I have used it for setting my resource handling mechanism as follows -
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
In Spring every request will go through the DispatcherServlet. To avoid Static file request through DispatcherServlet(Front contoller) we configure MVC Static content.
Spring 3.1. introduced the ResourceHandlerRegistry to configure ResourceHttpRequestHandlers for serving static resources from the classpath, the WAR, or the file system. We can configure the ResourceHandlerRegistry programmatically inside our web context configuration class.
we have added the /js/** pattern to the ResourceHandler, lets include the foo.js resource located in the webapp/js/ directory
we have added the /resources/static/** pattern to the ResourceHandler, lets include the foo.html resource located in the webapp/resources/ directory
#Configuration
#EnableWebMvc
public class StaticResourceConfiguration implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
System.out.println("WebMvcConfigurer - addResourceHandlers() function get loaded...");
registry.addResourceHandler("/resources/static/**")
.addResourceLocations("/resources/");
registry
.addResourceHandler("/js/**")
.addResourceLocations("/js/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new GzipResourceResolver())
.addResolver(new PathResourceResolver());
}
}
XML Configuration
<mvc:annotation-driven />
<mvc:resources mapping="/staticFiles/path/**" location="/staticFilesFolder/js/"
cache-period="60"/>
Spring Boot MVC Static Content if the file is located in the WAR’s webapp/resources folder.
spring.mvc.static-path-pattern=/resources/static/**
Use org.springframework.web.servlet.config.annotation.WebMvcConfigurer
With Spring Boot 2.1.4.RELEASE (Spring Framework 5.1.6.RELEASE), do like this
package vn.bkit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; // Deprecated.
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
public class MvcConfiguration implements WebMvcConfigurer {
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/");
resolver.setSuffix(".html");
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Related
We are getting the unable to infer base url when we tried to access the swagger url
We use Spring 5.3.18 and we don't use spring security.
We are using the Spring fox 3.0.0 version, and below is the Swagger Config and Web Config code.
#Profile("swagger")
#Configuration
#EnableSwagger2
#Import(SpringDataRestConfiguration.class)
public class SwaggerConfig {
private static final String DEFAULT = "1. Default";
#Bean
public Docket apiDocket() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("basepackage.rest.controller"))
.paths(PathSelectors.any()).build();
}
}
#EnableWebMvc
#Configuration
#Profile("swagger")
public class WebConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
I was trying to implement Pageable in my RestController and running into issues with this error message "No primary or default constructor found for interface org.springframework.data.domain.Pageable"
My Controller is
#GetMapping("/rest/category/all/page")
public Page<ItemCategory> getAllItemCategoryByPage(Pageable pageable){
Page<ItemCategory> categories = itemCategoryService.getAllItemCategoriesByPageable(pageable);
return categories;
}
What am I doing wrong here. It is a Spring Boot 2.0 Application.
Thanks in advance!
The selected solution is a workaround. You can make Spring resolve the parameters automatically using this configuration :
import org.springframework.context.annotation.Configuration;
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
#Configuration
#EnableSpringDataWebSupport
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add( new PageableHandlerMethodArgumentResolver());
}
}
I had the same problem with the WebFlux app. Spring Boot 2.4.0 misses the corresponding #EnableSpringDataWebSupport for the reactive apps but luckily provide working resolver implementation. You can enable it in the following way:
#Configuration
public class PageableWebFluxConfiguration implements WebFluxConfigurer {
#Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
configurer.addCustomResolver(new ReactivePageableHandlerMethodArgumentResolver());
}
}
If you use Clément Poissonnier's solution, check if a configuration class do not override another one.
I had the same problem and the solution below could not fix it:
#Configuration
#EnableSpringDataWebSupport
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add( new PageableHandlerMethodArgumentResolver());
}
}
I still had the message:
No primary or default constructor found for interface
org.springframework.data.domain.Pageable
I then realized the project had a Swagger configuration class:
#Configuration
#EnableSwagger2
public class SwaggerConfiguration extends WebMvcConfigurationSupport {
// Swagger configuration...
}
and that the above WebMvcConfig configuration was ignored.
The solution was to have only one configuration class:
#Configuration
#EnableSwagger2
public class WebMvcConfig extends WebMvcConfigurationSupport {
// Swagger configuration...
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add( new PageableHandlerMethodArgumentResolver());
}
}
}
You might also no need #EnableSpringDataWebSupport as pointed by John Paul Moore's answer
You can configure your test as:
#BeforeEach
public void setup(){
mockMvc = MockMvcBuilders.standaloneSetup(messageController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();
}
See explanation https://www.javafixing.com/2021/12/fixed-request-is-not-being-executed-in.html
I would suggest refactoring you controller to
public List<ItemCategory> getAllItemCategoryByPage(#RequestParam("page") int pageIndex,
#RequestParam("size") int pageSize){
return itemCategoryService
.getAllItemCategoriesByPageable(PageRequest.of(pageIndex, pageSize)).getContent();
}
I think you are missing an annotation before Pageable (how are you sending that data from client?).
Just to add to the answers already given regarding enabling #EnableSpringDataWebSupport using the annotation. This should already be enabled with spring boot auto configuration. You may need to check your configuration, or is this auto configuration class being excluded using java config or in application properties.
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
For Non Spring Boot Code:
I was dealing with some existing spring mvc code base without spring boot, there was already a RequestMappingHandlerAdapter bean registered in the xmls, so I had to do this
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
...
<property name="customArgumentResolvers">
<list>
<bean class="org.springframework.data.web.PageableHandlerMethodArgumentResolver">
</bean>
</list>
</property>
</bean>
I have a web application with the following configuration class:
#Configuration
#EnableWebMvc
#EnableSpringDataWebSupport
class CustomMvcConfiguration extends WebMvcConfigurerAdapter {
#Bean
public MyBean myBean() {
return new MyBean();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
}
}
I want to add a dependency of a jar on the application, add another bean and another interceptor to the context.In another project I have another WebMvcConfigurerAdapter class but it does not run:
#Configuration
#EnableWebMvc
#EnableSpringDataWebSupport
class OtherCustomMvcConfiguration extends WebMvcConfigurerAdapter {
#Bean
public OtherBean otherBean() {
return new OtherBean();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomInterceptor());
}
}
If I try to inject the OtherBean into a class of the application web does not exist in context:
#Inject
private OtherBean otherBean;
And the CustomInterceptor does not run. How can I add beans and interceptors to an application from an external module?
I think you just need to add proper #Include annotation to your MVC Configuration.
#Include(OtherCustomMvcConfiguration.class)
class CustomMvcConfiguration extends WebMvcConfigurerAdapter {
...
}
We're running a Spring setup where I don't see any XML config files, seems everything is done via annotation.
I've got some custom component classes in a specific package I need added to the spring context for autowiring and I annotated the class with #Component but it's not making a difference. Am I missing another annotation?
There is one loop I have where I needed to do a component scan to discover all the classes in the package, maybe I can just add them there since I'd already have a BeanDefinition handle on them. If so, what would I have to do?
for (BeanDefinition bd : scanner.findCandidateComponents("com.blah.target")) {
// how to add it to context here?
}
If you don't see any XML config file, then the project should have a package springconfig with a java file called WebConfig.java. This is exact equivalent of XML config file.
Below is a snippet of a typical Webconfig.java
package .....springconfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
<...>
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="<your source package>")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
String dir="/resources/";
registry.addResourceHandler("/images/**").addResourceLocations(dir + "images/");
...
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(100);
return resolver;
}
}
Check out this tutorial: Simple Spring MVC Web Application It is very nicely explained here.
I want to add spring mvc interceptor as part of Java config. I already have a xml based config for this but I am trying to move to a Java config. For interceptors, I know that it can be done like this from the spring documentation-
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
}
}
But my interceptor is using a spring bean autowired into it like follows-
public class LocaleInterceptor extends HandlerInterceptorAdaptor {
#Autowired
ISomeService someService;
...
}
The SomeService class looks like follows-
#Service
public class SomeService implements ISomeService {
...
}
I am using annotations like #Service for scanning the beans and have not specified them in the configuration class as #Bean
As my understanding, since java config uses new for creating the object, spring will not automatically inject the dependencies into it.
How can I add the interceptors like this as part of the java config?
Just do the following:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
LocaleInterceptor localInterceptor() {
return new LocalInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeInterceptor());
}
}
Of course LocaleInterceptor needs to be configured as a Spring bean somewhere (XML, Java Config or using annotations) in order for the relevant field of WebConfig to get injected.
The documentation for general customization of Spring's MVC configuration can be found here, and specifically for Interceptors see this section
When you handle the object creation for yourself like in:
registry.addInterceptor(new LocaleInterceptor());
there is no way the Spring container can manage that object for you and therefore make the necessary injection into your LocaleInterceptor.
Another way that could be more convenient for your situation, is to declare the managed #Bean in the #Configuration and use the method directly, like so:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public LocaleInterceptor localeInterceptor() {
return new LocaleInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( localeInterceptor() );
}
}
Try to inject your service as a constructor parameter. It is simple.
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
ISomeService someService;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor(someService));
}
}
Then reconfigure your interceptor,
public class LocaleInterceptor extends HandlerInterceptorAdaptor {
private final ISomeService someService;
public LocaleInterceptor(ISomeService someService) {
this.someService = someService;
}
}
Cheers !