在现代Web开发中,异常处理是一个不可或缺的部分。良好的异常处理不仅能提高系统的健壮性,还能提升用户体验。在Spring Boot中,全局异常处理的实现可以通过使用
@RestControllerAdvice
注解来完成。本文将详细介绍如何使用
@RestControllerAdvice
和
@ExceptionHandler
来统一处理异常,并给出具体的实现示例。
1.
@RestControllerAdvice
概述
@RestControllerAdvice
是Spring MVC提供的一个功能强大的注解,用于全局处理控制器中的异常。它相当于
@ControllerAdvice
和
@ResponseBody
的组合,可以用于定义以下三种功能:
- **
@ExceptionHandler
**:处理特定的异常,并将响应返回给前端。 - **
@InitBinder
**:预处理Web请求数据的绑定。 - **
@ModelAttribute
**:将数据绑定到模型中,以便在控制器的@RequestMapping
方法中使用。
@RestControllerAdvice
自动被Spring的组件扫描机制检测到,若应用通过MVC命令空间或MVC Java编程方式配置,该功能默认自动开启。
2. 实现全局异常处理
在实现全局异常处理时,我们通常会定义一个异常处理类,这个类中包含多个异常处理方法,每个方法对应一种或多种异常类型。下面是一个典型的实现示例。
2.1 全局异常处理器
importcom.sugon.cloud.lowcode.result.ReturnResult;importlombok.extern.slf4j.Slf4j;importorg.mybatis.spring.MyBatisSystemException;importorg.springframework.web.HttpRequestMethodNotSupportedException;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.ResponseBody;importorg.springframework.web.bind.annotation.RestControllerAdvice;importjavax.naming.AuthenticationException;importjavax.servlet.http.HttpServletRequest;importstaticcom.sugon.cloud.lowcode.constants.SplitCharacter.LEFT_PARENTHESES;importstaticcom.sugon.cloud.lowcode.constants.SplitCharacter.RIGHT_PARENTHESES;importstaticcom.sugon.cloud.lowcode.result.CodeMessageEnum.*;@RestControllerAdvice@Slf4jpublicclassGlobalExceptionHandler{@ExceptionHandler(value =BizException.class)@ResponseBodypublicReturnResultbizExceptionHandler(HttpServletRequest req,BizException e){
log.error("发生业务异常: {}, 请求接口: {}", e.getMessage(), req.getRequestURI());returnReturnResult.error(e.getCode(), e.getMessage());}@ExceptionHandler(value =NullPointerException.class)@ResponseBodypublicReturnResultexceptionHandler(HttpServletRequest req,NullPointerException e){
log.error("空指针异常信息: {}, 请求接口: {}", e, req.getRequestURI());returnReturnResult.error(NULL_POINT_ERROR_EXCEPTION.getCode(),NULL_POINT_ERROR_EXCEPTION.getMessage()+RIGHT_PARENTHESES+ e.getMessage()+LEFT_PARENTHESES);}@ExceptionHandler(value =HttpRequestMethodNotSupportedException.class)@ResponseBodypublicReturnResultmethodNotSupportedExceptionHandler(HttpServletRequest req,Exception e){
log.error("请求方法异常信息: {},请求接口: {}", e, req.getRequestURI());returnReturnResult.error(REQUEST_METHOD_ERROR.getCode(),REQUEST_METHOD_ERROR.getMessage()+RIGHT_PARENTHESES+ e.getMessage()+LEFT_PARENTHESES);}@ExceptionHandler(value =MyBatisSystemException.class)@ResponseBodypublicReturnResultsqlSyntaxErrorExceptionHandler(HttpServletRequest req,Exception e){
log.error("MyBatis系统异常信息: {},请求接口: {}", e, req.getRequestURI());returnReturnResult.error(INNER_FRAME_EXCEPTION.getCode(),INNER_FRAME_EXCEPTION.getMessage()+RIGHT_PARENTHESES+ e.getMessage()+LEFT_PARENTHESES);}@ExceptionHandler(value =AuthenticationException.class)publicReturnResultincorrectCredentialsException(HttpServletRequest request,AuthenticationException e){
log.error("用户名或密码不正确: {}, 请求接口: {}", e, request.getRequestURI());returnReturnResult.error(USER_CREDENTIALS_ERROR);}@ExceptionHandler(value =UserException.class)publicReturnResultincorrectUserException(HttpServletRequest request,UserException e){
log.error("用户信息异常: {}, 请求接口: {}", e, request.getRequestURI());returnReturnResult.error(e.getCode(), e.getMessage());}@ExceptionHandler(value =Exception.class)@ResponseBodypublicReturnResultexceptionHandler(HttpServletRequest req,Exception e){
e.printStackTrace();
log.error("未知异常: {}, 请求接口: {}", e, req.getRequestURI());returnReturnResult.error(INTERNAL_SERVER_ERROR.getCode(),INTERNAL_SERVER_ERROR.getMessage()+RIGHT_PARENTHESES+ e.getMessage()+LEFT_PARENTHESES);}}
2.2 自定义业务异常类
importcom.sugon.cloud.lowcode.result.BaseResultInterface;importcom.sugon.cloud.lowcode.result.CodeMessageEnum;importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;@ApiModel(description="业务异常数据")publicclassBizExceptionextendsRuntimeExceptionimplementsBaseResultInterface{privatestaticfinallong serialVersionUID =1L;@ApiModelProperty(value ="错误码")privateString code;@ApiModelProperty(value ="错误信息")privateString message;publicBizException(){super();}publicBizException(CodeMessageEnum codeMessageEnum){super(codeMessageEnum.getCode());this.code = codeMessageEnum.getCode();this.message = codeMessageEnum.getMessage();}publicBizException(CodeMessageEnum codeMessageEnum,Throwable cause){super(codeMessageEnum.getCode(), cause);this.code = codeMessageEnum.getCode();this.message = codeMessageEnum.getMessage();}publicBizException(CodeMessageEnum codeMessageEnum,String message,Throwable cause){super(codeMessageEnum.getCode(), cause);this.code = codeMessageEnum.getCode();this.message = message;}publicBizException(String message){super(message);this.message = message;}publicBizException(String code,String message){super(code);this.code = code;this.message = message;}publicBizException(String code,String message,Throwable cause){super(code, cause);this.code = code;this.message = message;}@OverridepublicThrowablefillInStackTrace(){returnthis;}@OverridepublicStringgetCode(){returnthis.code;}@OverridepublicStringgetMessage(){returnthis.message;}}
3. 统一返回格式
在上述代码中,所有的异常处理方法返回的是
ReturnResult
对象,它封装了返回给前端的数据。
ReturnResult
类的设计使得前端可以统一解析和展示错误信息。
3.1 返回结果类
importcom.alibaba.fastjson.JSONObject;importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Getter;importlombok.Setter;importstaticcom.sugon.cloud.lowcode.result.CodeMessageEnum.*;@Setter@Getter@ApiModel(description="返回响应数据")publicclassReturnResult<T>{@ApiModelProperty(value ="状态码")privateString code;@ApiModelProperty(value ="响应信息")privateString message;@ApiModelProperty(value ="响应对象")privateT result;@ApiModelProperty(value ="是否成功")privateboolean success =true;publicReturnResult(){}publicReturnResult(CodeMessageEnum codeMessageEnum){this.code = codeMessageEnum.getCode();this.message = codeMessageEnum.getMessage();}publicstaticReturnResultsuccess(){returnsuccess(null);}publicstatic<T>ReturnResult<T>success(T data){returnsuccess(SUCCESS, data);}publicstatic<T>ReturnResult<T>loginSuccess(T data){returnsuccess(SUCCESS_LOGIN, data);}publicstaticReturnResultloginOutSuccess(){returnsuccess(SUCCESS_LOGOUT,null);}privatestatic<T>ReturnResult<T>success(CodeMessageEnum codeMessageEnum,T data){ReturnResult<T> result =newReturnResult<>();
result.setCode(codeMessageEnum.getCode());
result.setMessage(codeMessageEnum.getMessage());
result.setResult(data);return result;}publicstaticReturnResulterror(CodeMessageEnum codeMessageEnum){returnerror(codeMessageEnum.getCode(), codeMessageEnum.getMessage());}publicstaticReturnResulterror(CodeMessageEnum codeMessageEnum,String message){returnerror(codeMessageEnum.getCode(), message);}publicstaticReturnResulterror(String code,String message){ReturnResult result =newReturnResult();
result.setCode(code);
result.setMessage(message);
result.setSuccess(false);return result;}@OverridepublicStringtoString(){returnJSONObject.toJSONString(this);}}
4. 总结
通过
@RestControllerAdvice
和
@ExceptionHandler
,我们可以在Spring Boot应用中实现全局异常处理,统一管理和处理所有异常。这样不仅可以
减少重复代码,还能使代码更加整洁,提高可维护性。同时,通过统一的返回格式,前端处理响应数据时也能更加方便。
希望这篇文章对您在Spring Boot中实现全局异常处理有所帮助。如有任何问题或建议,欢迎交流探讨。
版权归原作者 琴剑飘零西复东 所有, 如有侵权,请联系我们删除。