In the Spring Boot project, exceptions are handled uniformly. You can use @ControllerAdvice in Spring to handle exceptions uniformly, or you can define your own exception handling scheme. Spring Boot has some default policies for exception handling, which we’ll look at separately.

By default, the exception page in Spring Boot looks like this:

We can also see from this exception that the user is seeing this page because the developer did not explicitly provide a /error path. If the developer had provided a /error path, the page would not be displayed. Providing the /error path is actually the last resort, and Spring Boot itself will only look for the /error path when all conditions are not met when handling exceptions. So let’s take a look at how to customize error pages in Spring Boot. Generally speaking, there are two types, one is static page, the other is dynamic page.

Static exception page

Custom static exception page is divided into two types. The first type is to use HTTP response code to name the page, such as 404.html, 405.html, 500.html…. , the other is to directly define a 4xx. HTML, indicating that 400-499 states will display the exception page, 5xx. HTML, indicating that 500-599 states will display the exception page.

The default is to define the relevant page in the classpath:/static/error/ path:

At this point, the project is launched, and if the project throws a 500 request error, the 500.html page will be displayed automatically, and if 404 occurs, the 404.html page will be displayed. If the exception display page contains both 5xx. HTML and 500. HTML, the 500. HTML page is displayed first when a 500 exception occurs.

Dynamic exception page

Dynamic exception pages are defined in much the same way as static ones, with page templates such as JSP, Freemarker, and Thymeleaf. Dynamic exception pages can also support 404.html or 4xx.html, but in general, because dynamic exception pages can display exception details directly, there is no need to enumerate errors one by one. Just define 4xx.html (using the Thymeleaf template here) or 5xx.html.

Note that the dynamic page template does not require the developer to define the controller, but directly define the abnormal page. Spring Boot’s own exception processor will automatically find the abnormal page.

The page definition is as follows:

The page reads as follows:


      
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>5xx</h1>
<table border="1">
    <tr>
        <td>path</td>
        <td th:text="${path}"></td>
    </tr>
    <tr>
        <td>error</td>
        <td th:text="${error}"></td>
    </tr>
    <tr>
        <td>message</td>
        <td th:text="${message}"></td>
    </tr>
    <tr>
        <td>timestamp</td>
        <td th:text="${timestamp}"></td>
    </tr>
    <tr>
        <td>status</td>
        <td th:text="${status}"></td>
    </tr>
</table>
</body>
</html>
Copy the code

By default, the complete exception information is displayed as follows:

If dynamic pages and static page defines the exception handling page at the same time, such as the classpath: / static/error / 404 HTML and classpath: / templates/error / 404 HTML exist at the same time, using dynamic pages by default. A complete error page lookup would look like this:

A 500 error occurred –> Find dynamic 500.html page –> find static 500.html –> Find dynamic 5xx.html–> find static 5xx.html.

Custom exception data

By default, all exception data in Spring Boot is actually the five pieces of data shown above, This article 5 data definition in org. Springframework. Boot. Web. Reactive. Error. DefaultErrorAttributes class, specific definition in getErrorAttributes approach:

@Override
public Map<String, Object> getErrorAttributes(ServerRequest request,
                boolean includeStackTrace) {
        Map<String, Object> errorAttributes = new LinkedHashMap<>();
        errorAttributes.put("timestamp".new Date());
        errorAttributes.put("path", request.path());
        Throwable error = getError(request);
        HttpStatus errorStatus = determineHttpStatus(error);
        errorAttributes.put("status", errorStatus.value());
        errorAttributes.put("error", errorStatus.getReasonPhrase());
        errorAttributes.put("message", determineMessage(error));
        handleException(errorAttributes, determineException(error), includeStackTrace);
        return errorAttributes;
}
Copy the code

DefaultErrorAttributes class itself is in the org. Springframework. Boot. The autoconfigure. Web. Servlet. Error. ErrorMvcAutoConfiguration Defined in the Exception Auto-configuration class, Spring Boot automatically provides an instance of ErrorAttributes, which is TerrorAttributes, if the developer does not provide an instance of ErrorAttributes themselves.

Based on this, developers can customize ErrorAttributes in two ways:

  1. Directly implement the ErrorAttributes interface
  2. Inherit TerrorAttributes (recommended) because the handling of exception data in TerrorAttributes is done and developers can use it directly.

Specific definitions are as follows:

@Component
public class MyErrorAttributes  extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
        if ((Integer)map.get("status") = =500) {
            map.put("message"."Server internal error!);
        }
        returnmap; }}Copy the code

ErrorAttributes must be registered as a Bean so that Spring Boot does not use the default TerrorAttributes, which looks like this:

Custom exception view

The default exception view is the static or dynamic page described above. This can also be customized. First of all, Abnormal loading logic view by default in org. Springframework. Boot. Autoconfigure. Web. Servlet. Error. BasicErrorController errorHtml method of class, This method is used to return the exception page + data, and there is another error method, which is used to return the exception data (which is triggered if it is an Ajax request).

@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
                        request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        return(modelAndView ! =null)? modelAndView :new ModelAndView("error", model);
}
Copy the code

In this method, we first get the exception data through the getErrorAttributes method (which actually calls the getErrorAttributes method of the ErrorAttributes instance), Then call resolveErrorView to create a ModelAndView. If this fails, the user will be presented with a default error page.

Normally, the resolveErrorView method would come to the resolveErrorView method of the DefaultErrorViewResolver class:

@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map
       
         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;
}
Copy the code

In this case, the exception response code is used as the view name to search for dynamic and static pages respectively. If none is found, 4xx or 5xx is used as the view name to search for dynamic or static pages respectively.

To custom exception view resolution, is also very easy, because DefaultErrorViewResolver is ErrorMvcAutoConfiguration class provides the instance, the developer does not provide relevant instances, The DefaultErrorViewResolver is used. The default configuration fails when developers provide their own ErrorViewResolver instance, so customising an exception view simply requires providing an instance of ErrorViewResolver:

@Component
public class MyErrorViewResolver extends DefaultErrorViewResolver {
    public MyErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) {
        super(applicationContext, resourceProperties);
    }
    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        return new ModelAndView("/aaa/123", model); }}Copy the code

In fact, the developer can also define the exception data here (directly in the resolveErrorView method to redefine a model, copy the model data in the parameter and modify it, note that the model type in the parameter is UnmodifiableMap, That is, it cannot be modified directly) without customizing MyErrorAttributes. After the definition is complete, provide a view named 123 as shown below:

After that, the false attempt is defined as successful.

conclusion

We could actually customize the exception controller BasicErrorController, but Songo felt that would be too much work and that the previous methods would suffice for most of our development needs.

Pay attention to the public account [Jiangnan little Rain], focus on Spring Boot+ micro service and front and back end separation and other full stack technology, regular video tutorial sharing, after attention to reply to Java, get Songko for you carefully prepared Java dry goods!