Spring 4 - addResourceHandlers not resolving the static resources

92,681

Solution 1

this worked,

   registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");

and in the jsp files I referred to the static resources like

<link href="resources/css/bootstrap.css" rel="stylesheet" media="screen">

Solution 2

I guess it's a bit late, however I was facing with a similar problem just recently. After several days of wrestling, finally it turned out that my DispatcherServlet was not configured to handle the request, therefore the resources were never looked up. So I hope others will find this answer useful.

If the dispatcher servlet to that you give your config class above is mapped not to the root ("/") but to a top word (e.g. "/data/"), then you might face with the same problem.

Suppose I have a mapping as "/data/*" for my dispatcher servlet. So my calls look like

http://localhost:8080/myWebAppContext/data/command

and I thought that if I have a resource mapping e.g. "/content/**/*", then I have access to it as

http://localhost:8080/myWebAppContent/content/resourcePath

but it's not true, I should use

http://localhost:8080/myWebAppContent/data/content/resourcePath

instead. This was not clear for me, and since most of the samples use the root "/" for the dispatcher servlet's mapping, therefore it was not an issue there. Upon considering later I should have known it earlier - /data/ tells that the DispatcherServlet should evaluate the call, and the content/ tells to the servlet that a resource handler is the "controller".

But I want to make it very clear in my frontend (angularJs) whether I look for data (via the REST services) or a content (returning plain texts). The data comes from a database, but the content comes from files (e.g. pdf docs). Therefore, I decided to add two mappings to the dispatcher servlet:

public class MidtierWebConfig implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {

    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(MidtierAppConfig.class);

    servletContext.addListener(new ContextLoaderListener(rootContext));

    AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
    dispatcherContext.register(MidtierDispatcherConfig.class);

    Dynamic netskolaDispatcher = servletContext.addServlet(
        "dispatcher",
        new DispatcherServlet(dispatcherContext)
    );
    netskolaDispatcher.setLoadOnStartup(1);
    netskolaDispatcher.addMapping("/data/*");
    netskolaDispatcher.addMapping("/content/*");
}

}

The MidtierAppConfig class is empty, but the MidtierDispatcherConfig defines the static resources:

@Configuration
@ComponentScan("my.root.package")
@EnableWebMvc
public class MidtierDispatcherConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
            .addResourceHandler("/courses/**/*")
            .addResourceLocations("/WEB-INF/classes/content/")
        ;
    }
}

Now when I want to have access to my @Controller's, I use the /data/ prefix, and when I want to access to my resources, I use the /content/ prefix. Caveat is that if I have a @RequestMapping("/app") class which has a @RequestMapping("/about") method, then both the data/app/about and the content/app/about will call just that method (and without actually trying I guess I might access the resources as /app/courses/whatEverPath too), because the dispatcher listends to both "data/" and "content/", and analyzes only the rest of the url ("app/about" in both cases) to find the proper @Controller.

Regardless, the current solution I've reached is satisfactory enough for me, so I will leave it as it is.

Solution 3

This worked for me. Files available at /resources/js/select.js. Watch out that you are not missing @EnableWebMvc annotation....

@EnableWebMvc
@EnableTransactionManagement
public class ApplicationContextConfig extends WebMvcConfigurerAdapter {

    @Bean(name = "viewResolver")
    public InternalResourceViewResolver getViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
        .addResourceLocations("/resources/");
    }
}

Solution 4

I am using Spring Boot 2.2.1 and with "spring-boot-starter-web" and "spring-boot-starter-tomcat". In my case the Spring Boot only could find the "/resources/" folder when I use empty "classpath:/"

My folder structure:

enter image description here

My code:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
        .addResourceHandler("/resources/**")
        .addResourceLocations("classpath:/");
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

And using the browser I can find any file like:

http://localhost:8080/resources/test.txt

http://localhost:8080/resources/images/background-1.png

Share:
92,681
Vijay Veeraraghavan
Author by

Vijay Veeraraghavan

Updated on February 23, 2020

Comments

  • Vijay Veeraraghavan
    Vijay Veeraraghavan about 4 years

    My maven spring project directory structure is shown below. I am using Spring-4 annotation based configuration. I configure the resources like below. I tried many ways that are suggested in many Stackoverflow questions and other websites

    Spring 4 loading static resources

    http://imwill.com/spring-mvc-4-add-static-resources-by-annotation/#.U5GZlXKs9i4

    But the jsp files could not load the resources, all the static content requests returns 404 error. I tried these things in jsp,

     <link href="resources/css/bootstrap.css" rel="stylesheet" media="screen">
     <link href="/resources/css/bootstrap.css" rel="stylesheet" media="screen">
     <link href="css/bootstrap.css" rel="stylesheet" media="screen">
    

    EDIT: I am using servlet 2.5 because as of now I cannot upgrade my project from JBoss 5 to higher versions. JBoss5 do not support servlets 3, and do that matter?

    @Configuration
    @ComponentScan("com.mgage.mvoice")
    public class MyAppWebConfig extends WebMvcConfigurerAdapter {
         public void addResourceHandlers(ResourceHandlerRegistry registry) {  
            // I tried these many combinations separately.
    
            ResourceHandlerRegistration resourceRegistration = registry
                .addResourceHandler("resources/**");
            resourceRegistration.addResourceLocations("/resources/**");
            registry.addResourceHandler("/css/**").addResourceLocations("/css/**");
            registry.addResourceHandler("/img/**").addResourceLocations("/img/**");
            registry.addResourceHandler("/js/**").addResourceLocations("/js/**");
            registry.addResourceHandler("/resources/**")
                    .addResourceLocations("classpath:/resources/"); 
                  // do the classpath works with the directory under webapp?
         }
    
    }
    

    Project structure