SpringMVC实现全局异常处理器的经典案例
作者:凯酱
通过 @ControllerAdvice 注解,我们可以在一个地方对所有 @Controller 注解的控制器进行管理。
注解了 @ControllerAdvice 的类的方法可以使用 @ExceptionHandler、 @InitBinder、 @ModelAttribute 注解到方法上,这对所有注解了 @RequestMapping 的控制器内的方法都有效。
@ExceptionHandler:用于捕获所有控制器里面的异常,并进行处理。@InitBinder:用来设置 WebDataBinder,WebDataBinder 用来自动绑定前台请求参数到 Model 中。@ModelAttribute:@ModelAttribute 本来的作用是绑定键值对到 Model
里,此处是让全局的@RequestMapping 都能获得在此处设置的键值对。
本文使用 @ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理。只要设计得当,就再也不用在 Controller 层进行 try-catch 了!
一、经典案例
需求:希望通过全局统一的异常处理将自定义错误码以json的形式发送给前端。
1、统一返回结果类 ApiResult
首先,定义一个统一结果返回类,最终需要将这个结果类的内容返回给前端。
package com.tao.smp.exception; /** * Api统一的返回结果类 */ public class ApiResult { /** * 结果码 */ private String code; /** * 结果码描述 */ private String msg; public ApiResult() { } public ApiResult(ResultCode resultCode) { this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); } /** * 生成一个ApiResult对象, 并返回 * * @param resultCode * @return */ public static ApiResult of(ResultCode resultCode) { return new ApiResult(resultCode); } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } @Override public String toString() { return "ApiResult{" + "code='" + code + '\'' + ", msg='" + msg + '\'' + '}'; } }
2、错误码枚举类 ResultCode
有了 ApiResult ,接下来需要定义一个枚举类, 来包含所有自定义的结果码。
package com.tao.smp.exception; /** * 错误码 */ public enum ResultCode { /** * 成功 */ SUCCESS("0", "success"), /** * 未知错误 */ UNKNOWN_ERROR("0x10001", "unkonwn error"), /** * 用户名错误或不存在 */ USERNAME_ERROR("0x10002", "username error or does not exist"), /** * 密码错误 */ PASSWORD_ERROR("0x10003", "password error"), /** * 用户名不能为空 */ USERNAME_EMPTY("0x10004", "username can not be empty"); /** * 结果码 */ private String code; /** * 结果码描述 */ private String msg; ResultCode(String code, String msg) { this.code = code; this.msg = msg; } public String getCode() { return code; } public String getMsg() { return msg; } }
3、自定义业务异常类 BusinessRuntimeException
接下来需要定义我们自己的业务异常类,以后和业务相关的异常通通抛出这个异常类,我们将错误码枚举变量的值存于其中。
package com.tao.smp.exception; /** * 自定义业务异常 */ public class BusinessRuntimeException extends RuntimeException { /** * 结果码 */ private String code; /** * 结果码描述 */ private String msg; /** * 结果码枚举 */ private ResultCode resultCode; public BusinessRuntimeException(ResultCode resultCode) { super(resultCode.getMsg()); this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); this.resultCode = resultCode; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public ResultCode getResultCode() { return resultCode; } public void setResultCode(ResultCode resultCode) { this.resultCode = resultCode; } }
4、全局异常处理类 GlobalExceptionResolver
最后便是定义全局异常处理类。
- 通过 @ControllerAdvice 指定该类为 Controller 增强类。
- 通过 @ExceptionHandler 自定捕获的异常类型。
- 通过 @ResponseBody 返回 json 到前端。
注意一点:被@ControllerAdvice注解的全局异常处理类也是一个 Controller ,我们需要配置扫描路径,确保能够扫描到这个Controller。
package com.tao.smp.exception; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * 全局Controller层异常处理类 */ @ControllerAdvice public class GlobalExceptionResolver { private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionResolver.class); /** * 处理所有不可知异常 * * @param e 异常 * @return json结果 */ @ExceptionHandler(Exception.class) @ResponseBody public ApiResult handleException(Exception e) { // 打印异常堆栈信息 LOG.error(e.getMessage(), e); return ApiResult.of(ResultCode.UNKNOWN_ERROR); } /** * 处理所有业务异常 * * @param e 业务异常 * @return json结果 */ @ExceptionHandler(BusinessRuntimeException.class) @ResponseBody public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) { // 不打印异常堆栈信息 LOG.error(e.getMsg()); return ApiResult.of(e.getResultCode()); } }
二、测试
1、测试 TestController
package com.tao.smp.controller; import com.tao.smp.exception.BusinessRuntimeException; import com.tao.smp.exception.ResultCode; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; /** * 测试异常的抛出 */ @Controller @RequestMapping("/") public class TestController { /** * 测试返回异常信息 * @return */ @GetMapping("/exception") public String returnExceptionInfo() { if (1 != 2) { // 用户民错误或不存在异常 throw new BusinessRuntimeException(ResultCode.USERNAME_ERROR); } return "success"; } }
到此这篇关于SpringMVC实现全局异常处理器的文章就介绍到这了,更多相关SpringMVC全局异常处理器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!