How do you serve static files (CSS, JS, images) in Spring MVC, and where does Spring Boot look for them by default?
answer
- static/public/resources/META-INF classpath dirs
- addResourceHandler = URL, addResourceLocations = disk
- backed by ResourceHttpRequestHandler
- controllers win over static (low order)
- spring.web.resources.add-mappings=false
basics
~10 sPut files under src/main/resources/static (or public/resources/META-INF/resources) and Spring Boot serves them automatically at the URL root. To configure manually, override addResourceHandlers in a WebMvcConfigurer.
solid answer
~30 sSpring Boot auto-serves static content from classpath:/static/, classpath:/public/, classpath:/resources/, and classpath:/META-INF/resources/ — a file at static/css/app.css is reachable at /css/app.css. Under the hood these are registered as resource handlers backed by ResourceHttpRequestHandler. To customize, implement WebMvcConfigurer and override addResourceHandlers(ResourceHandlerRegistry), calling addResourceHandler("/assets/**").addResourceLocations("classpath:/static/"). The URL pattern is what clients request; the location is where files physically live (classpath or filesystem). Spring Boot's default mapping is /** with a configurable base path (spring.web.resources.static-locations). You can turn it off with spring.web.resources.add-mappings=false. This is separate from controller mapping — static handlers have the lowest precedence so controllers win on path conflicts.
code
java · 9 lines@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**")
.addResourceLocations("classpath:/static/", "file:/opt/uploads/")
.setCachePeriod(3600); // seconds
}
}go deeper
Should know the default folders and that Boot serves them automatically.
Should know addResourceHandlers/addResourceLocations and classpath vs file locations.
Should explain the ResourceHttpRequestHandler backing and precedence vs controllers.
Should discuss disabling defaults, base-path patterns, and serving user uploads from filesystem vs CDN tradeoffs.
## What 'static resources' means Static resources are files served as-is without any controller logic: CSS, JavaScript, images, fonts, HTML. Unlike a `@Controller` method that builds a response dynamically, static content is read from a location (classpath or filesystem) and streamed to the client. ## Spring Boot defaults Out of the box, Spring Boot serves static content from four classpath locations (highest to lowest precedence): - `classpath:/META-INF/resources/` - `classpath:/resources/` - `classpath:/static/` - `classpath:/public/` A file at `src/main/resources/static/css/app.css` is served at URL `/css/app.css` (the folder name `static` is NOT part of the URL). The default URL pattern is `/**`, configurable via `spring.web.resources.static-locations` and the base path via `spring.mvc.static-path-pattern` (e.g. `/resources/**`). ## The mechanism: addResourceHandlers + ResourceHttpRequestHandler Internally, Spring MVC maps static content by registering **resource handlers**. You do this by implementing `WebMvcConfigurer` and overriding `addResourceHandlers(ResourceHandlerRegistry registry)`: - `addResourceHandler("/assets/**")` — the **URL pattern** clients request. - `.addResourceLocations("classpath:/static/", "file:/opt/uploads/")` — one or more **physical locations** to look in, checked in order. Each registration produces a `ResourceHttpRequestHandler` — the actual handler that resolves a request path to a `Resource`, checks Last-Modified/ETag, sets caching headers, and writes bytes. The `SimpleUrlHandlerMapping` created from the registry has a low order, so `@RequestMapping` controllers take precedence when paths overlap. ## Location string prefixes - `classpath:/static/` — resources bundled in the jar/classpath. - `file:/opt/uploads/` — filesystem directory (useful for user-uploaded content served without a CDN). - A trailing slash is required on directory locations. ## Turning it off / customizing - `spring.web.resources.add-mappings=false` disables the default static handlers entirely. - Adding your own `addResourceHandlers` registration supplements (does not replace) the defaults unless you disable them. ## Gotchas - Path traversal (`../`) is blocked by Spring's `PathResourceResolver`, which verifies the resolved resource is inside the configured location. - Static handlers do not run through your controller filters unless configured; but globally registered `HandlerInterceptor`s do apply. - In Spring Boot 2.x properties were `spring.resources.*`; in Boot 2.4+/3.x they are `spring.web.resources.*`.
- If a controller maps /assets/report and a static file also exists at that path, which wins?The controller. Resource handlers are registered via SimpleUrlHandlerMapping with a low (late) order, so annotated handler mappings are consulted first and take precedence.
- What's the difference between addResourceHandler and addResourceLocations?addResourceHandler defines the URL pattern clients request (e.g. /assets/**); addResourceLocations defines one or more physical places (classpath:/... or file:/...) searched in order to find the file.
saying these in an interview costs you the question
- Thinking the folder name (static/public) appears in the URL
- Believing you must write a controller to serve every image or CSS file
- Claiming filesystem locations aren't supported — file: prefix works
- Confusing addResourceLocations with addResourceHandler