一、RestControllerAdvice注解与全局异常处理
这是一个与切面有关的注解,切面的注解肯定都有个作用范围,切面类的注解只能对其作用范围内的操作,实现切面操作。
RestControllerAdvice的作用范围是:单个项目中所有使用了RequestMapping(像PostMapping底层是使用了RequestMapping注解的也支持)的类都归他管,该注解还需要与其他注解配合使用才有意义,单独的使用该注解是没有任何意义的。
二、ExceptionHandler注解
RestControllerAdvice+ExceptionHandler这两个注解的组合,被用作项目的全局异常处理,一旦项目中发生了异常,就会进入使用了RestControllerAdvice注解类中使用了ExceptionHandler注解的方法,我们可以在这里处理全局异常,将异常信息输出到指定的位置。并对所有的错误信息进行归置。
三、用法
@RestControllerAdvice:处理全局范围内的异常
@RestControllerAdvice("com.example.demo"):指定了一个特定的包,表示该类只处理来自com.example.demo包下的控制器的异常
@RestControllerAdvice(basePackageClasses = UserController.class):指定了一个特定的类,表示该类只处理 UserController 类所在的包下的控制器的异常
@RestControllerAdvice(value = "com.example.demo"):用法同 @RestControllerAdvice("com.example.demo")
@RestControllerAdvice(annotations = Annotation.class):用于处理带有特定注解的控制器的异常。只有带有 Annotation 注解的控制器产生的异常会被这个类处理
四、示例代码
/**
* 全局异常处理
**/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler{
/**
* <1> 处理 form data方式调用接口校验失败抛出的异常
*
* @param e
* @return
*/
@ExceptionHandler(BindException.class)
public R bindExceptionHandler(BindException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
Map<String, String> errorMap = new HashMap<>();
fieldErrors.forEach((fieldError) -> errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()));
log.info("ExceptionControllerAdvice.exceptionHandler.bindExceptionHandler==================");
return R.error(BusinessCodeEnum.VALID_EXCEPTION).setData(errorMap);
}
/**
* <2>数据校验异常拦截
*
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public R exceptionHandle(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
Map<String, String> errorMap = new HashMap<>();
fieldErrors.forEach((fieldError) -> errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()));
log.info("ExceptionControllerAdvice.exceptionHandler.exceptionHandle==================");
return R.error(BusinessCodeEnum.VALID_EXCEPTION).setData(errorMap);
}
/**
* <3> 处理单个参数校验失败抛出的异常
*
* @param e
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
public R constraintViolationExceptionHandler(ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
Map<String, String> errorMap = new HashMap<>();
for (ConstraintViolation<?> constraintViolation : constraintViolations) {
PathImpl pathimpl = (PathImpl) constraintViolation.getPropertyPath();
errorMap.put(pathimpl.getLeafNode().getName(), constraintViolation.getMessage());
}
log.info("ExceptionControllerAdvice.exceptionHandler.constraintViolationExceptionHandler==================");
return R.error(BusinessCodeEnum.VALID_EXCEPTION).setData(errorMap);
}
/**
* <4> 自定义异常处理
*
* @param businessException
* @return
*/
@ExceptionHandler(value = BusinessException.class)
public R customHandler(BusinessException businessException) {
log.info("ExceptionControllerAdvice.exceptionHandler.customHandler==================");
return R.error(businessException.getCode(), businessException.getMsg());
}
/**
* <5> 其他所有异常处理
*
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
public R exceptionHandler(Exception e) {
log.info("ExceptionControllerAdvice.exceptionHandler.exceptionHandler==================");
return R.error(BusinessCodeEnum.OPERATION_FAILED);
}
五、其他
除了全局异常处理的功能外,还可以实现全局数据绑定和全局数据预处理,分别是 @ModelAttribute 和 @InitBinder
这两个注解也是可以与RestControllerAdvice配合使用的
- InitBinder注解:用于将前端传递的参数进行分别绑定
- ModelAttribute注解:获取InitBinder绑定的参数,对他进行属性绑定
@Controller
@RequestMapping("/test")
public class TestController {
// 绑定变量名字和属性,参数封装进类
@InitBinder("user")
public void initBinderUser(WebDataBinder binder) {
binder.setFieldDefaultPrefix("user.");
}
// 绑定变量名字和属性,参数封装进类
@InitBinder("addr")
public void initBinderAddr(WebDataBinder binder) {
binder.setFieldDefaultPrefix("addr.");
}
@RequestMapping("/test")
@ResponseBody
public Map<String,Object> test(HttpServletRequest request,
@ModelAttribute("user") User user,@ModelAttribute("addr") Addr addr){
Map<String,Object> map=new HashMap<String,Object>();
map.put("user", user);
map.put("addr", addr);
return map;
}