For when we develop spring web application such as IOException, ClassNotFoundException checked exceptions, such as the compiler will be prompted to programmers often use try-catch explicitly capture, For like a ClassCastException, NullPointerException such a checked exception, the compiler is not prompt you for a long time, this is often reflects one aspect of the ability of programmers write code.

In Spring Web and especially in Spring-Boot applications, when a request is successfully invoked, it will generally return a JSON object, as shown in the figure below:

But what if the request throws a RuntimeException? If we don’t do anything, the following page will appear when we call it again:

In other words, when an error occurs, spring-boot maps the request to the /error path by default, and returns the Whitelabel error page above if there is no path request handler.

1. Customize the error handling page

Of course it’s impossible not to handle runtime exceptions! The usual approach is to customize the uniform error page and return it. We implement a controller whose request path is /error. The controller returns a resource path address. We define a controller whose request map path is /error and implement the ErrorController interface.

MyErrorPageController

package com.example.demo.controller.handler.errorpage; import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** ** The class MyErrorPageController. ** Description: Custom error page ** @author: huangjiawei * @since: June 13, 2018 * @version:$Revision$ $Date$ $LastChangedBy$
 *
 */
@Controller
public class MyErrorPageController implements ErrorController {
    
    @RequestMapping("/error")
    public String handleError() {
    	return "error.html"; } @override public String; // The resource is in the resources/static directory} @override public StringgetErrorPath() {
    	returnnull; }}Copy the code

Then create an error-html file in the reosurces/static directory:

<! DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1> </h1> </body> </ HTML >Copy the code

Request http://localhost:7000/demo/getUserInfoWithNoHandler.json again, as follows:

2, use,@ControllerAdvice,@ResponseBody,@ExceptionHandlerUnified handling exceptions

By default, we can define a unified handler for certain types of exceptions in the system, such as a NullPointerException thrown by the system. So we can define a NullPointerException handler with the following code:

GetUserInfoWithNullPointerException interface

/** * test for null pointer error handling * @return
 * @throws NullPointerException
 */
@RequestMapping(value = "getUserInfoWithNullPointerException.json". method = RequestMethod.GET) public Student getUserInfoWithNullPointerException() throws NullPointerException { throw new  NullPointerException(); }Copy the code

NullPointerExceptionHandler.java

package com.example.demo.controller.handler; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.example.demo.pojo.ErrorReturn; / * * * * The class NullPointerExceptionHandler. * * Description: handle null pointer @ author: * * * @ huangjiawei since: June 13, 2018 * @version:$Revision$ $Date$ $LastChangedBy$
 *
 */
@ControllerAdvice
public class NullPointerExceptionHandler {
    @ExceptionHandler(NullPointerException.class)
    @ResponseBody
    public ErrorReturn dealNullPointerException() {
        e.printStackTrace();
    	ErrorReturn error = new ErrorReturn();
    	error.setReturnCode("1");
    	error.setDesc("Null pointer exception!");
    	returnerror; }}Copy the code

Browser: http://localhost:7000/demo/getUserInfoWithNullPointerException.json

In the same way, if we also need a uniform processor for other runtime exceptions, we can define a processor for each exception type as we did above. For example, if we want to define a processor for the ArithmeticException, we can just create a class or method. Then add ArithmeticException at the @ ExceptionHanler annotation on the method. The class specifies the exception type.

However, did you find that there is one exception class or method for each exception type? Because there are so many exception types at runtime, it is impossible to specify one handler class or method for each type. Spring can also solve this problem. If we don’t define a processor for a particular type of Exception, such as ArithmeticException, we can define an Exception or Throwable processor for unified handling.

This has the advantage of reducing the number of handler classes and moving exception handling to the parent class, which is also a big advantage of inheritance. But, when you define A specific type of both Exception, defines the processor Exception Exception again at the same time, so be careful, there may not have priority relationship, that is not necessarily will be executed only Exception handler, the father may be executed only A processor, and not B processor or only B processor, does not perform A processor. Such as the abnormal NullPointerExceptionHandler to Exception Exception passed ArithmeticException (but not to the Exception)

Now suppose we defined above NullPointerExceptionHandler, Defines the following ExceptionThrowableHandler again, so when a NullPointerException, will be the default execution ExceptionThrowableHandler method.

ExceptionThrowableHandler.java

package com.example.demo.controller.handler; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.example.demo.pojo.ErrorReturn; / * * * * The class ExceptionThrowableHandler. * * Description: some exceptions to The high level abnormal transfer (but not ArithmeticException to Exception) * * @author: Huangjiawei * @since: 2018 June 13 * @version:$Revision$ $Date$ $LastChangedBy$
 *
 */
@ControllerAdvice
public class ExceptionThrowableHandler {
    
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public ErrorReturn dealThrowable() {
    	ErrorReturn error = new ErrorReturn();
    	error.setDesc("Handling Throwable!");
    	error.setReturnCode("1");
    	return error;
    }
    
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ErrorReturn dealCommonException() {
    	ErrorReturn error = new ErrorReturn();
    	error.setReturnCode("1");
    	error.setDesc("Public exception handling!");
    	returnerror; }}Copy the code

Browser: http://localhost:7000/demo/getUserInfoWithNullPointerException.json

You can see that a handler that only executes exceptions, and a handler that does not execute null Pointers, means that Exception handling is passed up. Let’s look at the ArithmeticException thrown:

getUserInfoWithArithmeticException.json

/** * Test ArithmeticException error handling * @return
 * @throws ArithmeticException
 */
@RequestMapping(value = "getUserInfoWithArithmeticException.json". method = RequestMethod.GET) public Student getUserInfoWithArithmeticException() throws ArithmeticException { throw new ArithmeticException(); }Copy the code

ArithmeticExceptionHandler.java

package com.example.demo.controller.handler; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.example.demo.pojo.ErrorReturn; @ ControllerAdvice public class ArithmeticExceptionHandler {ArithmeticException exception handling / * * * * @return
     */
    @ResponseBody
    @ExceptionHandler(ArithmeticException.class)
    public ErrorReturn dealArithmeticException() {
    	ErrorReturn errorObject = new ErrorReturn();
    	errorObject.setReturnCode("1");
    	errorObject.setDesc("Arithmetic processing exception!");
    	returnerrorObject; }}Copy the code

Browser: http://localhost:7000/demo/getUserInfoWithArithmeticException.json

It is found that the ExceptionHandler is not passed to the upper layer ExceptionHandler.

Conclusion: Be careful when defining both a handler of a particular type and a parent type such as Exception. Not all exceptions are handled at the upper level. If we want to reduce the number of handler classes only and don’t want to add classes or methods for each handler of a particular type, Use the instanceof keyword to determine the exception type.

In the following code, we just create a common Exception handler that handles exceptions and uses Instanceof for judgment.

@ExceptionHandler(Exception.class) @ResponseBody public ErrorReturn dealCommonException(Exception e) { ErrorReturn error  = new ErrorReturn(); // Use instanceof to determine the exception typeif (e instanceof ArithmeticException) {
    	error.setReturnCode("1");
    	error.setDesc("Arithmetic exception handling!");
    	return error;
    }
    System.err.println("exception");
    error.setReturnCode("1");
    error.setDesc("Public exception handling!");
    return error;
}
Copy the code

The browser executes an interface that throws ArithmeticException, as follows:

This article code address: github.com/SmallerCode…

Thanks for reading!