天天看點

SpringBoot HATEOAS用法簡介

REST風格簡介

介紹HATEOAS之前先簡單介紹一下REST,REST 是 Representational state transfer 的縮寫,翻譯過來的意思是表達性狀态轉換。REST是一種架構的風格

Richardson Maturity Model

Richardson 提出了REST一種 成熟度模型,我們稱之為Richardson Maturity Model,這種模式将REST按照成熟度劃分為4個等級

  • Level0:使用HTTP作為WEB服務的傳輸方式,以REST樣式公開SOAP Web服務
  • Level1:使用适當的URI(使用名詞)公開資源,這種方式提出了資源的概念
  • Level2:資源使用正确的URI + HTTP方法,比如更新使用者就用put方式,查詢用get方式
  • Level3:使用HATEOAS(作為應用程式狀态引擎的超媒體),在資源的表達中包含了連結資訊,用戶端可以在連結資訊中發現可以執行的操作

HATEOAS是什麼?

HATEOAS代表“超媒體是應用程式狀态的引擎”

從前言我們已經可以清楚知道,使用HATEOAS限制是REST風格中成熟度最高的,也是官方推薦的一種方式,沒使用HATEOAS的項目,服務端和用戶端是耦合的,用戶端隻能通過相關文檔來知道服務端做了什麼修改,使用HATEOAS限制的REST服務,服務端修改接口資訊後,用戶端可以通過伺服器提供的資源的表達來智能地發現可以執行的操作,用戶端不需要做啥修改,因為資源資訊是會動态改變的

在Spring的官網,已經有提供這個項目的相關文檔,連結:​​https://spring.io/projects/spring-hateoas​​

SpringBoot HATEOAS

SpringBoot中也有內建HATEOAS,本部落格介紹一下如何使用

工具準備:

  • JDK8.0
  • Maven 3.0+建構工具
  • Eclipse或者IntelliJ IDEA
  • git&gitlab

Maven相關配置

在pom.xml加上hateoas配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>      

因為是要寫個web簡單curd例子,其它需要的也加上

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-hateoas</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.25</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>      

實體類實作ResourceSupport

Model類實作hateoas提供的ResourceSuppor

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.hateoas.ResourceSupport;

import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name="sys_user")
public class SysUserInfo extends ResourceSupport implements Serializable{

    @Id
    @GeneratedValue
    private Long userId;
    @Column(unique=true,length=20,nullable=false)
    private String username;
    @Column(length=2,nullable=true)
    private String sex;
    @Column(length=10,nullable=true)
    private String password;

    public SysUserInfo(){

    }

    @JsonCreator
    public SysUserInfo(@JsonProperty("userId")Long userId,@JsonProperty("username")String username,
                       @JsonProperty("sex")String sex,@JsonProperty("password")String password){
        this.userId = userId;
        this.username = username;
        this.sex = sex;
        this.password = password;
    }
}
....      

接口調用,基于HATEOAS模式

@GetMapping("/findBySysUserId/{userId}")
    public SysUserInfo findBySysUserId(@PathVariable("userId") long userId) {
        if (LOG.isInfoEnabled()) {
            LOG.info("請求參數userId : {}" , userId);
        }
        Optional<SysUserInfo> sysUserInfo = Optional.ofNullable(sysUserRepository.findByUserId(userId));
        if (!sysUserInfo.isPresent()) {
            throw new NotFoundException("查詢不到使用者資訊! userId:"+userId);
        }
        //Resource<SysUserInfo> resource = new Resource<SysUserInfo>(sysUserInfo.get());
        ControllerLinkBuilder linkBuilder = linkTo(methodOn(this.getClass()).findBySysUserId(userId));
        sysUserInfo.get().add(linkBuilder.withRel("findBySysUserId"));
        return sysUserInfo.get();
    }