1、异常的类型:
首先,我们明白异常分为
可预知异常(如空指针)
和
不可预知异常(如数据库连接异常)
:
- 其中,可预知异常由我们主动抛出,由SpringMVC统一捕获;
- 而不可预知异常有SpringMVC统一捕获Exception类型的异常;
而所谓异常统一捕获处理就是将可预知异常和不可预知异常
采用统一的信息格式
来表示,并且随请求响应给客户端。这样我们就可以
避免大量使用try/catch而导致的代码冗余
,
区别具体的错误信息
。
2、可预知异常实现:
下面就来讲讲如何实现可预知异常异常统一处理:
-
1、首先我们需要定义一个自定义异常类去继承RuntimeException类:
注:1、使用RuntimeException类而不使用Exception类是因为RuntimeException类不具有侵入性,即当我们使用throw new RuntimeException()时不需要进行异常捕获,也不需要进行异常声明;
2、ResultCode为异常信息(code,success,错误信息)的接口,由多个子类异常对象实现
/**
* 自定义异常类型
* @author LR
* @version 1.0
**/
public class CustomException extends RuntimeException {
//错误代码
ResultCode resultCode;
public CustomException(ResultCode resultCode){
this.resultCode = resultCode;
}
//得到错误对象
public ResultCode getResultCode(){
return resultCode;
}
}
-
2、定义一个异常抛出类:
这样我们就可以使用Exception.cast(ResultCode子类对象(异常信息对象))来抛出异常,也不会对代码有侵入性;
/**
* @className ExceptionCast
* @Description 异常抛出类
* @Author RJin
* @Date 2020/3/25 14:47
* @Version 1.0
*/
public class ExceptionCast {
//使用静态方法抛出自定义异常
public static void cast(ResultCode resultCode){
throw new CustomException(resultCode);
}
}
-
3、定义统一异常捕获类:
这样我们的客户端就可以拿到异常信息了
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* @className ExceptionCatch
* @Description 异常捕获类
* @Author RJin
* @Date 2020/3/25 14:51
* @Version 1.0
*/
@ControllerAdvice //代表控制器增强,只要使用@ExceptionHandler(指定异常类)捕获相对应的异常类,就会进入指定的方法
public class ExceptionCatch {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatch.class);
//捕获我们自定义的可预知异常CustomException
@ExceptionHandler(CustomException.class)
@ResponseBody //将返回的错误信息转换为json数据格式
public ResponseResult customException(CustomException customException){
//记录日志
LOGGER.error("catch exception:{}",customException.getMessage());
ResultCode resultCode = customException.getResultCode(); //获得异常信息对象
return new ResponseResult(resultCode); //请求信息的返回封装
}
}
3、不可预知异常实现:
思路流程:在Map集合中定义异常类型对应的错误代码和错误信息,如果在Map中找到了该异常我们就将该异常对应的错误信息返回,如果没有找到,就统一返回不可预知异常(如{code: 1888, success: true, message: “未知异常”})。
实现步骤:
-
在统一异常捕获类中定义一个ImmutableMap(google工具包中的一个Map类型,数据一旦放入该Map,将不可更改,并且该Map线程安全),其中该Map的键为Throwable的子类泛型,值为ResultCode。
private static ImmutableMap<Class<? extends Throwable>,ResultCode> EXCEPTIONS;
-
定义一个ImmutableMap的builder对象,去构建ImmutableMap:
protected static ImmutableMap.Builder<Class<? extends Throwable>,ResultCode> builder = ImmutableMap.builder();
-
定义一个static静态代码块,在builder对象中put添加异常类型对应的错误代码:
static { builder.put(HttpMessageNotReadableException.class, CommonCode.FAIL); }
-
再在统一异常捕获类中定义一个捕获Exception类的异常捕获方法:
//捕获Exception此类异常 @ExceptionHandler(Exception.class) @ResponseBody //将返回的错误信息转换为json数据格式 public ResponseResult exception(Exception exception){ //记录日志 LOGGER.error("catch exception:{}",exception.getMessage()); if (EXCEPTIONS == null){ //如果EXCEPTIONS等于空,证明EXCEPTIONS还未构建,执行EXCEPTIONS的构建方法 builder.build();//EXCEPTIONS构建方法 } //从EXCEPTIONS中找到异常类型所对应的错误代码,如果找到了将错误代码响应给用户,如果找不到给用户响应统一返回不可预知异常 ResultCode resultCode = EXCEPTIONS.get(exception.getClass()); if (resultCode != null){ return new ResponseResult(resultCode); //请求信息的返回封装 }else { return new ResponseResult(CommonCode.SERVER_ERROR); //请求信息的返回封装 } }
这样,我们的不可预知异常也实现了异常统一处理。
以上,就是对异常进行统一捕获处理。