Spring Boot: Global exception handling

Spring Boot also provides good support for exception handling. It provides @ ControllerAdvice annotation and @ ExceptionHandler annotation. The former is used to enable global exception capture, while the latter describes which exceptions are captured and handles these captured exceptions.

Test code

Project structure diagram:

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
    </parent>

    <packaging>jar</packaging>

    <groupId>com.kaven</groupId>
    <artifactId>springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>springboot</name>
    <description>springboot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Deeplearning trainexception class (custom exception):

package com.kaven.springboot.exception;

public class DeepLearningTrainException extends RuntimeException{
    public String gpuMessage;
    public DeepLearningTrainException(String message) {
        this.gpuMessage = message;
    }
    public String addHandler(String handler) {
        return this.gpuMessage + handler;
    }
}

ResponseVO class (custom response encapsulation class):

package com.kaven.springboot.vo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Setter;

@Setter
@Builder
@AllArgsConstructor
public class ResponseVO<T> {
    public Integer code;
    public String message;
    public T data;
}

Deeplearning controller class (define interface):

package com.kaven.springboot.controller;

import com.kaven.springboot.exception.DeepLearningTrainException;
import com.kaven.springboot.vo.ResponseVO;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DeepLearningController {

    @GetMapping("/train/{gpu}")
    public ResponseVO<String> train(@PathVariable(name = "gpu") boolean gpu) {
        System.out.println("Aspect level emotion analysis model is being trained...");
        System.out.println("GPU Insufficient video memory");
        if(gpu) throw new DeepLearningTrainException("Aspect level emotion analysis model training failed, GPU Insufficient video memory");
        else System.out.println("Successful training of aspect level emotion analysis model");
        return new ResponseVO<>(HttpStatus.OK.value(), HttpStatus.OK.name(), "Successful training");
    }
}

GlobalExceptionHandler class (Global exception handling):

package com.kaven.springboot.handler.exception;

import com.kaven.springboot.exception.DeepLearningTrainException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(DeepLearningTrainException.class)
    public String DeepLearningTrainExceptionHandler(Exception e) {
        DeepLearningTrainException exception = (DeepLearningTrainException) e;
        return exception.addHandler("[DeepLearningTrainExceptionHandler]");
    }
}

@The RestControllerAdvice annotation combines the @ ControllerAdvice and @ ResponseBody annotations, so the global exception handling method can respond with JSON data.

SpringbootApplication class (startup class):

package com.kaven.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(SpringbootApplication.class);
        application.run(args);
    }
}

application.properties:

server.port=8080

The default startup port of Spring Boot application is also 8080. This is just for demonstration.

Start the application and access http://localhost:8080/train/true , the response is shown in the figure below.

Obviously, the global exception handling for the custom exception deeplearning trainexception works.

visit http://localhost:8080/train/false , the response is shown in the figure below.

404 special handling of exceptions

By default, Spring Boot will not throw 404 exceptions, so @ ControllerAdvice cannot catch 404 exceptions, such as access http://localhost:8080/kaven .

Even if the global exception handling for the exception NoHandlerFoundException is added, the 404 exception cannot be caught.

    @ExceptionHandler(NoHandlerFoundException.class)
    public String NoHandlerFoundExceptionHandler(Exception e) {
        NoHandlerFoundException exception = (NoHandlerFoundException) e;
        return exception.getMessage() + "[NoHandlerFoundException]";
    }


You can use the following configuration to make this global exception handler catch 404 exception (NoHandlerFoundException).

spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false


Obviously, the global exception handling for the exception NoHandlerFoundException works.

spring.mvc.throw-exception-if-no-handler-found=true

Throw an exception directly when 404 exception is found.

spring.web.resources.add-mappings=false

Turn off the default static resource path mapping so that 404 errors can be captured. However, this configuration will cause problems in static resource access, that is, it is not suitable for the situation where the front and back ends are not separated.

Add an interface to access static resources, IndexController class (define interface):

package com.kaven.springboot.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {

    @GetMapping("/index")
    public String index() {
        return "index";
    }
}

index.html (static resource):

Add configuration:

spring.mvc.view.suffix=.html

visit http://localhost:8080/index , also caught by global exception handling.

Add the following configuration classes to access static resources normally.

package com.kaven.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ResourceConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

Add configuration again:

spring.mvc.view.prefix=/static/

visit http://localhost:8080/index , you can normally access static resources. These configurations will be described in detail by bloggers in the future.

Other interfaces can also be requested normally.



That's all for Spring Boot global exception handling. If the blogger has something wrong or you have different opinions, you are welcome to comment and supplement.

Keywords: Java Spring Spring Boot

Added by rich11 on Thu, 03 Feb 2022 20:03:33 +0200