24

我正在努力使用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 包含一个简单的“自我”链接,然后客户端可以使用该链接来刷新对象、删除它或进行其他操作。它还可能有一个“朋友”链接,指示如何获取用户的朋友列表:

{
  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/等。以适应开发过程中来来去去的各种链接。

想法?

4

4 回答 4

10

GitHub 上有一个名为Spring HATEOAS的有用项目,其描述如下:

“这个项目提供了一些 API 来简化在使用 Spring 尤其是 Spring MVC 时创建遵循 HATEOAS 原则的 REST 表示”

如果您返回的资源类扩展了“ResourceSupport”,您可以轻松地为其添加链接,并且您可以使用“ControllerLinkBuilder”构建链接,例如添加自我链接:

import static org.sfw.hateoas.mvc.ControllerLinkBuilder.*;

Link link = linkTo(YourController.class).slash(resource.getName()).withSelfRel();
resource.add(link);

这是一个相当新的项目,但如果需要,它可以从公共 Maven 存储库中获得:

<dependency>
    <groupId>org.springframework.hateoas</groupId>
    <artifactId>spring-hateoas</artifactId>
    <version>0.3.0.RELEASE</version>
</dependency>

如果您使用 Maven 工件:

org.sfw.hateoas.mvc.ControllerLinkBuilder

变成:

org.springframework.hateoas.mvc.ControllerLinkBuilder
于 2012-11-30T11:02:24.850 回答
1

我的想法:

  • 使用某种命名约定,例如,自引用 url 可以从对象的类名中构造出来。
  • 我不认为添加链接的东西应该由控制器添加(顺便说一句,你自己写了“我不希望我的控制器被视图结构污染”。我会尝试寻找一种方法来扩展 JSON 序列化,以便它自动添加额外的东西。可能你需要为你的实体添加一些注释,即使这会污染它们。
于 2011-08-24T05:54:21.397 回答
1

只是在寻找其他东西时偶然发现了这一点,并认为您应该考虑使用 Link 标头而不是 JSON 正文中的内容,这实际上只是污染了资源的表示。

查看有关网络链接的 IETF 备忘录以及链接关系的IANA 注册表

于 2012-08-15T11:35:38.867 回答
0

要在您的 api 中创建链接,您REST可以使用HAETOASSpring 框架的项目。

org.springframework.hateoas.mvc.ControllerLinkBuilder类有一组方法,您可以使用它们来构建链接,例如 -

Link link=linkTo(PersonControllerImpl.class).slash(null).withSelfRel();

此外,如果您有一个@RequestMapping带有一些 URI 值注释的控制器方法 -

@RequestMapping(value = "/customer", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<?> getCustomer() {

//...
}

然后您可以使用方法 URI 值创建链接 -

linkTo(methodOn(PersonControllerImpl.class).getCustomer()).toUri().toString()

它将返回String值 ( http://www.urhost.com/customer),您可以在entity Object.

于 2016-09-19T11:17:59.027 回答