8

I want to handle 404 page not found exception in my Spring MVC web app, I'm using SPRING 4.2.5.RELEASE, I had read several question regarding this topic but the similar questions are using a different spring java configuration.

I have a Global Exception Handler Controller class that have all my Exceptions, this class works fine but I can't handle a 404 page not found exception.

This is the approach that I take following a tutorial

1) I created a class named ResourceNotFoundException that extends from RuntimeException and I putted this annotation over the class definition @ResponseStatus(HttpStatus.NOT_FOUND)

like this:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException { 

}

2) I created this method in my exception's controller class

@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handleResourceNotFoundException() {

    return "notFoundJSPPage";
}

But still when I put a URL that doesn't exist I get this error "No mapping found for HTTP request with URI"

The questions that I had read said that I need to enable to true an option for the Dispatcher but since my configuration it's different from the other questions and I don't have a Web.xml I couldn't apply that.

Here it's my Config.java

@EnableWebMvc
@Configuration
@ComponentScan({"config", "controllers"})
public class ConfigMVC extends WebMvcConfigurerAdapter {

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

    @Bean
    public UrlBasedViewResolver setupViewResolver() {
        UrlBasedViewResolver resolver = new UrlBasedViewResolver();
        resolver.setPrefix("/WEB-INF/jsp/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(JstlView.class);
        return resolver;
    }

}

Here is my WebInitializer

public class WebInicializar implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(ConfigMVC.class);
        ctx.setServletContext(servletContext);
        Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);


    }
}

Here is my Global Exception Handler Controller

@ControllerAdvice
public class GlobalExceptionHandlerController {


    @ExceptionHandler(value = NullPointerException.class)
    public String handleNullPointerException(Exception e) {

        System.out.println("A null pointer exception ocurred " + e);

        return "nullpointerExceptionPage";
    }


    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public String handleAllException(Exception e) {

        System.out.println("A unknow Exception Ocurred: " + e);

        return "unknowExceptionPage";
    }


    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public String handleResourceNotFoundException() {

        return "notFoundJSPPage";
    }

}

And the class I created that extends Runtime Exception

@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException{

}
StackQuestion
  • 483
  • 2
  • 7
  • 20

4 Answers4

9

I solved the problem by putting this line in my onStartup method in the WebApplicationInitializer.class

this it's the line I add servlet.setInitParameter("throwExceptionIfNoHandlerFound", "true");

this is how it looks the complete method with the new line I added

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    ctx.register(ConfigMVC.class);
    ctx.setServletContext(servletContext);
    Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
    servlet.addMapping("/");
    servlet.setLoadOnStartup(1);
    servlet.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}

Then I created this controller method in my GlobalExceptionHandlerController.class

@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handle(NoHandlerFoundException ex) {

  return "my404Page";
}

and that solved my problem I deleted the handleResourceNotFoundException controller method in my GlobalExceptionHandlerController.class since it wasn't necessary and also I deleted the exception class ResourceNotFoundException.class that I created

StackQuestion
  • 483
  • 2
  • 7
  • 20
  • This should work, but the current best practices (as of Spring 4.2.3) are described in [this answer](http://stackoverflow.com/a/31436535/2074605). – Parker Nov 12 '16 at 12:30
  • @vallismortis The current best practice is to extend AbstractAnnotationConfigDispatcherServletInitializer ? Ho-hum. – Julian Go Jan 10 '17 at 21:38
2

You can also extend AbstractAnnotationConfigDispatcherServletInitializer and override this method:

@Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
    final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
    return dispatcherServlet;
}

OR this one:

@Override
public void customizeRegistration(ServletRegistration.Dynamic registration) {
    registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}

And finally in your ControlerAdvice use this:

@ExceptionHandler(NoHandlerFoundException.class)
public String error404(Exception ex) {

    return new ModelAndView("404");
}
zygimantus
  • 3,649
  • 4
  • 39
  • 54
1

Add following code in any controller and create a 404 page

@GetMapping("/*")
public String handle() {
    return "404";
}
Deepu
  • 83
  • 9
0

I found that the answer by zygimantus didnt work for some reason, so if you also have the same problem , then instead of declaring an "@ExceptionHandler", add one of these to a "@Configuration" class instead. I put mine in my WebMvcConfigurerAdapter

@Bean
  public HandlerExceptionResolver handlerExceptionResolver(){
      HandlerExceptionResolver myResolver = new HandlerExceptionResolver(){

        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
              //return your 404 page
            ModelAndView mav = new ModelAndView("404page");
            mav.addObject("error", exception);
            return mav;
        }
      };
      return myResolver;
  }

But make sure you also follow the rest of zygimantus ie

dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
cgull
  • 47
  • 4