Spring 休息控制器 Return 特定字段
Spring Rest Controller Return Specific Fields
我一直在思考使用 Spring MVC 设计 JSON API 的最佳方法。众所周知,IO 很昂贵,因此我不想让客户进行多次 API 调用来获得他们需要的东西。但是与此同时,我不一定要 return 厨房水槽。
举个例子,我正在开发一款类似于 IMDB 的游戏 API,但用于视频游戏。
如果我 return 编辑所有与游戏相关的内容,它看起来会像这样。
/api/game/1
{
"id": 1,
"title": "Call of Duty Advanced Warfare",
"release_date": "2014-11-24",
"publishers": [
{
"id": 1,
"name": "Activision"
}
],
"developers": [
{
"id": 1,
"name": "Sledge Hammer"
}
],
"platforms": [
{
"id": 1,
"name": "Xbox One",
"manufactorer": "Microsoft",
"release_date": "2013-11-11"
},
{
"id": 2,
"name": "Playstation 4",
"manufactorer": "Sony",
"release_date": "2013-11-18"
},
{
"id": 3,
"name": "Xbox 360",
"manufactorer": "Microsoft",
"release_date": "2005-11-12"
}
],
"esrbRating": {
"id": 1,
"code": "T",
"name": "Teen",
"description": "Content is generally suitable for ages 13 and up. May contain violence, suggestive themes, crude humor, minimal blood, simulated gambling and/or infrequent use of strong language."
},
"reviews": [
{
"id": 1,
"user_id": 111,
"rating": 4.5,
"description": "This game is awesome"
}
]
}
然而,他们可能不需要所有这些信息,但他们可能再次需要。从 I/O 和性能来看,调用所有内容似乎不是一个好主意。
我想通过在请求中指定 include 参数来实现。
现在例如,如果您没有指定任何包含,您将得到以下内容。
{
"id": 1,
"title": "Call of Duty Advanced Warfare",
"release_date": "2014-11-24"
}
无论您想要的所有信息,您的请求都应该是这样的。
/api/game/1?include=publishers,developers,platforms,reviews,esrbRating
这样客户就可以指定他们想要多少信息。但是,我对使用 Spring MVC 实现此目的的最佳方法感到茫然。
我认为控制器看起来像这样。
public @ResponseBody Game getGame(@PathVariable("id") long id,
@RequestParam(value = "include", required = false) String include)) {
// check which include params are present
// then someone do the filtering?
}
我不确定您将如何选择性地序列化 Game 对象。这甚至可能吗?在 Spring MVC 中解决这个问题的最佳方法是什么?
仅供参考,我正在使用 Spring Boot,其中包括用于序列化的 Jackson。
您可以将其序列化为 Map<String, Object>
,而不是返回 Game
对象,其中映射键代表属性名称。因此,您可以根据 include
参数将值添加到地图中。
@ResponseBody
public Map<String, Object> getGame(@PathVariable("id") long id, String include) {
Game game = service.loadGame(id);
// check the `include` parameter and create a map containing only the required attributes
Map<String, Object> gameMap = service.convertGameToMap(game, include);
return gameMap;
}
举个例子,如果你有这样的 Map<String, Object>
:
gameMap.put("id", game.getId());
gameMap.put("title", game.getTitle());
gameMap.put("publishers", game.getPublishers());
会这样序列化:
{
"id": 1,
"title": "Call of Duty Advanced Warfare",
"publishers": [
{
"id": 1,
"name": "Activision"
}
]
}
意识到我的回答来得太晚了:我建议看看 Projections
。
你问的是预测的内容。
既然你问的是关于 Spring 的问题,我会试一试:
https://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts
GraphQL
提供了一种按需提供不同投影的动态方式。我刚刚看到一篇关于如何将 GraphQL
与 SpringBoot
结合使用的非常有用的文章:
https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/
这可以通过 Spring Projections
完成。也适用于 Kotlin。
看这里:https://www.baeldung.com/spring-data-jpa-projections
解决方案一:
将 @JsonIgnore 添加到您不想包含在 API 响应(在模型中)
中的变量
@JsonIgnore
private Set<Student> students;
方案二:
删除您不想包含的变量的 getter。
如果您在其他地方需要它们,请为吸气剂使用不同的格式,因此 spring 不知道。
我一直在思考使用 Spring MVC 设计 JSON API 的最佳方法。众所周知,IO 很昂贵,因此我不想让客户进行多次 API 调用来获得他们需要的东西。但是与此同时,我不一定要 return 厨房水槽。
举个例子,我正在开发一款类似于 IMDB 的游戏 API,但用于视频游戏。
如果我 return 编辑所有与游戏相关的内容,它看起来会像这样。
/api/game/1
{
"id": 1,
"title": "Call of Duty Advanced Warfare",
"release_date": "2014-11-24",
"publishers": [
{
"id": 1,
"name": "Activision"
}
],
"developers": [
{
"id": 1,
"name": "Sledge Hammer"
}
],
"platforms": [
{
"id": 1,
"name": "Xbox One",
"manufactorer": "Microsoft",
"release_date": "2013-11-11"
},
{
"id": 2,
"name": "Playstation 4",
"manufactorer": "Sony",
"release_date": "2013-11-18"
},
{
"id": 3,
"name": "Xbox 360",
"manufactorer": "Microsoft",
"release_date": "2005-11-12"
}
],
"esrbRating": {
"id": 1,
"code": "T",
"name": "Teen",
"description": "Content is generally suitable for ages 13 and up. May contain violence, suggestive themes, crude humor, minimal blood, simulated gambling and/or infrequent use of strong language."
},
"reviews": [
{
"id": 1,
"user_id": 111,
"rating": 4.5,
"description": "This game is awesome"
}
]
}
然而,他们可能不需要所有这些信息,但他们可能再次需要。从 I/O 和性能来看,调用所有内容似乎不是一个好主意。
我想通过在请求中指定 include 参数来实现。
现在例如,如果您没有指定任何包含,您将得到以下内容。
{
"id": 1,
"title": "Call of Duty Advanced Warfare",
"release_date": "2014-11-24"
}
无论您想要的所有信息,您的请求都应该是这样的。
/api/game/1?include=publishers,developers,platforms,reviews,esrbRating
这样客户就可以指定他们想要多少信息。但是,我对使用 Spring MVC 实现此目的的最佳方法感到茫然。
我认为控制器看起来像这样。
public @ResponseBody Game getGame(@PathVariable("id") long id,
@RequestParam(value = "include", required = false) String include)) {
// check which include params are present
// then someone do the filtering?
}
我不确定您将如何选择性地序列化 Game 对象。这甚至可能吗?在 Spring MVC 中解决这个问题的最佳方法是什么?
仅供参考,我正在使用 Spring Boot,其中包括用于序列化的 Jackson。
您可以将其序列化为 Map<String, Object>
,而不是返回 Game
对象,其中映射键代表属性名称。因此,您可以根据 include
参数将值添加到地图中。
@ResponseBody
public Map<String, Object> getGame(@PathVariable("id") long id, String include) {
Game game = service.loadGame(id);
// check the `include` parameter and create a map containing only the required attributes
Map<String, Object> gameMap = service.convertGameToMap(game, include);
return gameMap;
}
举个例子,如果你有这样的 Map<String, Object>
:
gameMap.put("id", game.getId());
gameMap.put("title", game.getTitle());
gameMap.put("publishers", game.getPublishers());
会这样序列化:
{
"id": 1,
"title": "Call of Duty Advanced Warfare",
"publishers": [
{
"id": 1,
"name": "Activision"
}
]
}
意识到我的回答来得太晚了:我建议看看 Projections
。
你问的是预测的内容。
既然你问的是关于 Spring 的问题,我会试一试: https://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts
GraphQL
提供了一种按需提供不同投影的动态方式。我刚刚看到一篇关于如何将 GraphQL
与 SpringBoot
结合使用的非常有用的文章:
https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/
这可以通过 Spring Projections
完成。也适用于 Kotlin。
看这里:https://www.baeldung.com/spring-data-jpa-projections
解决方案一: 将 @JsonIgnore 添加到您不想包含在 API 响应(在模型中)
中的变量@JsonIgnore
private Set<Student> students;
方案二: 删除您不想包含的变量的 getter。
如果您在其他地方需要它们,请为吸气剂使用不同的格式,因此 spring 不知道。