Mastering Spring Boot Error Handling and Custom Error Pages

This article explains how Spring Boot's default /error mapping works, how to customize error responses with ErrorController, ErrorAttributes, @ControllerAdvice, custom HTML pages, ErrorViewResolver, ErrorPageRegistrar, and how to configure CORS globally or per controller.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Spring Boot Error Handling and Custom Error Pages

Error Handling

By default Spring Boot registers a global /error mapping that returns JSON for API clients and a whitelabel HTML page for browsers. The behavior can be customized via server.error properties, by implementing ErrorController, or by providing a bean of type ErrorAttributes.

A @ControllerAdvice class can be used to return custom JSON for specific exceptions, as shown in the example code.

@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {
    @ExceptionHandler(YourException.class)
    @ResponseBody
    ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
        HttpStatus status = getStatus(request);
        return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
    }
    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }
}

Custom Error Pages

Static HTML files placed under /error with the exact status code (e.g., 404.html) are used as custom error pages. Templates can also be used. For more complex scenarios, implement an ErrorViewResolver bean.

public class MyErrorViewResolver implements ErrorViewResolver {
    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        // Use the request or status to optionally return a ModelAndView
        return ...;
    }
}

The default DefaultErrorViewResolver searches for error views in classpath locations such as classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, and classpath:/public/.

public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
    private static final Map<Series, String> SERIES_VIEWS;
    static {
        Map<Series, String> views = new EnumMap<>(Series.class);
        views.put(Series.CLIENT_ERROR, "4xx");
        views.put(Series.SERVER_ERROR, "5xx");
        SERIES_VIEWS = Collections.unmodifiableMap(views);
    }
    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
        if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
            modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
        }
        return modelAndView;
    }
    private ModelAndView resolve(String viewName, Map<String, Object> model) {
        String errorViewName = "error/" + viewName;
        return resolveResource(errorViewName, model);
    }
    private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
        for (String location : this.resources.getStaticLocations()) {
            try {
                Resource resource = this.applicationContext.getResource(location);
                resource = resource.createRelative(viewName + ".html");
                if (resource.exists()) {
                    return new ModelAndView(new HtmlResourceView(resource), model);
                }
            } catch (Exception ignored) {}
        }
        return null;
    }
}

Mapping Errors Outside Spring MVC

Applications that do not use Spring MVC can register ErrorPage objects via the ErrorPageRegistrar interface, which works directly with the embedded servlet container.

@Bean
public ErrorPageRegistrar errorPageRegistrar() {
    return new MyErrorPageRegistrar();
}
private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
    }
}

CORS Support

Since Spring MVC 4.2, CORS can be enabled with @CrossOrigin on controller methods or globally by defining a WebMvcConfigurer bean that overrides addCorsMappings.

@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**");
            }
        };
    }
}

Images illustrate directory structures and configuration examples.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaSpring BootCORSError handlingCustom Error Page
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.