Global exception handling in SpringBook series of tutorials

Keywords: Programming Spring Java SpringBoot Maven

When there are exceptions in our back-end application, we usually wrap the exceptions and return them to the caller or the front-end. In the actual project, it is impossible to handle exceptions everywhere, and then elegant code may throw exceptions. So how can we handle these exceptions gracefully in Spring project?

This article will introduce a global exception handling method, mainly including the following knowledge points

  • @ Controller Advice Controller Enhancement
  • @ Exception Handler exception capture
  • @ ResponseStatus return status code
  • NoHandler FoundException Processing (404 exception capture)

Right-click to view the original text: Global exception handling in SpringBook series of tutorials

<!-- more -->

I. Environmental Construction

First, we need to build a web application in order to continue the follow-up testing. It is relatively simple to build a web application with SpringBook.

Create a maven project with the following pom file

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.7</version>
    <relativePath/> <!-- lookup parent from update -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.45</version>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

It's still a normal process. After the pom dependencies are settled, write a program entry

/**
 * Created by @author yihui in 15:26 19/9/13.
 */
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

II. Exception handling

1. @ControllerAdvice

We usually use @Controller Advice with annotation @ExceptionHandler to achieve global exception capture processing.

  • @ Controller Advice weaves enhancements for all Controllers
  • @ The ExceptionHandler tag in the method indicates that when a corresponding exception is thrown to the upper layer (that is, it is not caught by the business), the method will be triggered.

Next, we demonstrate the functionality through an example.

a. Exception capture

We define two exception capture case s, one is divided by 0, and the other is array crossover exception.

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    public static String getThrowableStackInfo(Throwable e) {
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        e.printStackTrace(new java.io.PrintWriter(buf, true));
        String msg = buf.toString();
        try {
            buf.close();
        } catch (Exception t) {
            return e.getMessage();
        }
        return msg;
    }

    @ResponseBody
    @ExceptionHandler(value = ArithmeticException.class)
    public String handleArithmetic(HttpServletRequest request, HttpServletResponse response, ArithmeticException e)
            throws IOException {
        log.info("divide error!");
        return "divide 0: " + getThrowableStackInfo(e);
    }

    @ResponseBody
    @ExceptionHandler(value = ArrayIndexOutOfBoundsException.class)
    public String handleArrayIndexOutBounds(HttpServletRequest request, HttpServletResponse response,
            ArrayIndexOutOfBoundsException e) throws IOException {
        log.info("array index out error!");
        return "aryIndexOutOfBounds: " + getThrowableStackInfo(e);
    }
}

In the above test, we returned the exception stack to the caller

b. Example services

Add several test methods

@Controller
@RequestMapping(path = "page")
public class ErrorPageRest {

    @ResponseBody
    @GetMapping(path = "divide")
    public int divide(int sub) {
        return 1000 / sub;
    }

    private int[] ans = new int[]{1, 2, 3, 4};

    @ResponseBody
    @GetMapping(path = "ary")
    public int ary(int index) {
        return ans[index];
    }
}

c. Test instructions

Examples are tested as follows. Above, we declare that the two exceptions captured are intercepted and the corresponding stack information is output.

But it's worth noting.

  • SpringBoot default error pages are displayed for 404 and 500 uncovered exceptions.
  • In addition, the http status code we captured and returned is 200

2. @ResponseStatus

The status code returned by the exception captured in the case above is 200, but in some cases, it may be preferable to return a more appropriate http status code, which can be specified using ResponseStatus.

It's easy to use, just add a comment.

@ResponseBody
@ExceptionHandler(value = ArithmeticException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleArithmetic(HttpServletRequest request, HttpServletResponse response, ArithmeticException e)
        throws IOException {
    log.info("divide error!");
    return "divide 0: " + getThrowableStackInfo(e);
}

3. 404 treatment

With @Controller Advice and @ExceptionHandler, 500 exceptions can be intercepted. What can I do if I want 404 exceptions to be intercepted as well?

First, modify the configuration file application.properties to throw out NoHandler FoundException

# When an error occurs, throw an exception directly
spring.mvc.throw-exception-if-no-handler-found=true
# Set the static resource mapping access path, and choose one of the following two options.
spring.mvc.static-path-pattern=/statics/**
# spring.resources.add-mappings=false

Next is the definition of exception capture

@ResponseBody
@ExceptionHandler(value = NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handleNoHandlerError(NoHandlerFoundException e, HttpServletResponse response) {
    return "noHandlerFound: " + getThrowableStackInfo(e);
}

Test again as follows, 404 was captured by us and returned to the stack information.

II. other

0. project

web series blog posts

Project source code

1. Grey Blog

Letters are not as good as letters. The above contents are purely family statements. Due to limited personal abilities, there are inevitably omissions and errors. If you find bug s or have better suggestions, you are welcome to criticize and correct them. Thank you very much.

Below is a grey personal blog, which records all the blogs about study and work. Welcome to visit it.

Posted by Gayner on Fri, 11 Oct 2019 03:54:20 -0700