V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
dreamramon
V2EX  ›  问与答

求教 Java 里面用 gson 来解析 变化的 api 响应 的比较好的写法。。。

  •  
  •   dreamramon · 2022-08-25 11:47:00 +08:00 · 1252 次点击
    这是一个创建于 839 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目里面一直在用 gson 来序列化对象,最近在接一家第三方 api 。

    如果请求出错,对方响应类似:

    {"code":-1021,"msg":"Timestamp for this request is outside of the recvWindow."}
    

    请求正确,对方响应:

    {
    	"feeTier": 0,
    	"updateTime": 0,
    	"assets": [{
    		"asset": "XXX",
    		"updateTime": 0
    	}],
    	"positions": [{
    		"symbol": "XXX",
    		"initialMargin": "0",
    		"maintMargin": "0"
    	}]
    }
    

    我自己构造了 2 个对象的 Pojo ,一个是 ResponseError ,一个是 Response

      if( httpResponse.contains("code\":-1021")){
                ResponseError resp = GSON.fromJson( httpResponse, ResponseError.class);
            }else{
                Response resp = GSON.fromJson( httpResponse, Response.class);
            }
      
    

    不知道有没有更好的写法,能够定义一个更好的: 1 ,让我能够不先用 string 来判断。。。 2 ,最好 2 个响应的序列化的对象可以怎样继承一下,统一的返回给上层。。。

    13 条回复    2022-08-26 17:18:21 +08:00
    qping
        1
    qping  
       2022-08-25 13:12:35 +08:00
    正则先 match 下?
    JxQg597
        2
    JxQg597  
       2022-08-25 13:18:57 +08:00
    对方的返回接口不标准,你的接受实体也没办法标准化抽象。
    1.用一个 Response 接收返回值,包含错误响应的 code,msg ,也包含正确响应的所有返回值。
    2.响应直接解析成 Response ,并作解析异常捕获,并抛出异常信息。
    3.根据 code 是否为 null 来判断请求是否错误,并抛出异常信息。
    4.最后直接 return Response
    bk201
        3
    bk201  
       2022-08-25 13:29:45 +08:00
    直接解析 json object 通过 path 拿自己需要的值,放入自己定义的标准 vo 里,返回给内部使用者
    superliy
        4
    superliy  
       2022-08-25 13:38:24 +08:00
    把出错的请求字段放到 abstract response 里,其他正确的 response 继承,这样都只要返回 response 就行,使用时判断 code
    jiajianjava
        5
    jiajianjava  
       2022-08-25 13:48:09 +08:00
    {
    "code":200,
    "msg": "",
    "feeTier": 0,
    "updateTime": 0,
    "assets": [{
    "asset": "XXX",
    "updateTime": 0
    }],
    "positions": [{
    "symbol": "XXX",
    "initialMargin": "0",
    "maintMargin": "0"
    }]
    }

    直接合并,定义这样是不是就好了?
    dreamramon
        6
    dreamramon  
    OP
       2022-08-25 14:05:34 +08:00
    @jiajianjava #5
    @JxQg597 #2
    主要是他正确的响应,他有几十个 api ,就有几十个格式。。。
    我们现在有 ResponseError.class, ResponseA.class, ResponseB.class
    然后有的时候,因为对方 api 不稳定,请求有需要重试。。。
    以前,只需要在我们封装的 HttpUtil 里面根据网络状态或者 http 状态码自动重试,业务层不操心了。。。

    但是现在这家,需要在业务层重试。。。所以说,想能不能有个统一的手段,能解析成一个 response ,然后根据里面某个值的判断,再分开能拿到 ResponseA 或者 ResponseB 。
    fgwmlhdkkkw
        7
    fgwmlhdkkkw  
       2022-08-25 14:54:23 +08:00
    try,catch
    JxQg597
        8
    JxQg597  
       2022-08-25 15:24:04 +08:00
    @dreamramon #6
    ```java
    class ResponseBase{
    String code,
    String msg
    }
    class XXXResponse extends ResponseBase{
    xxx,
    xxx,
    xxx
    }
    XXXResponse getXXX(AtomicInteger retriesNum){
    if (retriesNum==null ) retriesNum = new AtomicInteger(0);
    XXXResponse response = doGet();
    if(response.getcode !=null){
    log.error;
    int currentNum = retriesNum.getAndIncrement();
    if(currentNum>configRetriesNum) throw Exception;
    #需要延迟 sleep?
    return getXXX(retriesNum);
    }
    return response ;
    }
    ```
    JNotEnoughW
        9
    JNotEnoughW  
       2022-08-25 15:43:16 +08:00
    自己包装一层转换器,提前校验是否有 "code",组装成统一格式返回
    {
    "code":200,
    "msg":"",
    "data":xxx
    }
    sunjiayao
        10
    sunjiayao  
       2022-08-25 15:48:19 +08:00
    https://gist.github.com/sunluman/b49e12aa3e4f76390fbc08504ef38345
    只能通过有哪些 key 来区分用什么实体类型?可以先类似这样封装下,然后怒喷下对面
    oneisall8955
        11
    oneisall8955  
       2022-08-25 23:15:02 +08:00 via Android
    造轮子的时间到了,最近对接某平台也这样,不过会有固定 code 表示请求失败和正确
    dreamramon
        12
    dreamramon  
    OP
       2022-08-26 16:30:52 +08:00
    @JxQg597 #8

    谢谢大神。。。我的想法是有没有可能,可以写一个统一的父累。

    Response resp = GSON.fromJson( httpResponse, Response.class);
    然后 return 这个 resp 给到业务的方法,然后业务的方法拿到了这个 resp ,可以根据里面的 code 来判断是否出错,并且解析出自己的 ResponseA ,或者 ResponseB?

    比如:
    业务 A:
    if (resp.code==null) {
    ResponseA respA= (ResponseA) resp.data;

    }else if (resp.code == -1021) {
    //retry logic
    }


    业务 B:

    业务 A:
    if (resp.code==null) {
    ResponseB respB= (ResponseB) resp.data;

    } else if (resp.code == -1021) {
    //业务 B -1021 不重试
    } else if (resp.code == -1001) {
    //业务 B -1001 重试,下面自己实现重试逻辑
    }
    JxQg597
        13
    JxQg597  
       2022-08-26 17:18:21 +08:00
    @dreamramon #12 可以参考 9 楼的做法,做成标准 Response<T>,解析两次 Json ,需要用到泛型。
    ```java
    Class Response<T>{
    private String code;
    private String msg;
    private T data;
    public Response<T>(T data){
    this.data = data;
    }
    }
    public <T> Response<T> invokeGet(XXXQuery query, Class<T> tClass){
    try{
    String responseJson = doGet(query);
    Response response = JSONUtil.toBean(responseJson,Response.class);
    if(StrUtil.isNotEmpty(response.getCode())){
    return response;
    }
    T datd = JSONUtil.toBean(responseJson,tClass);
    return new Response<T>(data);
    }catch(AnyException e){
    log.error;
    throw new BussniessException();
    }
    }
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5374 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 02:55 · PVG 10:55 · LAX 18:55 · JFK 21:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.