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.
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
<code>@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();
}
}
</code>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
<code>@RestControllerAdvice
public class TestControllerAdvice {
@ExceptionHandler
public Object handle(Exception e) {
return "我是全局异常:" + e.getMessage();
}
}
</code>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
<code>@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AppAnnotation {}
</code>Controllers annotated with @AppAnnotation :
<code>@AppAnnotation
@RestController
public class AnnotationController {
@GetMapping("/an/get/{id}")
public Object an(@PathVariable Integer id) {
if (id < 10) {
throw new RuntimeException("发生错误了");
}
return "自定义Annotation注解: " + id;
}
}
</code>Controllers without the annotation:
<code>@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;
}
}
</code> <code>@RestControllerAdvice(annotations = {AppAnnotation.class})
public class AnnotationControllerAdvice {
@ExceptionHandler
public Object handle(Exception e) {
return "特定注解全局异常:" + e.getMessage();
}
}
</code>Only the controller with @AppAnnotation is intercepted by the advice.
Handling Specific Controllers
<code>@RestController
public class UserController {
@GetMapping("/user/{id}")
public Object get(@PathVariable Integer id) {
if (id < 10) {
throw new RuntimeException("用户ID错误");
}
return "Users";
}
}
</code> <code>@RestController
public class PersonController {
@GetMapping("/person/{id}")
public Object get(@PathVariable Integer id) {
if (id < 10) {
throw new RuntimeException("Person ID错误");
}
return "Person";
}
}
</code> <code>@RestControllerAdvice(assignableTypes = {UserController.class})
public class SpecificControllerAdvice {
@ExceptionHandler
public Object handle(Exception e) {
return "指定Controller全局异常:" + e.getMessage();
}
}
</code>The advice applies only to UserController ; exceptions from PersonController are not handled.
Handling Controllers in Specific Packages
<code>@RestControllerAdvice(basePackages = {"com.pack.pkg1"})
public class PackageControllerAdvice {
@ExceptionHandler
public Object handle(Exception e) {
return "指定包下的全局异常:" + e.getMessage();
}
}
</code>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:
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.