我想发送仅包含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微服务的组织如何实现此功能?谢谢!
答案 0 :(得分:1)
方法1:将对象转换为Map,删除多余的键,将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());
}
方法2:使用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);
}
答案 1 :(得分:1)
这是另一种方法:
假设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);