Spring Boot 自定义异常及Spring MVC处理异常流程
Overridethrow new ForbiddenOperationException("信息不存在");//业务代码未受检异常:RuntimeException及其子类属于未受检异常,这意味着它们在编译时不需要被显式捕获或声明抛出。这减少了代码的冗余,使得开发者可以更加专注于业务逻辑的实现。事务管理:在Spring框架等事务管理环境中,默认情况下只有未捕获的RuntimeException会
一、抛异常的流程
在Spring Boot(或Spring MVC)的应用中,异常确实通常会按照从Mapper层抛给Service层,再抛给Controller层,最终由Spring MVC的DispatcherServlet来参与整个异常处理流程的一部分(尽管DispatcherServlet本身并不直接处理异常,但它负责调用控制器并处理控制器的响应,包括异常处理后的响应)
二、Spring MVC的异常处理机制
了解上面的流程,当Controller层抛出异常时,Spring MVC的异常处理机制会介入。它会查找是否有全局异常处理器(或控制器中定义的局部异常处理方法(使用@ExceptionHandler注解的方法)来处理这个异常。如果找到了相应的异常处理方法,Spring MVC会调用这个方法来处理异常,并生成一个HTTP响应返回给客户端。如果没有找到相应的异常处理方法,Spring MVC可能会使用默认的异常处理策略(如返回错误页面或JSON格式的错误信息)。
三、自定义异常
我们以这个自定义异常为例:
@Override
public void deleteById(Long id) {
Serve serve = baseMapper.selectById(id);
if(ObjectUtil.isNull(serve)){
throw new ForbiddenOperationException("信息不存在");
}
//业务代码
}
首先我的项目中让ForbiddenOperationException()继承CommonException(),其次CommonException继承自RuntimeException,继承RuntimeException的好处,有下面四点:
- 未受检异常:RuntimeException及其子类属于未受检异常,这意味着它们在编译时不需要被显式捕获或声明抛出。这减少了代码的冗余,使得开发者可以更加专注于业务逻辑的实现。
- 事务管理:在Spring框架等事务管理环境中,默认情况下只有未捕获的RuntimeException会触发事务回滚。因此,如果自定义异常旨在表示程序中的逻辑错误或意外情况,并且希望这些错误能够导致事务回滚,那么继承自RuntimeException是一个合适的选择。
- 简化代码:由于未受检异常不需要在方法签名中声明,因此使用继承自RuntimeException的自定义异常可以简化代码结构,提高代码的可读性和可维护性。
- 全局异常处理:在Spring Boot等现代Java框架中,开发者通常会使用全局异常处理器来捕获和处理各种异常。继承自RuntimeException的自定义异常可以更容易地被全局异常处理器捕获和处理,从而提供一致的异常处理体验。
public class ForbiddenOperationException extends CommonException {
public ForbiddenOperationException() {
this("禁止操作");
}
public ForbiddenOperationException(String message) {
super(604, message);
}
public ForbiddenOperationException(Throwable throwable, String message) {
super(throwable, 604, message);
}
public ForbiddenOperationException(Throwable throwable) {
super(throwable, 604, "禁止操作");
}
}
查看上方的异常处理机制,他会去寻找是否有全局异常处理器,或控制器中定义的局部异常处理方法(使用@ExceptionHandler注解的方法)来处理这个异常。
关键的两个注解
第一个是@RestControllerAdvice,是一个Spring MVC的注解,它用来定义全局的异常处理逻辑。你可以把它想象成一个“全局异常处理助手”。当你在Spring应用中遇到异常时,这个助手会自动站出来,帮你处理这些异常,而不是让每个控制器(Controller)都去单独处理。
另一个是@ExceptionHandler,这个注解可以理解为:当你使用@ExceptionHandler
注解在一个方法上时,你就告诉Spring:“嘿,当遇到这种类型的异常时,就用这个方法来处理它”。这个方法可以接收异常对象作为参数,并且可以返回一个响应给客户端,比如一个JSON格式的错误信息。
@RestControllerAdvice
@Slf4j
public class CommonExceptionAdvice {
/**
* 自定义异常处理
* @param e
* @return
*/
@ExceptionHandler({CommonException.class})
public Result customException(CommonException e) {
log.error("请求异常,message:{},e", e.getMessage(),e);
// 标识异常已被处理
ResponseUtils.setResponseHeader(BODY_PROCESSED, "1");
if(RequestUtils.getRequest().getRequestURL().toString().contains("/inner/")) {
CommonException commonException = new CommonException(e.getCode(), e.getMessage());
ResponseUtils.setResponseHeader(HeaderConstants.INNER_ERROR, Base64Utils.encodeStr(e.getCode() + "|" + e.getMessage()));
throw commonException;
}
return Result.error(e.getCode(), e.getMessage());
}
/**
* 非自定义异常处理
* @param e 异常
* @return
*/
@ExceptionHandler({Exception.class})
public Result noCustomException(Exception e) {
log.error("请求异常,", e);
// 标识异常已被处理
ResponseUtils.setResponseHeader(BODY_PROCESSED, "1");
if(RequestUtils.getRequest().getRequestURL().toString().contains("/inner/")) {
CommonException commonException = new CommonException(ErrorInfo.Msg.REQUEST_FAILD);
ResponseUtils.setResponseHeader(HeaderConstants.INNER_ERROR, Base64Utils.encodeStr( "500|" + ErrorInfo.Msg.REQUEST_FAILD));
throw commonException;
}
return Result.error(ErrorInfo.Msg.REQUEST_FAILD);
}
}
可能会有疑惑,我抛出的是new ForbiddenOperationException(),异常处理器中没写处理其的方法,也可以处理吗?
那你还记不记得,他继承自CommonException,因为Java的异常处理机制遵循继承原则。如果一个异常是某个特定异常类的实例,或者是这个特定异常类的任何子类的实例,那么任何捕获这个特定异常类(或其父类)的catch
块,或者在这个场景下是Spring MVC中的@ExceptionHandler
方法,都能够处理这个异常。
更多推荐
所有评论(0)