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
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">
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.
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:
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
It is possible to simplify the web page's URI just to contain the filename of a resource:
<link href="bootstrap.css" rel="stylesheet" media="screen">
An appropriate configuration might be as the following:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("*.css").addResourceLocations("/resources/css/");
}
Spring concatenates '/resources/css/' string with whatever filename extracted from URI to identify the actual location of a resource.
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/");
}
}