Spring--同一数据返回格式与同一非常处理处罚

[复制链接]
发表于 2025-9-22 00:46:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
1.同一数据返回格式

欺压登录案例中, 我们共做了两部分⼯作
1. 通过Session来判断⽤户是否登录
2. 对后端返回数据进⾏封装, 告知前端处理处罚的结果(设置status401等)
回想我们在给前端返回时举行了一个同一的数据包装
  1. @Data
  2. public class Result<T> {
  3.     private int status;//1.  200成功   2. -1未登录 3. -2  异常
  4.     private String errorMsg;//错误信息
  5.     private T data;
  6.     /**
  7.      * 登录成功
  8.      * @param data
  9.      * @param <T>
  10.      * @return
  11.      */
  12.     public static <T> Result success(T data) {
  13.         Result result = new Result();
  14.         result.setStatus(ResultStatus.SUCCESS.getCode());
  15.         result.setErrorMsg("");
  16.         result.setData(data);
  17.         return result;
  18.     }
  19.     /**
  20.      * 未登录
  21.      * @return
  22.      */
  23.     public static Result unLogin() {
  24.         Result result = new Result();
  25.         result.setErrorMsg("未登录,请登录后访问");
  26.         result.setStatus(ResultStatus.UNLOGIN.getCode());
  27.         return result;
  28.     }
  29.     /**
  30.      * 登录失败
  31.      * @param data
  32.      * @param <T>
  33.      * @return
  34.      */
  35.     public static <T> Result fail(String msg) {
  36.         Result result = new Result();
  37.         result.setErrorMsg(msg);
  38.         result.setStatus(ResultStatus.FAIL.getCode());
  39.         result.setData("");
  40.         return result;
  41.     }
  42. }
复制代码
假如能将返回的数据全部都包装为Result那么代码就更加结实了(方便后续的添加修改)
参考拦截器,我们肯定不会对原来的方法返回结果直接一个一个修改。
SpringBoot也对此功能举行了支持
使用方法:
统⼀的数据返回格式使⽤ @ControllerAdvice 和 ResponseBodyAdvice 的⽅式实现 
  1. @ControllerAdvice
  2. public class ResponseAdvice implements ResponseBodyAdvice {
  3. @Override
  4. public boolean supports(MethodParameter returnType, Class converterType) {
  5. return true;
  6. }
  7. @Override
  8. public Object beforeBodyWrite(Object body, MethodParameter returnType,
  9. MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest
  10. request, ServerHttpResponse response) {
  11. return Result.success(body);
  12. }
  13. }
复制代码
 
@ControllerAdvice注解已经包罗五大注解,会交给Spring举行管理
这个类有两个方法:supports(),beforeBodyWrite()
supports():判断是否要执⾏beforeBodyWrite⽅法. true为执⾏, false不执⾏
可以通过参数获取类及方法誊写逻辑:
  1.     @Override
  2.     public boolean supports(MethodParameter returnType, Class converterType) {
  3.         //获取执行方法的类
  4.         Class<?> declaringClass = returnType.getMethod().getDeclaringClass();
  5.         //获取执行的方法
  6.         Method method = returnType.getMethod();
  7.         //判断是否执行beforeBodyWrite方法   true--执行  false--不执行
  8.         return true;
  9.     }
复制代码
 beforeBodyWrite(): 对response⽅法进⾏详细操纵处理处罚
 在这里是将返回数据包装后返回给前端
但是这里假如直接对String举行包装返回会出现错误:
写一个测试类:
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4.     @RequestMapping("/t1")
  5.     public String t1() {
  6.         return "t1";
  7.     }
  8.     @RequestMapping("/t2")
  9.     public Integer t2() {
  10.         return 2;
  11.     }
  12.     @RequestMapping("/t3")
  13.     public Boolean t3() {
  14.         return true;
  15.     }
  16. }
复制代码

而其他范例不会出现这种环境。出现这种环境是在源码阶段的范例不匹配(这里不举行穷究)
解决方法是将返回的Result转换成Spring范例。
  1.          private static ObjectMapper mapper = new ObjectMapper();        
  2.          if(body instanceof String) {
  3.             //将result类型转化为String类型   否则在源码阶段会出现类型不匹配
  4.             return  mapper.writeValueAsString(Result.success(body));
  5.         }
复制代码
假如返回的范例就是Result则不消转换,直接返回
  1.         //如果body是Result类型就直接返回
  2.         if(body instanceof Result) {
  3.             return body;
  4.         }
复制代码
 最终代码:
  1. /** * 同一结果返回 */@Slf4j@ControllerAdvicepublic class ResponseAdvice implements ResponseBodyAdvice {    private static ObjectMapper mapper = new ObjectMapper();
  2.     @Override
  3.     public boolean supports(MethodParameter returnType, Class converterType) {
  4.         //获取执行方法的类
  5.         Class<?> declaringClass = returnType.getMethod().getDeclaringClass();
  6.         //获取执行的方法
  7.         Method method = returnType.getMethod();
  8.         //判断是否执行beforeBodyWrite方法   true--执行  false--不执行
  9.         return true;
  10.     }    @SneakyThrows    @Override    public 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));        }
  11.         //如果body是Result类型就直接返回
  12.         if(body instanceof Result) {
  13.             return body;
  14.         }        return Result.success(body);    }}
复制代码
2.同一非常处理处罚

在上一步同一结果返回时,假如范例不匹配,并没有爆出非常(最外层显示200),这是我们不能吸取的。
我们固然可以对每一块代码举行trycacth围绕,但同样面对冗余的环境。
解决方法是:同一非常处理处罚
统⼀非常处理处罚使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的
@ControllerAdvice 控制器关照类(标识作用), @ExceptionHandler 是非常处理处罚器,两个团结表⽰当出现非常的时间执⾏某个关照,也就是执⾏某个⽅法变乱
记得加: @ResponseBody
  1. /**
  2. * 统一异常处理
  3. */
  4. //接⼝返回为数据时, 需要加 @ResponseBody 注解
  5. @ControllerAdvice
  6. @ResponseBody
  7. public class ErrorAdvice {
  8.     @ExceptionHandler
  9.     public Object handler(Exception e) {
  10.         return Result.fail(e.getMessage());
  11.     }
  12. }
复制代码
假如代码出现Exception非常(包罗Exception的⼦类), 就返回⼀个 Result的对象, Result 对象的设置参考 Result.fail(e.getMessage())
  1.     public static <T> Result fail(String msg) {
  2.         Result result = new Result();
  3.         result.setErrorMsg(msg);
  4.         result.setStatus(ResultStatus.FAIL.getCode());
  5.         result.setData("");
  6.         return result;
  7.     }
复制代码
固然,只能爆Exception这么宽泛的非常就没有意义了
我们可以针对差别的非常, 返回差别的结果
  1. @ExceptionHandler
  2.     public Object handler(Exception e) {
  3.         return Result.fail(e.getMessage());
  4.     }
  5.     //空指针异常
  6.     @ExceptionHandler
  7.     public Object handler(NullPointerException e) {
  8.         return Result.fail(e.getMessage());
  9.     }
  10.     //算数异常
  11.     @ExceptionHandler
  12.     public Object handler(ArithmeticException e) {
  13.         return Result.fail(e.getMessage());
  14.     }
复制代码
如今我们在测试类中添加两个非常观察一下:
  1.     @RequestMapping("/t1")
  2.     public String t1() {
  3.         String s = "1";
  4.         char a = s.charAt(2);
  5.         return "t1";
  6.     }
  7.     @RequestMapping("/t2")
  8.     public Integer t2() {
  9.         int s = 10/0;
  10.         return 2;
  11.     }
复制代码


它会抛出隔断最近的非常
针对差别的非常, 返回差别的结果尚有一种写法:
  1.     //算数异常
  2.     @ExceptionHandler(ArithmeticException.class)
  3.     public Object handler1(Exception e) {
  4.         return Result.fail(e.getMessage());
  5.     }
  6.     @ExceptionHandler(NullPointerException.class)
  7.     public Object handler2(Exception e) {
  8.         return Result.fail(e.getMessage());
  9.     }
  10.     @ExceptionHandler(Exception.class)
  11.     public Object handler3(Exception e) {
  12.         return Result.fail(e.getMessage());
  13.     }
复制代码
将非常加在注解中

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表