自定义异常
在Service中处理业务时,如果操作失败,应该抛出异常,并且应该抛出自定义异常,避免与原有的其他异常在同一个业务中出现而导致无法区分失败的原因!
通常情况下,自定义异常应该继承RuntimeExcption,其主要原因是:
- 所有的RuntimeException不会受到try...catch或throw/throws语法的约束,更适合结合Spring MVC框架统一处理异常机制来处理
- 基于Spring JDBC的事物管理,默认将基于RuntimeException进行回滚
在开发实践中,同一个业务可能存在多种“失败”的可能,以“登录账号”为例,导致失败的原因有:
- 用户名不存在
- 密码错误
- 账号被冻结
- 其他
为了区分这些不同的失败,了解失败的原因,可以:
- 为每一种失败都创建一个异常类
- 使用同一个异常类,对不同的失败使用携带了不同信息的对象
一般采用第2种方式,在自定义异常类中添加带String message参数的构造方法,并在构造方法中调用父类的同参数的构造方法。
public class ServiceException extends RuntimeException{
public ServiceException(String message){
super(message);
}
}
则抛出异常时,必须封装异常信息的描述文本,例如
if (count > 0) {
String message = "添加用户失败,用户名已经存在";
log.debug("message");
throw new ServiceException(message);
}
处理异常
在服务端项目中,如果某个抛出的异常始终没有被处理,则默认会向客户端响应500错误(HTTP状态码为500)。
在服务端的项目中,必须对异常进行处理,如果不处理,软件的使用者可能不清除是因为什么原因出现异常,也不知道如何调整参数来解决这个问题。如果用户反复提交错误的请求,对于服务器而言,也浪费了一些性能。所以处理异常变着尤为重要。
Spring MVC框架提供了统一处理异常的机制,对于每种类型的异常,只需要编写1段相关的处理代码即可。
当使用这种机制时,在控制器类的个处理请求的方法中,将不使用try...catch语句来包裹可能抛出异常的办法并处理,则控制器类中各处理请求的方法抛出的异常,都会被Spring MVC框架捕获并尝试调用统一处理异常的方法。
关于统一处理异常的方法:
- 注解:必须添加@ExceptionHandler注解
- 访问权限:应该使用public
- 返回值类型:需要什么类型的数据就返回什么类型的数据
- 方法名称:自定义
- 参数列表:必须有1个异常类型的参数,表示Spring MVC框架调用处理请求的方法时捕获到的异常,并且按需添加HttpServletRequest、HttpServletResponse等少量特定类型的参数,不可以随意添加其他参数
通常,我们会将统一异常的代码定义在专门的类中,并在此类上添加@RestControllerAdvice注解,添加了此注解的类中的特定方法将作用于整个项目任何处理请求的方法的过程
import cn.tedu.csmall.product.ex.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常处理器
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
public GlobalExceptionHandler() {
log.debug("创建全局异常处理器对象:GlobalExceptionHandler");
}
@ExceptionHandler
public String handleServiceException(ServiceException e) {
log.debug("处理请求的方法抛出了ServiceException,将统一处理");
return e.getMessage();
}
}
有了上述类之后,任何处理请求的方法对于ServiceException都应该是抛出,且各控制器类中都不关心如何处理SeviceException,会由以上方法进行处理!