本文共 5866 字,大约阅读时间需要 19 分钟。
全局异常处理是Spring Boot应用中非常重要的一部分,能够统一处理各种异常,提升应用的健壮性和用户体验。本文将详细介绍Spring Boot全局异常处理的配置与实现,包括代码设计和优化。
在Spring Boot应用中,通过@ControllerAdvice
注解和配置文件application.yml
,可以实现全局异常处理的统一配置。这种方法能够处理@Controller
、@RestController
以及容器级别的异常,提升应用的异常处理能力。
首先,我们需要定义一个通用的运行时异常BusinessException
。该类应携带错误代码和错误信息,便于在全局处理器中构造返回结果。
package com.what21.demo.common;import lombok.Data;@Datapublic class BusinessException extends RuntimeException { private Integer code; private String message; public BusinessException(String message) { super(message); } public BusinessException(String message, Throwable cause) { super(message, cause); } public BusinessException(Throwable cause) { super(cause); } public BusinessException(Integer code, String message) { super(code + ":" + message); this.code = code; this.message = message; }}
接下来,创建封装返回结果的R
类:
package com.what21.demo.common;import lombok.Getter;import lombok.Setter;import lombok.ToString;import java.io.Serializable;@Getter@Setter@ToStringpublic class Rimplements Serializable { private static final long serialVersionUID = 1L; public static final String OK = "SUCCESS"; public static final String ERROR = "ERROR"; @Getter @Setter private String code; @Getter @Setter private String msg; @Getter @Setter private T data; public static R ok() { return instance(OK, null, null); } public static R ok(T data) { return instance(OK, null, data); } public static R ok(T data, String msg) { return instance(OK, msg, data); } public static R okMsg(String msg) { return instance(OK, msg, null); } public static R error() { return instance(ERROR, null, null); } public static R error(T data) { return instance(ERROR, null, data); } public static R error(T data, String msg) { return instance(ERROR, msg, data); } public static R errMsg(String msg) { return instance(ERROR, msg, null); } public static R instance(String code, String msg, T data) { R result = new R<>(); result.setCode(code); result.setMsg(msg); result.setData(data); return result; }}
最后,配置全局异常处理器:
package com.what21.demo.common;import lombok.extern.slf4j.Slf4j;import org.springframework.validation.BindException;import org.springframework.validation.ObjectError;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestControllerAdvice;import org.springframework.web.servlet.NoHandlerFoundException;import java.util.List;@Slf4j@ControllerAdvicepublic class GlobalExceptionHandler { @ExceptionHandler(value = {BusinessException.class}) @ResponseBody public R businessExceptionHandler(BusinessException e) { log.debug("处理业务异常,代码:{},信息:{}", e.getCode(), e.getMessage()); return R.instance(e.getCode().toString(), e.getMessage(), null); } @ExceptionHandler(value = {Exception.class}) @ResponseBody public R exceptionHandler(Exception e) { if (e instanceof NoHandlerFoundException) { return R.instance("1001", e.getMessage(), null); } else if (e instanceof IllegalArgumentException) { return R.instance("1001", e.getMessage(), null); } else if (e instanceof IllegalStateException) { return R.instance("1001", e.getMessage(), null); } else if (e instanceof BindException) { BindException ex = (BindException) e; ListallErrors = ex.getAllErrors(); ObjectError error = allErrors.get(0); return R.instance("1001", error.getDefaultMessage(), null); } else if (e instanceof MethodArgumentNotValidException) { MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e; List errors = ex.getBindingResult().getAllErrors(); if (!errors.isEmpty()) { org.springframework.web.bind.BinderResult error = errors.get(0); return R.instance("1001", error.getDefaultMessage(), null); } } return R.instance("1001", e.getMessage(), null); }}
application.yml
spring: mvc: throw-exception-if-no-handler-found: true resources: add-mappings: false
创建一个测试控制器:
package com.what21.demo.controller;import com.what21.demo.common.BusinessException;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;@Controllerpublic class EchoController { @GetMapping("/") public String index(Model model) { model.addAttribute("index", "首页"); return "index"; } @RequestMapping(path = "/echo", method = {RequestMethod.GET}) @ResponseBody public String echo() { if (true) { throw new BusinessException(1002, "业务异常信息"); } return "hello"; }}
通过上述配置,可以实现对以下场景的异常处理:
业务异常:任何抛出的BusinessException
都会被businessExceptionHandler
捕获,并返回一个JSON格式的错误结果。
未映射的URL异常:当URL未找到时,NoHandlerFoundException
会导致返回一个格式化的404错误。
参数验证异常:@Valid
注解和校验器 Butt师傅异常会被处理为标准化的错误信息。
通过R.instance
方法,可以根据不同场景构造特定的返回结果,实现JSON格式的错误处理。例如,R.instance(ERROR, "错误代码", "错误信息")
将返回一个{error: "错误信息"}
的JSON对象。
减少重复代码:可以创建一个自定义的异常处理结果构建器,减少R.instance
方法的重复调用。
分区处理异常:根据异常类型分区处理,实现更细致的错误信息构建。
日志记录:通过Slf4j
或其他日志框架记录异常处理日志,方便定位问题。
统一错误页面:可以通过редirect到一个统一的错误页面,提升用户体验。
定制返回结果:根据需要扩展R
类,添加更多的处理逻辑,使其适应不同业务需求。
通过以上配置和实现,可以大大简化异常处理逻辑,使代码更加整洁高效,提升应用的稳定性和用户体验。
转载地址:http://zhprz.baihongyu.com/