SpringBoot-@ControllerAdvice中获取泛
2020-01-22 本文已影响0人
dothetrick
1.这个需求的背景
不知大家项目是否碰到过这个场景:
作为一个后端开发,你提供了十几个不同的api给前端调用,联调的时候突然发现,新来的前端妹子没有在返回值展示时做非null判断,所有异常时要展示0或空字符的值,都要你按完整结构返回,而不是只返回空结构,前端自己填默认值。返回空js就会报错。。。
例如下面这个返回值,异常时要返回这个:
{
"code": 1000,
"data": {
"fwzy": 0,
"yyfz": 0,
"yyzg": "",
}
}
ok,这个时候你是跟老大反馈呢?还是要前端妹子加班改?
作为一个有追求的程序员,为了项目进度,当然是想个最简单的修改方案,那么思路如下:
- 通常web api项目中,都会使用
@ControllerAdvice
统一处理抛出的异常,然后返回错误信息。-
controller
一般会定义一个通用返回类,实际的返回值用泛型标识 - 例如这样:
-
import lombok.Data;
@Data
public class CommonResVo<T> {
private Integer code;
private String info;
private T data;
}
- 如果异常时要保持返回的字段完整,就需要在统一异常处理中根据返回的泛型,创建实际的对象,然后返回。
2. @ControllerAdvice中如何获取返回的实际类型呢?
- 使用@ExceptionHandler注解的方法,可以使用参数类型为
org.springframework.web.method.HandlerMethod
的参数获取要处理的类的对象 - 这里的原理是
- mvc中检测到Controller抛出的异常后,会通过
org.springframework.web.servlet.DispatcherServlet#processHandlerException
进行处理,该函数的定义如下:
- mvc中检测到Controller抛出的异常后,会通过
protected ModelAndView processHandlerException(HttpServletRequest request,
HttpServletResponse response,
@Nullable Object handler,
Exception ex) throws Exception;
- 处理时会根据对应参数的类型载入参数并调用异常处理方法。
- 这里有一个注意点
- 当
@ExceptionHandler
修饰的方法的参数中,有类型获取不到的,则这个处理函数不会被触发,相当于没有异常处理了。这个一定要注意。
- 当
3. 完整示例
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 统一异常处理
*
* @param var1
* @param var2
* @param handlerMethod //抛出异常的controller类
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public CommonResVo handleException(HttpServletRequest var1, HttpServletResponse var2, HandlerMethod handlerMethod, Exception e) {
logger.error("Exception " + e.getMessage());
Object data = new Object();
//业务需求,不返回错误,记录异常,返回空对象
try {
//获取方法返回类型中,CommonResVo中的泛型对象
String typeName = ((ParameterizedType) handlerMethod.getMethod().getGenericReturnType()).getActualTypeArguments()[0].getTypeName();
data = Class.forName(typeName).newInstance();
} catch (Exception ex) {
logger.error("获取返回值中泛型类对象失败");
}
CommonResVo result = new CommonResVo();
result.setCode(1000);
result.setData(data);
return result;
}
以上内容属个人学习总结,如有不当之处,欢迎在评论中指正