下面是关于Spring Boot项目异常处理及返回结果统一的完整攻略:
1. 异常处理的重要性
在Web开发中,异常是常见的问题。除开系统自带的异常外,还有业务系统自己抛出的异常。如果不及时有效的处理异常,系统将会毫无提示地将异常信息直接暴露给用户,这对系统的安全性以及可维护性均会产生不利影响。
因此,良好的异常处理机制非常重要。Spring Boot为我们提供了强大的异常处理机制,使用它能够做到全局统一异常处理并返回统一格式的异常信息,这样一来,不仅能够保护系统的安全性,更能给用户提供友好的提示。
2. 统一异常处理
统一异常处理是指将所有可能出现的异常捕获并转化为同一种异常类型,从而使得异常处理方式标准化并分离业务和异常处理逻辑。
在Spring Boot中,您可以使用@ControllerAdvice,@ExceptionHandler和其他有关注解来实现全局异常处理。具体的步骤如下:
2.1 创建一个全局异常处理类
首先,你需要创建一个类并添加@ControllerAdvice注解。这样Spring Boot就知道它应该将这个类用作全局异常处理程序。
@ControllerAdvice
public class GlobalExceptionHandler {
// 异常处理方法
}
2.2 使用@ExceptionHandler来处理异常
接下来,您需要使用@ExceptionHandler注解来处理各种异常类型。例如:
@ExceptionHandler(Exception.class)
@ResponseBody
public JsonResult handleException(Exception e) {
// 处理逻辑
}
在上面的代码中,我们使用了@ApiIgnore注解,表示这个方法不会被Swagger API文档显示。@ResponseBody注解是将方法的返回值自动转换为JSON格式。
在异常处理中,我们需要使用自定义异常类,统一处理所有抛出的自定义异常。查看如下的代码:
@ExceptionHandler(CustomException.class)
@ResponseBody
public JsonResult handleCustomException(CustomException e) {
// 处理逻辑
}
相比较上面的代码,这里处理的是自定义异常。对于常规异常和自定义异常的处理方式需要分别处理。
2.3 自定义异常
定义自定义异常需要继承RuntimeException或其子类,以便在代码中抛出异常:
public class CustomException extends RuntimeException {
// 自定义异常处理逻辑
}
2.4 返回异常信息
下面是一个返回统一格式的异常处理实例:
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public JsonResult handleException(Exception ex) {
log.error("[GlobalExceptionHandler] handleException: ", ex);
return JsonResult.error(ResultCode.INTERNAL_SERVER_ERROR.getCode(),
ResultCode.INTERNAL_SERVER_ERROR.getMessage());
}
@ExceptionHandler(CustomException.class)
@ResponseBody
public JsonResult handleCustomException(CustomException ex) {
log.error("[GlobalExceptionHandler] handleCustomException: ", ex);
return JsonResult.error(ex.getCode(), ex.getMessage());
}
}
在上面的代码中,我们使用了@Slf4j注解,用于记录日志,@ResponseBody用于将结果转换为JSON字符串,而JsonResult是自定义的统一数据返回格式。
3. 统一返回结果处理
除了处理异常信息,将所有的返回结果都统一成一个格式,也是很有必要的。这样一来,无论使用什么方式,返回的数据都是统一的格式,这样利于前端数据处理以及进行规范化。
3.1 创建返回结果类
首先,您需要创建一个返回结果类。根据实际情况,您的结果类可以包含不同的属性。一般来说,一个返回结果类需要包含状态码(code)、消息(msg)以及返回的数据(data)等属性。示例如下:
public class JsonResult {
// 请求结果状态码
private Integer code;
// 请求结果消息
private String msg;
// 请求结果数据
private Object data;
}
3.2 封装返回结果
定义好返回结果类之后,您需要在Controller层对所有的返回对象进行封装,并使用@JsonInclude注解转换为JSON格式,并设置每个方法的@ResponseBody注解为统一处理类:
@RestControllerAdvice
public class ResponseControllerAdvice {
@ExceptionHandler({Exception.class, BusinessException.class})
public JsonResult handleException(Exception ex) {
return JsonResult.fail(ex.getMessage());
}
@ExceptionHandler(HttpMessageNotReadableException.class)
public JsonResult handleHttpMessageNotReadableException(HttpServletRequest request,
HttpMessageNotReadableException ex) {
String message = String.format("URL: %s, %s", request.getRequestURL().toString(),
"参数解析失败,请检查传参格式是否正确或参数是否缺失");
return JsonResult.fail(message);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public JsonResult handleMethodArgumentNotValidException(HttpServletRequest request,
MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
StringBuilder message = new StringBuilder();
if (bindingResult.hasErrors()) {
bindingResult.getAllErrors()
.forEach(error -> message.append(error.getDefaultMessage()).append(","));
}
message.deleteCharAt(message.length() - 1);
String errMsg = String.format("URL: %s, %s", request.getRequestURL().toString(),
"参数校验失败: " + message);
return JsonResult.fail(errMsg);
}
@ExceptionHandler(value = HttpException.class)
public JsonResult httpExceptionHandler(HttpServletRequest request, HttpException e) {
return JsonResult.fail(e.getCode(), e.getMessage());
}
/**
* 非法参数异常
*/
@ExceptionHandler(IllegalArgumentException.class)
public JsonResult illegalArgumentExceptionHandler(HttpServletRequest request,
IllegalArgumentException e) {
return JsonResult.fail(e.getMessage());
}
/**
* 参数缺失异常
* @param request
* @param e
* @return
*/
@ExceptionHandler(MissingServletRequestParameterException.class)
public JsonResult missingServletRequestParameterExceptionHandler(HttpServletRequest request,
MissingServletRequestParameterException e) {
return JsonResult.fail("缺少请求参数:" + e.getParameterName());
}
/**
* Token校验失败异常
* @param request
* @param e
* @return
*/
@ExceptionHandler(value = TokenException.class)
public JsonResult tokenExceptionHandler(HttpServletRequest request, TokenException e) {
return JsonResult.fail(e.getCode(), e.getMessage());
}
/**
* 权限认证异常
*/
@ExceptionHandler(value = AuthenticationException.class)
public JsonResult authenticationExceptionHandler(HttpServletRequest request,
AuthenticationException e) {
return JsonResult.fail(e.getCode(), e.getMessage());
}
/**
* 抛出通用异常
* @param e
* @param request
* @return
*/
@ExceptionHandler(value = CommonException.class)
public JsonResult commonExceptionHandler(CommonException e, HttpServletRequest request) {
return JsonResult.fail(e.getCode(), e.getMessage());
}
/**
* 参数解析异常
* @param e
* @param request
* @return
*/
@ExceptionHandler(value = ParseException.class)
public JsonResult parseExceptionHandler(ParseException e, HttpServletRequest request) {
return JsonResult.fail(e.getMessage());
}
/**
* 业务异常处理
* @param e
* @param request
* @return
*/
@ExceptionHandler(value = BizException.class)
public JsonResult bizExceptionHandler(BizException e, HttpServletRequest request) {
return JsonResult.fail(e.getCode(), e.getMessage());
}
}
3.3 封装返回结果示例
/**
* 新增商品类别信息
*
* @param category
* @return
*/
@PostMapping("save")
public JsonResult save(@RequestBody @Validated Category category) {
return JsonResult.ok(categoryService.save(category));
}
在上面示例中,我们将返回值简化为了JsonResult.ok(obj)的语法。这样一来,返回的结果就会被 ResponseControllerAdvice进行统一返回。如果只有一个接口需要统一返回结果,那么直接在controller层return JsonResult.ok(obj)就可以,如果有多个接口需要统一返回,每个接口都写一遍就显得复杂冗余。将所有返回统一到一个单独的Controller中,等待SpringMVC拦截响应再进行统一输出。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springboot项目异常处理及返回结果统一 - Python技术站