SpringBoot @ControllerAdvice 处理异常
应用中的异常,有两件事要考虑,怎么处理这个异常,怎么把异常可读性高地返回给前端用户
1.怎么把异常可读性高的返回给前端用户或API的消费者
自定义错误代码和错误内容
2.怎么处理异常
比如遇到某个异常时需要发邮件通知IT团队
@ControllerAdvice 是 Spring Framework 提供的一个注解,用于定义全局的异常处理、数据绑定和模型属性的增强。
它的主要作用是集中管理控制器的全局逻辑,例如异常处理,而不需要在每个控制器中重复编写相同的代码。
主要功能
全局异常处理:通过 @ExceptionHandler 注解 捕获并处理控制器中抛出的异常。
全局数据绑定:通过 @InitBinder 注解对请求参数进行预处理。
全局模型属性:通过 @ModelAttribute 注解为所有控制器提供公共的模型数据
3.自定义错误代码和内容,并且使用@ControllerAdvice统一处理异常
3.1 自定义错误码,可以把Demo换成projectname
public enum ExceptionCode { IN_VALID_REQUEST("Demo0001", ""), BAD_REQUEST("Demo400", "Bad Request"), NOT_FOUND("Demo404", "Resource Not Found"), INTERNAL_SERVER_ERROR("Demo500", "Internal Server Error"); private final String code; private final String message; ExceptionCode(String code, String message) { this.code = code; this.message = message; } public String getCode() { return code; } public String getMessage() { return message; } }
3.2 自定义异常InvalidationException
public class InvalidationRequestException extends RuntimeException { public InvalidationRequestException(String message) { super(message); } public InvalidationRequestException(String message, Throwable cause) { super(message, cause); } }
3.3 自定义ExceptionAdvice,统一处理exception
当controller中抛出InvalidationRequestException时,就会被@ControllerAdvice 中的 @ExceptionHandler handleInvalidationException()方法捕获并处理该异常
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class GlobalExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); @ExceptionHandler(InvalidationRequestException.class) @ResponseBody public ResponseEntity<Map<String, String>> handleInvalidationException(InvalidationRequestException ex) { logger.warn("InvalidationRequestException: {}", ex.getMessage()); //其它异常处理逻辑,比如发邮件,打电话通知IT团队 //返回给UI或API消费者 Map<String, String> response = new HashMap<>(); response.put("code", ExceptionCode.IN_VALIDATED_REQUEST.getCode()); response.put("detail",ex.getMessage()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); } @ExceptionHandler(Exception.class) public ResponseEntity<String> handleGenericException(Exception ex) { return new ResponseEntity<>("An error occurred: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } }
3.4 controller, 抛出InvalidationException异常
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class DemoController { @GetMapping("/validate") public String validateParameter(@RequestParam String input) { if (input == null || input.trim().isEmpty()) { throw new InvalidationRequestException("Input parameter is invalid or empty"); } return "Input is valid: " + input; } }
3.5 测试
启动应用,访问 http://localhost:8082/validate?input
校验失败时,返回http状态码是400,body如下
{ "code": "Demo0001", "detail": "Input parameter is invalid or empty" }
==========================================
1.异常直接抛出
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class DemoController { @GetMapping("/throwException") public String throwException() { throw new RuntimeException("This is a runtime exception!"); } }
启动应用,访问 http://localhost:8082/throwException
会获得一个状态码为500的异常 An error occurred: This is a runtime exception!
思考:这个异常对用户或者call API的消费者来说,可读性太低,不能明确的知道是什么错误
2.自定义状态码和错误信息,返回给前端用户或者API 消费者可读性高的异常
自定义错误码,可以把Demo换成projectname
public enum ExceptionCode { IN_VALIDATED_REQUEST("Demo0001", ""), BAD_REQUEST("Demo400", "Bad Request"), NOT_FOUND("Demo404", "Resource Not Found"), INTERNAL_SERVER_ERROR("Demo500", "Internal Server Error"); private final String code; private final String message; ExceptionCode(String code, String message) { this.code = code; this.message = message; } public String getCode() { return code; } public String getMessage() { return message; } }
controller抛出异常
import com.example.demo_async.exception.ExceptionCode; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class DemoController { @GetMapping("/testErrorCode") public ResponseEntity<Map<String, String>> testErrorCode() { Map<String, String> response = new HashMap<>(); response.put("code", ExceptionCode.BAD_REQUEST.getCode()); response.put("detail", ExceptionCode.BAD_REQUEST.getMessage()); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } }
返回http status 400, body 如下
{ "code": "Demo400", "detail": "Bad Request" }
思考:如果有很多个controller方法都会抛出这个异常,就需要在每个方法里写一遍异常处理的逻辑,会产生大量的重复代码,怎么解决呢?
浙公网安备 33010602011771号