3
votes

I have simple Spring MVC application where I want to hande 404 Not found exceptions in my Advice Controller class

Configuration:

   public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {


    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{WebConfig.class};
    }


    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{RootConfig.class, SecurityConfig.class};
    }


    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }


    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        servletContext.addListener(new SessionListener());
        FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
        encodingFilter.setInitParameter("encoding", "UTF-8");
        encodingFilter.setInitParameter("forceEncoding", "true");
        encodingFilter.addMappingForUrlPatterns(null, true, "/*");
    }
}

Controller:

@Controller
@RequestMapping("/")
public class HomeController {
 @RequestMapping(value = "/error/", method = RequestMethod.GET)
    public String error(){return "error";}
}

ControllerAdvice:

@ControllerAdvice
public class AdviceController {

    @ExceptionHandler(MyOwnException.class)
    @ResponseStatus(value= HttpStatus.BAD_REQUEST)
    public String checkoutException(CheckoutException e, HttpServletRequest httpServletRequest)   {
                return "error";
    }
}

I can catch my own exceptions when I manually throw MyOwnException but I can't get how to catch NoHandlerFound exception. I need to send 404 error code and appropriate error.jsp page when there is no controller method to handle request

1

1 Answers

4
votes

If your webapp is using web.xml it's very simple - just add the following (assuming usage of InternalResourceViewResolver with prefix pointing at your WEB-INF view folder and suffix .jsp). You can have multiple error-page elements of other error codes too.

<error-page>
    <error-code>404</error-code>
    <location>/error</location>
</error-page>

If you are not using web.xml it's more complicated and you'll have to define and register your own ExceptionResolver. Take a look at this spring.io blog article for details on how to do this.


(Edit after comment)

If you want to catch the NoHandlerFound exception you first have to tell Spring to throw it via setting a flag in the DispatcherServlet directly. To do so, in your AppInitializer class add the DispatcherServlet definition on top of what you are currently doing to add the flag:

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    super.onStartup(servletContext);
    servletContext.addListener(new SessionListener());
    //BEGIN OF NEW CODE
    WebApplicationContext context = getContext();
    DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
    //we did all this to set the below flag
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet",dispatcherServlet );
    //END OF NEW CODE
    FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
    encodingFilter.setInitParameter("encoding", "UTF-8");
    encodingFilter.setInitParameter("forceEncoding", "true");
    encodingFilter.addMappingForUrlPatterns(null, true, "/*");
}

Then you can catch the NoHandlerFound exception directly in your AdviceController:

@ControllerAdvice
public class AdviceController {
    //..
    @ExceptionHandler(NoHandlerFoundException.class)
    public String dealWithNoHandlerFoundException(CheckoutException e, HttpServletRequest httpServletRequest)   {
                return "error";
    }
}