Spring MVC、REST 和 HATEOAS
我正在努力寻找使用 HATEOAS 实现 Spring MVC 3.x RESTful 服务的正确方法。考虑以下限制:
- 我不希望我的域实体被 web/rest 结构污染。
- 我不希望我的控制器被视图构造污染。
- 我想支持多种观点。
目前我有一个很好地组合在一起的 MVC 应用程序,没有 HATEOAS。域实体是纯 POJO,没有嵌入任何视图或 Web/REST 概念。例如:
class User {
public String getName() {...}
public String setName(String name) {...}
...
}
我的控制器也很简单。它们提供路由和状态,并委托给 Spring 的视图解析框架。请注意,我的应用程序支持 JSON、XML 和 HTML,但没有域实体或控制器嵌入视图信息:
@Controller
@RequestMapping("/users")
class UserController {
@RequestMapping
public ModelAndView getAllUsers() {
List<User> users = userRepository.findAll();
return new ModelAndView("users/index", "users", users);
}
@RequestMapping("/{id}")
public ModelAndView getUser(@PathVariable Long id) {
User user = userRepository.findById(id);
return new ModelAndView("users/show", "user", user);
}
}
所以,现在我的问题是 - 我不确定支持 HATEOAS 的干净方法。这是一个例子。假设当客户端请求 JSON 格式的用户时,结果如下:
{
firstName: "John",
lastName: "Smith"
}
假设当我支持 HATEOAS 时,我希望 JSON 包含一个简单的“self”链接,客户端可以使用该链接来刷新对象,删除它,或者其他什么。它还可能有一个“朋友”链接,指示如何获取用户的朋友列表:
{
firstName: "John",
lastName: "Smith",
links: [
{
rel: "self",
ref: "http://myserver/users/1"
},
{
rel: "friends",
ref: "http://myserver/users/1/friends"
}
]
}
不知何故,我想将链接附加到我的对象。我认为执行此操作的正确位置是在控制器层中,因为控制器都知道正确的 URL。此外,由于我支持多个视图,我觉得正确的做法是以某种方式装饰控制器中的域实体,然后再将它们转换为 JSON/XML/Spring 视图解析框架中的任何内容。实现此目的的一种方法可能是使用包含链接列表的通用 Resource 类来包装有问题的 POJO。需要进行一些视图调整才能将其压缩为我想要的格式,但它是可行的。不幸的是,嵌套资源无法以这种方式包装。想到的其他事情包括添加到 ModelAndView 的链接,然后自定义每个 Spring 的开箱即用视图解析器以将链接填充到生成的 JSON/XML/等中。我不想要的是不断地手工制作 JSON/XML/等等。以适应开发过程中出现和消失的各种链接。
想法?
I'm struggling with the correct way to implement Spring MVC 3.x RESTful services with HATEOAS. Consider the following constraints:
- I don't want my domain entities polluted with web/rest constructs.
- I don't want my controllers polluted with view constructs.
- I want to support multiple views.
Currently I have a nicely put together MVC app without HATEOAS. Domain entities are pure POJOs without any view or web/rest concepts embedded. For example:
class User {
public String getName() {...}
public String setName(String name) {...}
...
}
My controllers are also simple. They provide routing and status, and delegate to Spring's view resolution framework. Note my application supports JSON, XML, and HTML, yet no domain entities or controllers have embedded view information:
@Controller
@RequestMapping("/users")
class UserController {
@RequestMapping
public ModelAndView getAllUsers() {
List<User> users = userRepository.findAll();
return new ModelAndView("users/index", "users", users);
}
@RequestMapping("/{id}")
public ModelAndView getUser(@PathVariable Long id) {
User user = userRepository.findById(id);
return new ModelAndView("users/show", "user", user);
}
}
So, now my issue - I'm not sure of a clean way to support HATEOAS. Here's an example. Let's say when the client asks for a User in JSON format, it comes out like this:
{
firstName: "John",
lastName: "Smith"
}
Let's also say that when I support HATEOAS, I want the JSON to contain a simple "self" link that the client can then use to refresh the object, delete it, or something else. It might also have a "friends" link indicating how to get the user's list of friends:
{
firstName: "John",
lastName: "Smith",
links: [
{
rel: "self",
ref: "http://myserver/users/1"
},
{
rel: "friends",
ref: "http://myserver/users/1/friends"
}
]
}
Somehow I want to attach links to my object. I feel the right place to do this is in the controller layer as the controllers all know the correct URLs. Additionally, since I support multiple views, I feel like the right thing to do is somehow decorate my domain entities in the controller before they are converted to JSON/XML/whatever in Spring's view resolution framework. One way to do this might be to wrap the POJO in question with a generic Resource class that contains a list of links. Some view tweaking would be required to crunch it into the format I want, but its doable. Unfortunately nested resources could not be wrapped in this way. Other things that come to mind include adding links to the ModelAndView, and then customizing each of Spring's out-of-the-box view resolvers to stuff links into the generated JSON/XML/etc. What I don't want is to be constantly hand-crafting JSON/XML/etc. to accommodate various links as they come and go during the course of development.
Thoughts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
GitHub 上有一个名为 Spring HATEOAS 的有用项目,其描述如下:
如果您返回的资源类扩展了“ResourceSupport”,您可以轻松地向其添加链接,并且可以使用“ControllerLinkBuilder”构建链接,例如添加自链接:
这是一个相当新的项目,但它是如果需要,可从公共 Maven 存储库获取:
如果您使用 Maven 工件:
则变为:
There is a useful project called Spring HATEOAS on GitHub which has the following description:
If the resource class you are returning extends 'ResourceSupport' you can easily add links to it, and you can build links using 'ControllerLinkBuilder', for example to add a self link:
It is quite a new project but it is available from the public Maven repo if required:
If you use the maven artifact:
becomes:
我的想法:
My Thoughts:
只是在寻找其他内容时偶然发现了这一点,并认为您应该考虑使用 Link 标头而不是 JSON 正文中的内容,这实际上只会污染资源的表示形式。
查看关于网络链接的 IETF 备忘录以及链接关系的 IANA 注册表。
Just stumbled across this while looking for something else and thought you should be considering using the Link header instead of content in the JSON body which is really just polluting the representations of your resources.
Check out the IETFs memo on web linking and also the IANA registry of link relations.
要在您的
REST
api 中创建链接,您可以使用 Spring 框架的HAETOAS
项目。org.springframework.hateoas.mvc.ControllerLinkBuilder
类有一组方法,您可以使用它们来构建链接,例如 -另外,如果您有一个具有
@RequestMapping
注释的控制器方法一些 URI 值 -那么您可以使用方法 URI 值创建链接 -
它将返回
String
值 (http://www.urhost.com/customer
),您可以设置在你的实体
对象
。TO create the link in your
REST
api you can useHAETOAS
project of Spring framework.org.springframework.hateoas.mvc.ControllerLinkBuilder
class have set of method which you can use to build a link like -Also if you have a controller method having
@RequestMapping
annotation with some URI value -then you can create link using method URI value as -
it will return
String
value (http://www.urhost.com/customer
) which you can set in yourentity
Object
.