【问题标题】:Modify REST API response to only include fields requested in query parameter修改 REST API 响应以仅包含查询参数中请求的字段
【发布时间】:2020-03-06 04:30:40
【问题描述】:

我想发送仅包含 GET api 请求字段的响应。减少响应的总大小。

例如, 默认行为,何时请求特定字段

GET /v1/users/

{
   "data" : 
     [
        {
            "name" : "User1",
            "phone" : "800-999-9999",
            "city" : "XYZ1",
            "country" : "PQR1"
        },
        {
            "name" : "User2",
            "phone" : "800-999-9999",
            "city" : "XYZ2",
            "country" : "PQR2"
         }
     ]
}

用例,需要的字段作为查询参数传递

GET /v1/users/?fields=name,city

{
   "data" : 
     [
        {
            "name" : "User1",
            "city" : "XYZ1"
        },
        {
            "name" : "User2",
            "city" : "XYZ2"
         }
     ]
}

遇到了“https://github.com/monitorjbl/json-view”。却被小队击落。

如何使用 Spring Boot 实现此功能?使用 java 微服务的组织如何实现此功能?谢谢!

【问题讨论】:

    标签: java rest api spring-boot microservices


    【解决方案1】:

    方法一:对象转Map,去掉多余key,Map转Json

    @GetMapping("/v1/users")
    @ResponseBody
    public List<Map> getUsers(@RequestParam(required = false) Set<String> fields) { 
        List<User> users = ...;
        ObjectMapper oMapper = new ObjectMapper();
        return users.stream().map(u -> oMapper.convertValue(u, Map.class))
           .peek(map -> { 
              if (fields != null) map.keySet().retainAll(fields)
           })
           .collect(Collectors.toList());
    }
    

    方法二:使用Gson

    @GetMapping("/v1/users")
    @ResponseBody
    public String getUsers(@RequestParam(required = false) Set<String> fields) { 
        List<User> users = ...;
        Gson gson = new GsonBuilder()
                .setExclusionStrategies(new ExclusionStrategy() {
                    @Override
                    public boolean shouldSkipField(FieldAttributes f) {
                        return f.getDeclaringClass().equals(User.class)
                                 && fields != null 
                                 && !fields.contains(f.getFieldName())
                                ;
                    }
    
                    @Override
                    public boolean shouldSkipClass(Class<?> clazz) {
                        return false;
                    }
                }).create();
        return gson.toJson(users); 
    }
    

    遇到了“https://github.com/monitorjbl/json-view”。却被小队击落。

    顺便说一句,Jackson 支持 @JsonView 注释,但它不允许根据需要动态包含/排除字段。您可以定义字段子集,然后返回这些子集

    public class Views {
        public static class Short {
        }
    }
    
    public class User {
        @JsonView(Views.Short.class)
        public String city;
    
        @JsonView(Views.Short.class)
        public String name;
    
        public String phone;
    
        public String country;
    }
    
    @GetMapping("/v1/users")
    @ResponseBody
    public String getUsers(@RequestParam(required = false) boolean shortView) { 
        List<User> users = ...;
        ObjectMapper mapper = new ObjectMapper();
        if (shortView) mapper = mapper.writerWithView(Views.Short.class);
        return mapper.writeValueAsString(users);
    }
    

    【讨论】:

      【解决方案2】:

      这是另一种方法:

      假设 1:我认为将控制器的返回类型定义为域对象并让 spring 单独处理将其转换为 JSON 会更好(与 @Alexander Pavlov 的回答不同)。 IMO 对于一般代码的可读性和像 swagger 这样的工具来说更好 内省控制器,应该知道应该返回什么。

      假设 2:您的 User 类中没有原语。

      好的,现在控制器显然调用了一些“服务”来对数据库进行一些查询,或者通常执行一些最终生成用户列表(您返回给客户端的列表)的逻辑。返回对象应该是这样的:

      class Users {
      
           private List<User> data;
      }
      
      class User { // + constructors, getters, setters, etc.
         private String name;
         private String city;
         private String phone;
         private String country;    
      }
      

      在这种情况下,您可以在服务中将“null”放在您不想返回的字段中:

      User user = new User("John", "LA", null, null); // you only have name and city
      

      现在您可以将注释 @JsonInclude(Include.NON_NULL) 放在类 User 上,这将指示 Jackson 根本不将值为“null”的字段包含到序列化响应中。

      如果您希望全局应用此行为,可以配置ObjectMapper bean:

       ObjectMapper mapper = new ObjectMapper();
       mapper.setSerializationInclusion(Include.NON_NULL);
      

      【讨论】:

      • + 假设 3:域模型允许空值。有时强制的不可为空性(例如对于集合)通过简化对此类对象的处理来支付自己的费用。仅允许空值用于自定义序列化可能是不好的权衡。
      猜你喜欢
      • 1970-01-01
      • 2015-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多