SpringBoot基础之统一数据格式返回

1,501 阅读4分钟

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

前言

  1. 在正常的开发过程中,因为前端展示的界面多种多样,所以数据会有各种各样的结构,如果后台对数据不加封装的情况下,数据格式就会千奇百怪,最终会降低开发效率,因此需要统一格式.
  2. 在程序发生异常的情况下, 异常信息提示的格式,很大程度上也和正常返回不一致(和全局异常处理一起阅读更佳),所以需要统一格式
  3. 在业务进行中,有些接口请求成功,但是因为业务需要,需要返回一些特殊的状态,在统一了数据格式之后,前端可以在请求入口对这些状态统一的处理.所以需要统一格式

和全局异常处理一起阅读更佳

实现思路

  1. 在项目我我们常常封装一个返回对象类,在类中定义好标准的数据格式.

    正常情况下,我们会将定义三个参数code,msg,data.

    data用于存防业务数据,

    code用来展示统一定义的状态码

    msg用来展示一些基础的成功或者失败信息

  2. 也会创建一个状态码枚举类,类似这样

public enum  ResultCode {

   SUCCESS(200,"操作成功"),

   NO_LOGIN(301,"请重新登录"),
   NO_AUTH(302,"您还没有此功能的权限"),
   NO_UPDATE_DATA(303,"该数据不能操作"),
   NOT_ACCESS(304,"禁止访问"),

   FAIL(5000,"操作失败,请联系管理员"),
 
   CUSTOM_FAIL(5001,"自定义错误")
   
   //等等等
   ;

   private int code;
   private String msg;

   public int code(){
       return this.code ;
   }
   public String msg(){
       return this.msg ;
   }

   ResultCode(int code, String msg) {
       this.code = code;
       this.msg = msg;
   }
}

一般对于中小型公司的中小型项目,正常的状态和异常的状态各个定义一个就好,全靠msg展示信息是没问问题的, 如果有问题的话就去看alibaba出品的java规范.

返回数据的多种实现

(1) Object接收各种数据

public class R implements Serializable {

   private int code;
   private String msg;
   private Object data ;

   private R() {}
   private R(ResultCode resultCode, String msg) {
       this.code = resultCode.code();
       this.msg = msg;
   }

   /***
    * 操作成功,当参数为1个,则将数据直接指向data字典, 当 参数为偶数个时,将单数参数设置为Map的key,每个随后的参数设置为Value
    */
   public static R ok(Object... data){
       R resultVo =  new R(200,"操作成功");
       resultVo.data =integrationData(data);
       return resultVo;
   }


   /***
    * 自定义异常,需要返回异常信息
    */
   public static R fail(String failMsg, Object... data){
       R resultVo = new R(5000,failMsg);
       resultVo.data =integrationData(data);
       return resultVo;
   }

   //.... 只包含基本的,各种变种没有写...

   /***
    * 将返回参数整理到data中
    * @param data
    * @return
    */
   private static Object integrationData(Object... data){
   
       if(data==null||data.length==0){  return null;   }
       
       int length = data.length;
       
       if(length==1){   return data[0];   }
       
       if(length %2 ==1){
           throw new RuntimeException("返回结果参数数量不正确,应该为偶数,实际为:"+length);
       }
       if(length %2 ==0){
           HashMap<Object, Object> map = new HashMap<>();
           for (int i = 0; i < length; i+=2) {
               map.put(data[i],data[i+1]);
           }
           return map;
       }
       return "";
   }

}

使用方式

R.OK("数据1");
R.OK("数据1","KEY2","数据2");

或许你看到的是这种,这种如果存在多个数据,只能手动创建一个Map然后将数据放到data中

public class R<T> implements Serializable {
    private int code;
    private String msg;
    private T data ;
}

(2) Map接收数据

public class R extends HashMap<String, Object>{

    public R() {
        put("code", 0);
        put("msg", "操作成功");
    }

    public static R error(String msg) {
        return error(5000, msg);
    }
    public static R error(int code, String msg) {
        R r = new R();
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }

    public static R ok() {
        return new R();
    }
    public static R ok(String msg) {
        R r = new R();
        r.put("msg", msg);
        return r;
    }

    public static R ok(Map<String, Object> map) {
        R r = new R();
        r.putAll(map);
        return r;
    }

    public static R ok(Object data) {
        return new R().put("data",data);
    }

    @Override
    public R put(String key, Object value) {
        super.put(key, value);
        return this;
    }

}

这种数据格式就是利用了map来做返回对象,可以想map一样操作他

R.OK("数据1");
R.OK("数据1").put("KEY2","数据2");

(3) 实现ResponseBodyAdvice并注解@RestControllerAdvice

这种方法比较少见,并且在实际使用过程中,如果沟通不畅出现问题的几率是比较大的

@RestControllerAdvice
public class MyResponseAdvice implements ResponseBodyAdvice<Object> {
 
   //开启支持
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    //处理封装数据
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //处理指定类型的数据
        if(o instanceof String){
          R.ok(o)
        }
        //更多的处理方式
        return o;
    }
}

这个的使用方式就是;在cotroller想怎么写就怎么写,在MyResponseAdvice会自动封装.

配合全局异常处理需要做的地方

详见指定文章的指定两个部分:

1.拦截404或者服务器错误等未进入controller的异常

2.filter等自定义代码中异常

    作者:ZOUZDC
    链接:https://juejin.cn/post/7028963866063306760
    来源:稀土掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。