I'm using Spring Boot (v1.3.5.RELEASE). And in the docs, there's this short section regarding error-handling:
Spring Boot provides an /error mapping by default that handles all errors in a sensible way, and it is registered as a ‘global’ error page in the servlet container. For machine clients it will produce a JSON response with details of the error, the HTTP status and the exception message. For browser clients there is a ‘whitelabel’ error view that renders the same data in HTML format (to customize it just add a View that resolves to ‘error’).
So, to set my own custom page, I'd just need a view that resolves to error
. I've added Freemarker to my classpath:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
And sure enough, making a file named error.ftl
in src/main/resources/templates
did the job of getting me my own custom page.
However, instead of having error.ftl
in the resources/templates
folder, I'd like to place it inside WEB-INF/templates
.
So, I moved the file (now in WEB-INF/templates/error.ftl
) and made the following spring configuration-related beans:
@Bean(name = "freeMarkerViewResolver")
public FreeMarkerViewResolver getFreeMarkerViewResolver() {
FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver();
freeMarkerViewResolver.setSuffix(".ftl");
return freeMarkerViewResolver;
}
@Bean(name = "freemarkerConfigurer")
public FreeMarkerConfigurer getFreeMarkerConfigurer() {
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setTemplateLoaderPaths(
"classpath:/templates/",
"/WEB-INF/templates/");
return freeMarkerConfigurer;
}
But now, I only get the whitelabel page instead of /WEB-INF/templates/error.ftl
(when, let's say for example, I access an invalid path such as localhost:8080/invalid
). Is there anything I missed?
I'm pretty sure BasicErrorController
handles the job:
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
response.setStatus(getStatus(request).value());
Map<String, Object> model = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.TEXT_HTML));
return new ModelAndView("error", model);
}
And here are my logs:
2016-09-12 08:46:00.241 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Bound request context to thread: org.apache.catalina.connector.RequestFacade@11e1fd30
2016-09-12 08:46:00.241 DEBUG 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/invalid]
2016-09-12 08:46:00.242 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@75739a6e] in DispatcherServlet with name 'dispatcherServlet'
2016-09-12 08:46:00.242 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.handler.SimpleUrlHandlerMapping : No handler mapping found for [/invalid]
2016-09-12 08:46:00.242 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@67eec602] in DispatcherServlet with name 'dispatcherServlet'
2016-09-12 08:46:00.242 DEBUG 5888 --- [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /invalid
2016-09-12 08:46:00.243 DEBUG 5888 --- [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/invalid]
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@605d8da4] in DispatcherServlet with name 'dispatcherServlet'
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.h.BeanNameUrlHandlerMapping : No handler mapping found for [/invalid]
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@3fa90efa] in DispatcherServlet with name 'dispatcherServlet'
2016-09-12 08:46:00.244 DEBUG 5888 --- [nio-8080-exec-4] o.s.w.s.handler.SimpleUrlHandlerMapping : Matching patterns for request [/invalid] are [/**]
2016-09-12 08:46:00.244 DEBUG 5888 --- [nio-8080-exec-4] o.s.w.s.handler.SimpleUrlHandlerMapping : URI Template variables for request [/invalid] are {}
2016-09-12 08:46:00.244 DEBUG 5888 --- [nio-8080-exec-4] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapping [/invalid] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[ServletContext resource [/], class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@16545fd3]]] and 1 interceptor
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@5ef1fb8a]
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler adapter [org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter@781974d0]
2016-09-12 08:46:00.244 DEBUG 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/invalid] is: -1
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.r.ResourceHttpRequestHandler : Applying "invalid path" checks to path: invalid
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : Resolving resource for request path "invalid"
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : Checking location: ServletContext resource [/]
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : No match for location: ServletContext resource [/]
2016-09-12 08:46:00.244 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : Checking location: class path resource [META-INF/resources/]
2016-09-12 08:46:00.245 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : No match for location: class path resource [META-INF/resources/]
2016-09-12 08:46:00.245 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : Checking location: class path resource [resources/]
2016-09-12 08:46:00.245 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : No match for location: class path resource [resources/]
2016-09-12 08:46:00.245 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : Checking location: class path resource [static/]
2016-09-12 08:46:00.245 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : No match for location: class path resource [static/]
2016-09-12 08:46:00.245 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : Checking location: class path resource [public/]
2016-09-12 08:46:00.245 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.resource.PathResourceResolver : No match for location: class path resource [public/]
2016-09-12 08:46:00.245 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.r.ResourceHttpRequestHandler : No matching resource found - returning 404
2016-09-12 08:46:00.245 DEBUG 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2016-09-12 08:46:00.246 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@11e1fd30
2016-09-12 08:46:00.246 DEBUG 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Successfully completed request
2016-09-12 08:46:00.246 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Bound request context to thread: org.apache.catalina.core.ApplicationHttpRequest@292356a6
2016-09-12 08:46:00.246 DEBUG 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
2016-09-12 08:46:00.246 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@75739a6e] in DispatcherServlet with name 'dispatcherServlet'
2016-09-12 08:46:00.246 TRACE 5888 --- [nio-8080-exec-4] o.s.w.s.handler.SimpleUrlHandlerMapping : No handler mapping found for [/error]
2016-09-12 08:46:00.246 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@67eec602] in DispatcherServlet with name 'dispatcherServlet'
2016-09-12 08:46:00.246 DEBUG 5888 --- [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2016-09-12 08:46:00.247 TRACE 5888 --- [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Found 2 matching mapping(s) for [/error] : [{[/error],produces=[text/html]}, {[/error]}]
2016-09-12 08:46:00.248 DEBUG 5888 --- [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]
2016-09-12 08:46:00.248 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@5ef1fb8a]
2016-09-12 08:46:00.248 DEBUG 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/error] is: -1
2016-09-12 08:46:00.248 TRACE 5888 --- [nio-8080-exec-4] .w.s.m.m.a.ServletInvocableHandlerMethod : Invoking [BasicErrorController.errorHtml] method with arguments [org.apache.catalina.core.ApplicationHttpRequest@292356a6, org.apache.catalina.connector.ResponseFacade@4fa94295]
2016-09-12 08:46:00.248 TRACE 5888 --- [nio-8080-exec-4] .w.s.m.m.a.ServletInvocableHandlerMethod : Method [errorHtml] returned [ModelAndView: reference to view with name 'error'; model is {timestamp=Mon Sep 12 08:46:00 SGT 2016, status=404, error=Not Found, message=No message available, path=/invalid}]
2016-09-12 08:46:00.249 DEBUG 5888 --- [nio-8080-exec-4] o.s.w.s.v.ContentNegotiatingViewResolver : Requested media types are [text/html, text/html;q=0.8] based on Accept header types and producible media types [text/html])
2016-09-12 08:46:00.249 DEBUG 5888 --- [nio-8080-exec-4] o.s.w.s.v.ContentNegotiatingViewResolver : Returning [org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView@58edc30] based on requested media type 'text/html'
2016-09-12 08:46:00.249 DEBUG 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Rendering view [org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView@58edc30] in DispatcherServlet with name 'dispatcherServlet'
2016-09-12 08:46:00.249 TRACE 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Cleared thread-bound request context: org.apache.catalina.core.ApplicationHttpRequest@292356a6
2016-09-12 08:46:00.249 DEBUG 5888 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Successfully completed request