@ControllerAdvice和、@ExceptionHandler可以构建全局异常处理器。
它们的底层原理是使用Spring AOP方式对被@RequestMaping声明的方法进行增强,从而达到异常统一处理的目的。
这样做的好处的就是不需要我们手动的对每一个异常进行try…catch。
首先@ControllerAdvice相当于通知类,同时又要具备切点表达式的身份,它会对所有被@RequestMaping声明的方法进行增强。
而@ExceptionHandler声明的方法相当于通知(增强方法)但它更加强大,它会对切入点进行上下文检索其声明的异常(@ExceptionHandler(value = Exception.class))所在,进行try…catch统一对异常进行处理。
全局异常处理流程:
1、创建自定义业务异常类;
2、创建一个类并声明@ControllerAdvice,作为全局异常处理类
3、在全局异常处理类上,创建增强方法,声明@ExceptionHandler检索需要处理的异常。
自定业务义异常类:
public class CustomException extends Exception {
public CustomException(String message){
super(message);
}
}
全局异常处理类:
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
@ResponseBody
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {
String message = ex.getMessage();
if (message.contains("Duplicate entry")) {
String[] split = message.split(" ");
return R.error(split[2] + "已存在");
}
return R.error("未知错误");
}
@ExceptionHandler(CustomException.class)
@ResponseBody
public R<String> customExceptionHandler(CustomException ce) {
return R.error(ce.getMessage());
}
}
测试:
比如这里有一个业务异常需要处理,分类关联菜品,不能删除:
@Override
public R<String> delete(Long id) {
LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
dishLambdaQueryWrapper.eq(Dish::getCategoryId, id);
if (dishMapper.selectCount(dishLambdaQueryWrapper) > 0) {
throw new CustomException("当前分类下关联了菜品,不能删除");
}
LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId, id);
if (setmealMapper.selectCount(setmealLambdaQueryWrapper) > 0) {
throw new CustomException("当前分类下关联了套餐,不能删除");
}
categoryMapper.deleteById(id);
return R.success("删除分类成功");
}
最终执行流程:

增强后的代码相当于:
@Override
public R<String> delete(Long id) {
LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
dishLambdaQueryWrapper.eq(Dish::getCategoryId, id);
if (dishMapper.selectCount(dishLambdaQueryWrapper) > 0) {
throw new CustomException("当前分类下关联了菜品,不能删除");
}
LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId, id);
if (setmealMapper.selectCount(setmealLambdaQueryWrapper) > 0) {
try {
throw new CustomException("当前分类下关联了套餐,不能删除");
} catch (CustomException e) {
return R.error(e.getMessage());
}
}
categoryMapper.deleteById(id);
return R.success("删除分类成功");
}