写点什么

SpringBoot 之:SpringBoot 中使用 HATEOAS

作者:程序那些事
  • 2022 年 5 月 14 日
  • 本文字数:2103 字

    阅读完需:约 7 分钟

SpringBoot之:SpringBoot中使用HATEOAS

简介

HATEOAS 是实现 REST 规范的一种原则,通过遵循 HATEOAS 规范,可以解决我们实际代码实现的各种个问题。作为 java 最流行的框架 Spring 当然也会不缺席 HATEOAS 的集成。


本文将会通过一个具体的例子来讲解如何在 SpringBoot 中使用 HATEOAS。

我们的目标

HATEOAS 规则中,返回的数据会带有链接。我们以熟悉的 Book 为例,来展示这次的 HATEOAS,首先创建一个 Book entity:


@Data@Entitypublic class Book {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title;}
复制代码


我们希望能够通过下面的链接来获取到 Book 的详细数据:


GET /book/1
复制代码


返回的数据如下:



{ "content": { "id": 1, "title": "The Hobbit" }, "_links": { "self": { "href": "http://localhost:8080/book/1" } }}
复制代码


可以看到在返回的数据中除了 content 包含了 book 的信息之外,还有一个_links 属性,表示和该 Book 相关的资源链接。

构建 Entity 和 Repository

在做任何数据之前,我们都需要构建相应的数据,也就是 entity 和对应的数据操作,为了简便起见,我们使用 H2 的内存数据库。


我们需要在 application.properties 中配置如下:


spring.jpa.hibernate.ddl-auto=validate
spring.datasource.url=jdbc:h2:mem:testdbspring.datasource.driverClassName=org.h2.Driverspring.datasource.username=saspring.datasource.password=passwordspring.jpa.database-platform=org.hibernate.dialect.H2Dialect
复制代码


然后配置对应的 repository :


public interface BookRepository extends CrudRepository<Book, Long> {    long deleteByTitle(String title);
@Modifying @Query("delete from Book b where b.title=:title") void deleteBooks(@Param("title") String title);}
复制代码


同时,需要在 resources 中放置创建 table 的 schema.sql 和插入数据的 data.sql。这样在程序启动的时候就可以自动创建相应的数据。

构建 HATEOAS 相关的 RepresentationModel

如果要让自己来实现,也可以实现添加链接的操作,但是这样就太复杂了,还好我们有 Spring。要在 Spring 中使用 HATEOAS,需要进行如下配置:


<dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-hateoas</artifactId>        </dependency>
复制代码


如果我们想要对 Book 进行 HATEOAS 的构建,那么可以构建一个类,继承 RepresentationModel 即可:


public class BookModel extends RepresentationModel<BookModel> {
private final Book content;
@JsonCreator public BookModel(@JsonProperty("content") Book content) { this.content = content; }
public Book getContent() { return content; }}
复制代码


上面的例子中,我们用 RepresentationModel 封装了一个 Book 对象,并将其设置为 json 的 content 属性。

构建 Controller

有了 RepresentationModel,我们就可以使用它来构建 HATEOAS 的响应了。


我们看下面的例子:


  @RequestMapping("/book/{id}")  public HttpEntity<Book> getBook(@PathVariable("id") Long id) {    Book book= bookRepository.findById(id).get();    BookModel bookModel = new BookModel(book);    bookModel.add(linkTo(methodOn(BookController.class).getBook(id)).withSelfRel());    return new ResponseEntity(bookModel, HttpStatus.OK);  }
复制代码


上面的例子中,我们使用 @RequestMapping 来构建了一个 HTTP 请求,通过传入 book 的 id 来从数据库中查找相应的 Book 数据。


然后将其传入 BookModel 中,构建好 RepresentationModel。这时候可以直接返回这个对象。但是我们还需要向其添加一些 links。


我们使用 bookModel.add 来添加相应的 link。并且使用 linkTo 方法来生成相应的 link。


最后将 RepresentationModel 返回。


当我们请求/book/1 的时候,就会得到最前面我们想要得到的 json 值。使用 HATEOAS 是不是很简单?

HATEOAS 的意义

HATEOAS 带有相应的资源链接,通过一个资源就可以得到从这个资源可以访问的其他的资源,就像是一个访问到一个页面,可以再通过这个页面去访问其他的页面一样。


所以 HATEOAS 的意义就在于我们只需要访问一个资源就可以遍历所有的资源。


我们通过测试来体验一下资源的访问。


首先,我们直接访问/book/1 这个资源,来确认下得到的结果:


    @Test    void envEndpointNotHidden() throws Exception {        mockMvc.perform(get("/book/1"))                .andExpect(jsonPath("$.content.title").value("The Hobbit"));    }
复制代码


然后再通过 Spring HATEOAS 提供的 Traverson 类来进行链接的遍历:


  @Test  void envEndpointNotHidden() throws Exception {    Traverson traverson = new Traverson(new URI("http://localhost:" + this.port + "/book/1"), MediaTypes.HAL_JSON);    String bookTitle = traverson.follow("self").toObject("$.content.title");    assertThat(bookTitle).isEqualTo("The Hobbit");  }
复制代码

总结

很好,我们已经可以使用基本的 HATEOAS 了,本文例子可以参考:


learn-springboot2


发布于: 刚刚阅读数: 2
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
SpringBoot之:SpringBoot中使用HATEOAS_Java_程序那些事_InfoQ写作社区