当前位置: 首页 > news >正文

Spring--统一数据返回格式与统一异常处理

1.统一数据返回格式

强制登录案例中, 我们共做了两部分⼯作

1. 通过Session来判断⽤户是否登录

2. 对后端返回数据进⾏封装, 告知前端处理的结果(设置status401等)

回想我们在给前端返回时进行了一个统一的数据包装

@Data
public class Result<T> {private int status;//1.  200成功   2. -1未登录 3. -2  异常private String errorMsg;//错误信息private T data;/*** 登录成功* @param data* @param <T>* @return*/public static <T> Result success(T data) {Result result = new Result();result.setStatus(ResultStatus.SUCCESS.getCode());result.setErrorMsg("");result.setData(data);return result;}/*** 未登录* @return*/public static Result unLogin() {Result result = new Result();result.setErrorMsg("未登录,请登录后访问");result.setStatus(ResultStatus.UNLOGIN.getCode());return result;}/*** 登录失败* @param data* @param <T>* @return*/public static <T> Result fail(String msg) {Result result = new Result();result.setErrorMsg(msg);result.setStatus(ResultStatus.FAIL.getCode());result.setData("");return result;}
}

如果能将返回的数据全部都包装为Result那么代码就更加健壮了(方便后续的添加修改)

参考拦截器,我们肯定不会对原来的方法返回结果直接一个一个修改。

SpringBoot也对此功能进行了支持

使用方法:

统⼀的数据返回格式使⽤ @ControllerAdvice ResponseBodyAdvice 的⽅式实现 

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, 
MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest 
request, ServerHttpResponse response) {return Result.success(body);}
}

 

@ControllerAdvice注解已经包含五大注解,会交给Spring进行管理

这个类有两个方法:supports(),beforeBodyWrite()

supports():判断是否要执⾏beforeBodyWrite⽅法. true为执⾏, false不执⾏

可以通过参数获取类及方法书写逻辑:

    @Overridepublic boolean supports(MethodParameter returnType, Class converterType) {//获取执行方法的类Class<?> declaringClass = returnType.getMethod().getDeclaringClass();//获取执行的方法Method method = returnType.getMethod();//判断是否执行beforeBodyWrite方法   true--执行  false--不执行return true;}

 beforeBodyWrite(): 对response⽅法进⾏具体操作处理

 在这里是将返回数据包装后返回给前端

但是这里如果直接对String进行包装返回会出现错误:

写一个测试类:

@RestController
@RequestMapping("/test")
public class TestController {@RequestMapping("/t1")public String t1() {return "t1";}@RequestMapping("/t2")public Integer t2() {return 2;}@RequestMapping("/t3")public Boolean t3() {return true;}
}

而其他类型不会出现这种情况。出现这种情况是在源码阶段的类型不匹配(这里不进行深究)

解决方法是将返回的Result转换成Spring类型。

         private static ObjectMapper mapper = new ObjectMapper();        if(body instanceof String) {//将result类型转化为String类型   否则在源码阶段会出现类型不匹配return  mapper.writeValueAsString(Result.success(body));}

如果返回的类型就是Result则不用转换,直接返回

        //如果body是Result类型就直接返回if(body instanceof Result) {return body;}

 最终代码:

/*** 统一结果返回*/
@Slf4j
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {private static ObjectMapper mapper = new ObjectMapper();@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {//获取执行方法的类Class<?> declaringClass = returnType.getMethod().getDeclaringClass();//获取执行的方法Method method = returnType.getMethod();//判断是否执行beforeBodyWrite方法   true--执行  false--不执行return true;}@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {//判断body是否是String类型if(body instanceof String) {//将result类型转化为String类型   否则在源码阶段会出现类型不匹配return  mapper.writeValueAsString(Result.success(body));}//如果body是Result类型就直接返回if(body instanceof Result) {return body;}return Result.success(body);}
}

2.统一异常处理

在上一步统一结果返回时,如果类型不匹配,并没有爆出异常(最外层显示200),这是我们不能接收的。

我们当然可以对每一块代码进行trycacth环绕,但同样面临冗余的情况。

解决方法是:统一异常处理

统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的

@ControllerAdvice 控制器通知类(标识作用), @ExceptionHandler 是异常处理器,两个结合表⽰当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件

记得加: @ResponseBody

/*** 统一异常处理*/
//接⼝返回为数据时, 需要加 @ResponseBody 注解
@ControllerAdvice
@ResponseBody
public class ErrorAdvice {@ExceptionHandlerpublic Object handler(Exception e) {return Result.fail(e.getMessage());}
}

如果代码出现Exception异常(包括Exception的⼦类), 就返回⼀个 Result的对象, Result 对象的设置参考 Result.fail(e.getMessage())

    public static <T> Result fail(String msg) {Result result = new Result();result.setErrorMsg(msg);result.setStatus(ResultStatus.FAIL.getCode());result.setData("");return result;}

当然,只能爆Exception这么宽泛的异常就没有意义了

我们可以针对不同的异常, 返回不同的结果

@ExceptionHandlerpublic Object handler(Exception e) {return Result.fail(e.getMessage());}//空指针异常@ExceptionHandlerpublic Object handler(NullPointerException e) {return Result.fail(e.getMessage());}//算数异常@ExceptionHandlerpublic Object handler(ArithmeticException e) {return Result.fail(e.getMessage());}

现在我们在测试类中添加两个异常观察一下:

    @RequestMapping("/t1")public String t1() {String s = "1";char a = s.charAt(2);return "t1";}@RequestMapping("/t2")public Integer t2() {int s = 10/0;return 2;}

它会抛出距离最近的异常

针对不同的异常, 返回不同的结果还有一种写法:

    //算数异常@ExceptionHandler(ArithmeticException.class)public Object handler1(Exception e) {return Result.fail(e.getMessage());}@ExceptionHandler(NullPointerException.class)public Object handler2(Exception e) {return Result.fail(e.getMessage());}@ExceptionHandler(Exception.class)public Object handler3(Exception e) {return Result.fail(e.getMessage());}

将异常加在注解中

相关文章:

  • 将 MySQL 8 主从复制延迟优化到极致
  • 如何在iStoreOS DHCP中排除特定IP地址
  • zkPass案例实战之合约篇
  • 【论文#目标检测】Attention Is All You Need
  • 【泊松过程和指数分布】
  • 力扣DAY63-67 | 热100 | 二分:搜索插入位置、搜索二维矩阵、排序数组查找元素、搜索旋转排序数组、搜索最小值
  • OpenCV 图形API(52)颜色空间转换-----将 NV12 格式的图像数据转换为 RGB 格式的图像
  • 计算机视觉基础
  • 提高Spring Boot开发效率的实践
  • MsQuick编译和使用
  • c++概念——模板的进阶讲解
  • django软件开发招聘数据分析与可视化系统设计与实现(源码+lw+部署文档+讲解),源码可白嫖!
  • 香港科技大学广州|金融科技学域博士招生宣讲会—南开大学专场
  • ThinkPHP快速使用手册
  • VUE的创建
  • 【C语言】文本操作函数fgetc、fputc、fgets、fputs、fprintf、fscanf、fread、fwrite
  • 【Linux应用】RADXA ZERO 3快速上手:镜像烧录、串口shell、外设挂载、WiFi配置、SSH连接、文件交互
  • JavaEE学习笔记(第二课)
  • linux磁盘挂载
  • 【25软考网工】第三章(2)以太网帧结构与封装、以太网物理层标准
  • 上海车展上的双向奔赴:跨国车企融入中国创新,联手“在中国,为全球”
  • 复旦大学校友夫妇一次性捐赠10亿元,成立学敏高等研究院
  • 王励勤当选中国乒乓球协会新一任主席
  • 匈牙利总理投票反对乌克兰加入欧盟
  • 中国墨西哥商会副执行主席:深耕中国市场18年,对未来充满信心
  • 马文化体验展商圈启动,环球马术冠军赛的能量不止在赛场