As you know, in XML, the way to configure this is:
404
/my-custom-page-not-fo
For Java config there is a method setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound)
in DispatcherServlet
. By settting it to true
I guess you are doing same thing
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
then you can can this NoHandlerFoundException.class
in controller advice as stated in above answer
it will be like something
public class WebXml implements WebApplicationInitializer{
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
DispatcherServlet dp = new DispatcherServlet(context);
dp.setThrowExceptionIfNoHandlerFound(true);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", dp);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(MAPPING_URL);
}
}
In your web configuration class,
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter
Declare a bean as follows,
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container)
{
ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/401.html");
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html");
container.addErrorPages(error401Page,error404Page,error500Page);
}
};
}
Add the mentioned html files(401.html
.etc) to /src/main/resources/static/
folder.
Hope this helps
A solution for Spring 5 and Thymeleaf 3.
In MyWebInitializer
, enable exception throwing with setThrowExceptionIfNoHandlerFound()
. We need to do casting to DispatcherServlet
.
@Configuration
public class MyWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
...
@Override
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
var dispatcher = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcher.setThrowExceptionIfNoHandlerFound(true);
return dispatcher;
}
}
Create a controller advice with @ControllerAdvice
and add error message to the ModealAndView
.
@ControllerAdvice
public class ControllerAdvisor {
@ExceptionHandler(NoHandlerFoundException.class)
public ModelAndView handle(Exception ex) {
var mv = new ModelAndView();
mv.addObject("message", ex.getMessage());
mv.setViewName("error/404");
return mv;
}
}
Create 404 error template, which displays the error message. Based on my configuration, the file is src/main/resources/templates/error/404.html
.
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Resource not found</title>
</head>
<body>
<h2>404 - resource not found</h2>
<p>
<span th:text="${message}" th:remove="tag"></span>
</p>
</body>
</html>
For completeness, I add the Thymeleaf resolver configuration. We configure the Thymeleaf templates to be in templates
directory on the classpath.
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {
@Autowired
private ApplicationContext applicationContext;
...
@Bean
public SpringResourceTemplateResolver templateResolver() {
var templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
return templateResolver;
}
...
}
The most clean solution since spring 4.2 RC3 is using the new createDispatcherServlet
hook within the class extending AbstractDispatcherServletInitializer
(or indirectly through extending AbstractAnnotationConfigDispatcherServletInitializer
) like this:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
/* ... */
@Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
final DispatcherServlet dispatcherServlet = super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
}
Then you can use a global @ControllerAdvice
(a class that is annotated with @ControllerAdvice
) as described in the reference docs. Within the advice you can handle the NoHandlerFoundException
with an @ExceptionHandler
as described here.
This could look something like this:
@ControllerAdvice
public class NoHandlerFoundControllerAdvice {
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<String> handleNoHandlerFoundException(NoHandlerFoundException ex) {
// prepare responseEntity
return responseEntity;
}
}
In springboot it is even simplier. Because of Spring autoconfiguration stuff, spring creates a bean org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties
. This class is annotated with @ConfigurationProperties(prefix = "spring.mvc")
and therefore it will seek for properties with spring.mvc prefix.
Part from javadoc:
Annotation for externalized configuration. Add this to a class definition or a
* @Bean method in a @Configuration class if you want to bind and validate
* some external Properties (e.g. from a .properties file).
You just have to add to your i.e. application.properties
file following properties:
spring.mvc.throwExceptionIfNoHandlerFound=true
spring.resources.add-mappings=false //this is for spring so it won't return default handler for resources that not exist
and add exception resolver as follows:
@ControllerAdvice
public class ExceptionResponseStatusHandler {
@ExceptionHandler(NoHandlerFoundException.class)
public ModelAndView handle404() {
var out = new ModelAndView();
out.setViewName("404");//you must have view named i.e. 404.html
return out;
}
}
In Spring Framework, there are number of ways of handing exceptions (and particularly 404 error). Here is a documentation link.
error-page
tag in web.xml, and customize error page. Here is an example.Second, you can use one @ExceptionHandler
for all controllers, like this:
@ControllerAdvice
public class ControllerAdvisor {
@ExceptionHandler(NoHandlerFoundException.class)
public String handle(Exception ex) {
return "404";//this is view name
}
}
For this to work, set throwExceptionIfNoHandlerFound property to true for DispatcherServlet
in web.xml:
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
You can also pass some objects to error view, see javadoc for this.