【spring boot】捕获全局异常@RestControllerAdvice
一.由来
场景: 使用 Java的validation做入参的校验 ,但是这种入参校验在还没有进入controller就会字段校验不通过,从而直接返回异常信息给前端,
前端的异常提醒, 类似于下面这种 很不友好的
后端接口报错提示信息:
二.解决方法
1.解决如上问题,需要对异常做捕获处理,Spring boot 提供了@RestControllerAdvice 可以完成 全局异常捕获处理
2.具体实现
2.1 定义请求入参GlobalParams
【比如,使用Java的validation做入参的校验 这种场景】
package com.sxd.swapping.globalException.param;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 使用 Java的validation做入参的校验
* 测试一下全局异常怎么捕获这种入参类型的校验(因为此处入参校验未通过,压根就不会进Controller)
*/
@Data
public class GlobalParams {
@NotNull(message = "ID不能为空")
private Long id;
@NotEmpty(message = "集合不能为空")
private List<String> myStrList;
}
2.2 定义请求响应GlobalResult
【可一定要getter/setter方法】
package com.sxd.swapping.globalException.result;
import lombok.Data;
/**
* 自定义一个 统一响应体
*/
@Data
public class GlobalResult {
public static final String SUCCESS_CODE = "0000";
public static final String ERROR_CODE = "9999";
/**
* 状态码
*/
private String code;
/**
* 状态码描述
*/
private String message;
/**
* 响应结果
*/
private Object data;
private GlobalResult(String code, String message) {
this(code, message, null);
}
private GlobalResult(String code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
public static GlobalResult build(String code, String message) {
return new GlobalResult(code, message);
}
public static GlobalResult build(String code, String message, Object data) {
return new GlobalResult(code, message, data);
}
public static GlobalResult success() {
return build(SUCCESS_CODE, "处理成功");
}
public static GlobalResult success(String code, String message) {
return build(code, message);
}
public static GlobalResult success(Object data) {
return build(SUCCESS_CODE, "处理成功", data);
}
public static GlobalResult error() {
return build(ERROR_CODE, "处理失败");
}
public static GlobalResult error(String message) {
return error(ERROR_CODE, message);
}
public static GlobalResult error(String code, String message) {
return build(code, message);
}
}
2.3 定义全局异常捕获GlobalAdvice
【可捕获一种特定异常,也可捕获多种异常,依顺序从上往下】
package com.sxd.swapping.globalException.advice;
import com.sxd.swapping.globalException.result.GlobalResult;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.List;
/**
* 全局异常捕获
*@RestControllerAdvice都是对Controller进行增强的,可以全局捕获spring mvc抛的异常。
*
* ExceptionHandler 可以全局仅捕获一种异常,也可以全局捕获多种异常,从上到下 依次处理
*
*/
@RestControllerAdvice
public class GlobalAdvice {
/**
* ExceptionHandler的作用是用来捕获指定的异常
* 这里示例 捕获 Java的validation做入参的校验 的校验失败的异常
* 统一处理,免得返回前端
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public GlobalResult handleStoreAuthException(MethodArgumentNotValidException e) {
List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
StringBuilder detailMsg = new StringBuilder();
if (CollectionUtils.isNotEmpty(allErrors)) {
allErrors.stream().forEach(i -> detailMsg.append(i.getDefaultMessage()).append(";"));
}
return GlobalResult.build(GlobalResult.ERROR_CODE, detailMsg.toString());
}
/**
* ExceptionHandler的作用是用来捕获指定的异常
* 这里示例 捕获 Exception异常
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public GlobalResult handleStoreAuthException(Exception e) {
return GlobalResult.build(GlobalResult.ERROR_CODE, e.getMessage());
}
}
2.4 定义接口GlobalExceptionController
package com.sxd.swapping.globalException.controller;
import com.sxd.swapping.globalException.param.GlobalParams;
import com.sxd.swapping.globalException.result.GlobalResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@Slf4j
@Controller
@RequestMapping("/myglobal/exception")
public class GlobalExceptionController {
@ResponseBody
@PostMapping(value = "/test")
public GlobalResult myTest(@Valid @RequestBody GlobalParams params){
Long id = params.getId();
id = id / 0;
log.info("业务处理!!!");
return GlobalResult.success();
}
}
三.验证结果
前端控件也可返回友好的异常提醒