Java如何用一个统一结构接收成员名称不固定的数据

 更新时间:2024年11月29日 16:09:30   作者:mzlogin  
这篇文章主要为大家详细介绍了Java如何用一个统一结构接收成员名称不固定的数据,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

本文介绍了一种 Java 中如何用一个统一结构接收成员名称不固定的数据的方法。

背景

最近在做企业微信的内部应用开发,遇到了一个小问题:企业微信的不同接口,返回的数据的结构不完全一样。

比如,获取部门列表接口返回的数据结构是这样的:

{
    "errcode": 0,
    "errmsg": "ok",
    "department": [
        {
            "id": 2,
            "name": "广州研发中心",
            "name_en": "RDGZ",
            "department_leader":["zhangsan","lisi"],
            "parentid": 1,
            "order": 10
        }
    ]
}

而获取部门成员接口返回的数据结构是这样的:

{
    "errcode": 0,
    "errmsg": "ok",
    "userlist": [
        {
            "userid": "zhangsan",
            "name": "张三",
            "department": [1, 2],
            "open_userid": "xxxxxx"
        }
    ]
}

就是说,不同接口的返回框架是一样的,都是 errcode + errmsg + 数据部分,但数据部分的成员名称不一样,比如上面的 department 和 userlist

我不知道为什么这样设计,从 Java 开发者的习惯来讲,如果由我来设计,我会尽量保持接口返回的数据结构的一致性,比如数据部分都用 data 来表示,这样在序列化、反序列化的时候可以用一个统一的泛型结构来进行。

当然这可能是企微内部的开发语言或习惯的差异,或者其它原因,这里也无法深究,只谈如何应对。

分析

遇到这个问题后,第一反应是用 JSON 结构来接收,然后不同接口的数据部分用不同的 key 来读取。可以实现,但总觉得不够优雅。

然后想到 GitHub 上应该有不少开源的企微开发的封装库,去看看它们的实现,说不定会有更好的方案,最终果然有收获。

主要看了两个库:

前者 WxJava 知名度更高,包含的东西也更多,包含微信、企微的各种开发包的封装。它这块的实现是用我们前面提到的方法,用 JSON 结构来接收,然后不同接口的数据用不同的 key 来读取。

后者 wecom-sdk 是企微的开发包。它这块的实现是用了一个统一的泛型结构来接收数据。

以下分别截取两个库的两个部门管理相关接口的封装代码:

WxJava 版:

github.com/binarywang/WxJava/blob/develop/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java

@Override
public List<WxCpDepart> list(Long id) throws WxErrorException {
    String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST);
    if (id != null) {
      url += "?id=" + id;
    }

    String responseContent = this.mainService.get(url, null);
    JsonObject tmpJsonObject = GsonParser.parse(responseContent);
    return WxCpGsonBuilder.create()
      .fromJson(tmpJsonObject.get("department"),
        new TypeToken<List<WxCpDepart>>() {
        }.getType()
      );
  }

@Override
public List<WxCpDepart> simpleList(Long id) throws WxErrorException {
    String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_SIMPLE_LIST);
    if (id != null) {
      url += "?id=" + id;
    }

    String responseContent = this.mainService.get(url, null);
    JsonObject tmpJsonObject = GsonParser.parse(responseContent);
    return WxCpGsonBuilder.create()
      .fromJson(tmpJsonObject.get("department_id"),
        new TypeToken<List<WxCpDepart>>() {
        }.getType()
      );
  }
}

wecom-sdk 版:

github.com/NotFound403/wecom-sdk/blob/release/wecom-sdk/src/main/java/cn/felord/api/DepartmentApi.java

@GET("department/list")
GenericResponse<List<DeptInfo>> deptList(@Query("id") long departmentId) throws WeComException;

@GET("department/simplelist")
GenericResponse<List<DeptSimpleInfo>> getSimpleList(@Query("id") long departmentId) throws WeComException;

抛开 wecom-sdk 版引入了 Retrofit2 库的支持导致的代码量锐减,在返回数据的反序列化上,我也更倾向于 wecom-sdk 版的实现。

实现

那接下来我们直接参照 wecom-sdk 里的实现方式,写一个泛型类,就可以用来接收企微的不同接口返回的数据了:

@Data
public class WxWorkResponse<T> {

    @JsonProperty("errmsg")
    private String errMsg;

    @JsonProperty("errcode")
    private Integer errCode;

    @JsonAlias({
            "department",
            "userlist"
    })
    private T data;
}

这里面起到关键作用的是 Jackson 库里的 @JsonAlias 注解。它的官方文档是这样介绍的:

Annotation that can be used to define one or more alternative names for a property, accepted during deserialization as alternative to the official name. Alias information is also exposed during POJO introspection, but has no effect during serialization where primary name is always used.
Examples:
  public class Info {
    @JsonAlias({ "n", "Name" })
    public String name;
  }
  
NOTE: Order of alias declaration has no effect. All properties are assigned in the order they come from incoming JSON document. If same property is assigned more than once with different value, later will remain. For example, deserializing
   public class Person {
      @JsonAlias({ "name", "fullName" })
      public String name;
   }
   
from
   { "fullName": "Faster Jackson", "name": "Jackson" }
   
will have value "Jackson".
Also, can be used with enums where incoming JSON properties may not match the defined enum values. For instance, if you have an enum called Size with values SMALL, MEDIUM, and LARGE, you can use this annotation to define alternate values for each enum value. This way, the deserialization process can map the incoming JSON values to the correct enum values.
Sample implementation:
public enum Size {
       @JsonAlias({ "small", "s", "S" })
       SMALL,
  
       @JsonAlias({ "medium", "m", "M" })
       MEDIUM,
  
       @JsonAlias({ "large", "l", "L" })
       LARGE
   }
During deserialization, any of these JSON structures will be valid and correctly mapped to the MEDIUM enum value: {"size": "m"}, {"size": "medium"}, or {"size": "M"}.

回到我们的例子,除了 department 和 userlist 之外还用到其它的 key,可以继续在 @JsonAlias 注解里添加。

这样,对不同的接口的封装,我们反序列化后统一 getData() 就可以获取到数据部分了,使用时不用再去操心数据部分的 key 是什么。

以上就是Java如何用一个统一结构接收成员名称不固定的数据的详细内容,更多关于Java统一结构接收不固定数据的资料请关注脚本之家其它相关文章!

相关文章

  • Mybatis 多对一查询的实现方法

    Mybatis 多对一查询的实现方法

    这篇文章主要介绍了Mybatis 多对一查询,本文通过场景分析示例代码相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • Springboot中的异步任务执行及监控详解

    Springboot中的异步任务执行及监控详解

    这篇文章主要介绍了Springboot中的异步任务执行及监控详解,除了自己实现线程外,springboot本身就提供了通过注解的方式,进行异步任务的执行,下面主要记录一下,在Springboot项目中实现异步任务,以及对异步任务进行封装监控,需要的朋友可以参考下
    2023-10-10
  • 避免sql注入_动力节点Java学院整理

    避免sql注入_动力节点Java学院整理

    这篇文章主要介绍了避免sql注入,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Java实战之城市多音字处理

    Java实战之城市多音字处理

    这篇文章主要介绍了Java实战之城市多音字处理,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • 腾讯开源消息中间件TubeMQ总体介绍分析

    腾讯开源消息中间件TubeMQ总体介绍分析

    这篇文章主要为大家介绍了腾讯开源消息中间件TubeMQ的总体介绍分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-02-02
  • Springboot实现给前端返回一个tree结构方法

    Springboot实现给前端返回一个tree结构方法

    这篇文章主要介绍了SpringBoot返回给前端一个tree结构的实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 手写java性能测试框架第二版

    手写java性能测试框架第二版

    这篇文章主要为大家介绍了手写java性能测试框架第二版实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 详谈Array和ArrayList的区别与联系

    详谈Array和ArrayList的区别与联系

    下面小编就为大家带来一篇详谈Array和ArrayList的区别与联系。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • spring mvc中的@ModelAttribute注解示例介绍

    spring mvc中的@ModelAttribute注解示例介绍

    在Spring mvc中,注解@ModelAttribute是一个非常常用的注解,下面这篇文章主要给大家介绍了关于spring mvc中@ModelAttribute注解的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
    2017-09-09
  • Maven 搭建SpringMVC+Hibernate项目详解

    Maven 搭建SpringMVC+Hibernate项目详解

    本文主要介绍Maven 搭建SpringMVC+Hibernate的知识,这里整理了详细的资料,并附示例代码,有兴趣的小伙伴可以参考下
    2016-09-09

最新评论