Controller based error pages spring thymeleaf

2020-07-25 10:24发布

问题:

I've managed to build static error pages and redirect to them with this bean:

    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {

        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                if (optiuniEnvironment.equals("development")) {
                    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, "/404.html");

                    container.addErrorPages(error401Page, error404Page, error500Page);
                }
            }
        };
    }

However, now I want to build a custom page, that uses the functionality of the controller.

So in my controller I have something like

    @RequestMapping("/404.html")
    String pageNotFound(Model model, HttpServletRequest request)
    {
        return "404";
    }

and wish to redirect to it if I encounter the HttpStatus 404.

I believe the answer is configuring the DispatcherServlet, but not sure. Any ideas? Thanks!

(if possible, please use java-based configurations, not xml)

回答1:

You can handle these error using following methods:

1. Using Exception Handler method in same controller:

@ExceptionHandler(NoHandlerFoundException.class)
public String handle404Exception(NoHandlerFoundExceptionex) {
     //do whatever you want
     return "viewName";
}

2. Create Exception controller

@ControllerAdvice
public class ExceptionController {

    @ExceptionHandler(NoHandlerFoundException.class)
    public String handle404Exception(NoHandlerFoundExceptionex) {
         //do whatever you want
         return "viewName";
    }
}

If using Spring Boot, set following properties in application.properties

server.error.whitelabel.enabled=false
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

3. Adding Error Page Registrar:

@Bean
public ErrorPageRegistrar errorPageRegistrar(){
    return new CustomErrorPageRegistrar();
}

private static class CustomErrorPageRegistrar implements ErrorPageRegistrar {

    // Register your error pages and url paths.
    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
    }

}

and define your controller endpoint for respective urls (eg. /400)



回答2:

Solution for SpringBoot version: 1.2 - even if not the best - it's good enough for now.

Created a GlobalErrorController

@RestController
@Profile("prod")
public class GlobalErrorController implements ErrorController {

    private static final String PATH = "/error";

    @RequestMapping(value = PATH)
    public void error(HttpServletResponse response) throws IOException {
        int status = response.getStatus();
        switch (status) {
            case 404:
                response.sendRedirect("/404");
                break;
            case 401:
                response.sendRedirect("/401");
                break;
            case 403:
                response.sendRedirect("/401");
                break;
            default:
                response.sendRedirect("/404");
        }

    }

    @Override
    public String getErrorPath() {
        return PATH;
    }
}

And in my HomeController I added:

@RequestMapping("404")
String get404ErrorPage() {
    return "404";
}

@RequestMapping("401")
String get401ErrorPage() {
    return "401";
}

I chose this approach because I need in the error pages some functionality from the controller.

Other solutions are more than welcome!