Mastering Global Exception Handling in Spring MVC with @RestControllerAdvice

This guide explains how Spring MVC's @ControllerAdvice, @RestControllerAdvice, and @ExceptionHandler annotations enable both local and global exception handling, including selective handling by custom annotations, specific controllers, or packages, with practical code examples for Java developers.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Global Exception Handling in Spring MVC with @RestControllerAdvice

Environment: Spring 5.3.23

1. Introduction

Spring MVC provides a flexible exception‑handling mechanism based on the @ControllerAdvice and @ExceptionHandler annotations. @ControllerAdvice defines a global exception‑handling class, while @ExceptionHandler specifies the exception types to handle. In RESTful projects the preferred annotation is @RestControllerAdvice, which combines @ControllerAdvice with @ResponseBody so that returned objects are automatically serialized to JSON.

2. Application Cases

Controller‑level Exception Handling

@RestController
public class TestController {
  @GetMapping("/test/{id}")
  public Object test(@PathVariable Integer id) {
    if (id < 5) {
      throw new RuntimeException("运行时异常");
    }
    return "测试异常处理";
  }

  @ExceptionHandler
  public Object handle(Exception e) {
    return e.getMessage();
  }
}

This method handles exceptions only for the TestController. It is convenient for a single controller but becomes cumbersome when many controllers exist.

Global Exception Handling

@RestControllerAdvice
public class TestControllerAdvice {
  @ExceptionHandler
  public Object handle(Exception e) {
    return "我是全局异常:" + e.getMessage();
  }
}

The global handler works when the controller does not define its own @ExceptionHandler. Local handlers have higher priority than global ones.

Handling Only Specific Annotations

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AppAnnotation {}

Controllers annotated with @AppAnnotation:

@AppAnnotation
@RestController
public class AnnotationController {
  @GetMapping("/an/get/{id}")
  public Object an(@PathVariable Integer id) {
    if (id < 10) {
      throw new RuntimeException("发生错误了");
    }
    return "自定义Annotation注解: " + id;
  }
}

Controllers without the annotation:

@RestController
public class AnnotationController2 {
  @GetMapping("/an/get2/{id}")
  public Object an(@PathVariable Integer id) {
    if (id < 10) {
      throw new RuntimeException("2发生错误了");
    }
    return "自定义Annotation注解2: " + id;
  }
}
@RestControllerAdvice(annotations = {AppAnnotation.class})
public class AnnotationControllerAdvice {
  @ExceptionHandler
  public Object handle(Exception e) {
    return "特定注解全局异常:" + e.getMessage();
  }
}

Only the controller with @AppAnnotation is intercepted by the advice.

Handling Specific Controllers

@RestController
public class UserController {
  @GetMapping("/user/{id}")
  public Object get(@PathVariable Integer id) {
    if (id < 10) {
      throw new RuntimeException("用户ID错误");
    }
    return "Users";
  }
}
@RestController
public class PersonController {
  @GetMapping("/person/{id}")
  public Object get(@PathVariable Integer id) {
    if (id < 10) {
      throw new RuntimeException("Person ID错误");
    }
    return "Person";
  }
}
@RestControllerAdvice(assignableTypes = {UserController.class})
public class SpecificControllerAdvice {
  @ExceptionHandler
  public Object handle(Exception e) {
    return "指定Controller全局异常:" + e.getMessage();
  }
}

The advice applies only to UserController; exceptions from PersonController are not handled.

Handling Controllers in Specific Packages

@RestControllerAdvice(basePackages = {"com.pack.pkg1"})
public class PackageControllerAdvice {
  @ExceptionHandler
  public Object handle(Exception e) {
    return "指定包下的全局异常:" + e.getMessage();
  }
}

When a controller in com.pack.pkg1 throws an exception, the advice handles it; controllers in other packages are unaffected.

Conclusion: Local (controller‑level) exception handling takes precedence over global exception handling.

Additional reference images about the parameters and return types accepted by @ExceptionHandler methods:

ExceptionHandler parameter types
ExceptionHandler parameter types
ExceptionHandler return types
ExceptionHandler return types
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.

javabackend-developmentException HandlingSpring MVCRestControllerAdvice
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.