Spring Boot 2.0 – Spring Boot REST HATEOAS例子

位置:首页>文章>详情   分类: 教程分享 > Java教程   阅读(2959)   2023-03-28 11:29:14

前言

在这个Spring HATEOAS示例中,我们将学习如何将HATEOAS链接添加到在spring boot项目中创建的现有REST API。我们将使用类
org.springframework.hateoas.ResourceSupport 、
org.springframework.hateoas.mvc.ControllerLinkBuilder
org.springframework.hateoas.Link Spring HATEOAS模块提供的类。

为了演示链接的创建,我们将首先创建一些REST API并查看它们的输出。然后,我们将HATEOAS链接应用到REST资源,然后我们将比较有无链接的输出。
HATEOAS(The Hypermedia As The Engine Of Application Statue)
 

项目结构

Spring HATEOAS示例 - 项目结构

创建REST API

在这个例子中,我创建了三个带有端点的REST API,如下所示:
  • /employees
  • /employees/{id}
  • /employees/{id}/report

REST资源模型

EmployeeListVO:
@XmlRootElement (name="employees")
public class EmployeeListVO implements Serializable
{
    private static final long serialVersionUID = 1L;
      
    private List<EmployeeVO> employees = new ArrayList<EmployeeVO>();
  
    public List<EmployeeVO> getEmployees() {
        return employees;
    }
  
    public void setEmployees(List<EmployeeVO> employees) {
        this.employees = employees;
    }
}
EmployeeListVO:
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.NONE)
public class EmployeeVO implements Serializable
{
    private static final long serialVersionUID = 1L;
     
    public EmployeeVO(Integer id, String firstName, String lastName, String email) {
        super();
        this.employeeId = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }
 
    public EmployeeVO() {
 
    }
 
    @XmlAttribute
    private Integer employeeId;
 
    @XmlElement
    private String firstName;
 
    @XmlElement
    private String lastName;
 
    @XmlElement
    private String email;
 
    //removed getters and setters for readability
 
    @Override
    public String toString() {
        return "EmployeeVO [id=" + employeeId + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email
                + "]";
    }
}
EmployeeReport:
@XmlRootElement(name="employee-report")
public class EmployeeReport implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    //根据需要添加其他信息
}

REST Controller

EmployeeRESTController:
@RestController
public class EmployeeRESTController {
     
    @RequestMapping(value = "/employees")
    public EmployeeListVO getAllEmployees()
    {
        EmployeeListVO employeesList  = new EmployeeListVO();
 
        for (EmployeeVO employee : EmployeeDB.getEmployeeList())
        {
            employeesList.getEmployees().add(employee);
        }
 
        return employeesList;
    }
      
    @RequestMapping(value = "/employees/{id}")
    public ResponseEntity<EmployeeVO> getEmployeeById (@PathVariable("id") int id)
    {
        if (id <= 3) {
            EmployeeVO employee = EmployeeDB.getEmployeeList().get(id-1);
            return new ResponseEntity<EmployeeVO>(employee, HttpStatus.OK);
        }
        return new ResponseEntity<EmployeeVO>(HttpStatus.NOT_FOUND);
    }
     
    @RequestMapping(value = "/employees/{id}/report")
    public ResponseEntity<EmployeeReport> getReportByEmployeeById (@PathVariable("id") int id)
    {
        //Do some operation and return report
        return null;
    }
}

DAO层

我已经创建了EmployeeDB类来模拟DAO层。在实际应用中,从数据源获取数据将是更复杂的代码。

EmployeeDB
public class EmployeeDB {
 
    public static List<EmployeeVO> getEmployeeList()
    {
        List<EmployeeVO> list = new ArrayList<>();
 
        EmployeeVO empOne = new EmployeeVO(1, "Lokesh", "Gupta", "demo@gmail.com");
        EmployeeVO empTwo = new EmployeeVO(2, "Amit", "Singhal", "asinghal@yahoo.com");
        EmployeeVO empThree = new EmployeeVO(3, "Kirti", "Mishra", "kmishra@gmail.com");
 
        list.add(empOne);
        list.add(empTwo);
        list.add(empThree);
 
        return list;
    }
}
 

启动类:

@SpringBootApplication
public class Application
{
    public static void main(String[] args)
    {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
    }
}


Maven - pom.xml

我们来看看用于这个项目的pom.xml文件。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.demo</groupId>
    <artifactId>springbootdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>springbootdemo</name>
    <url>http://maven.apache.org</url>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>
 
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-hateoas</artifactId>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
    <repositories>
        <repository>
            <id>repository.spring.release</id>
            <name>Spring GA Repository</name>
            <url>http://repo.spring.io/release</url>
        </repository>
    </repositories>
</project>
 

API输出

/employees
{
    "employees": [
        {
            "employeeId": 1,
            "firstName": "Lokesh",
            "lastName": "Gupta",
            "email": "demo@gmail.com"
        },
        {
            "employeeId": 2,
            "firstName": "Amit",
            "lastName": "Singhal",
            "email": "asinghal@yahoo.com"
        },
        {
            "employeeId": 3,
            "firstName": "Kirti",
            "lastName": "Mishra",
            "email": "kmishra@gmail.com"
        }
    ]
}
/employees/{id}
{
	"employeeId": 1,
	"firstName": "Lokesh",
	"lastName": "Gupta",
	"email": "demo@gmail.com"
}


如何将HATEOAS链接添加到REST资源

步骤1)使用ResourceSupport类扩展资源模型

扩展您想添加HATEOAS链接的所有模型类 - 包括org.springframework.hateoas.ResourceSupport类。

@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.NONE)
public class EmployeeVO extends ResourceSupport implements Serializable
{
    //rest all code is same
}
 
//...
 
@XmlRootElement (name="employees")
public class EmployeeListVO extends ResourceSupport implements Serializable
{
    //rest all code is same
}
 
//...
 
@XmlRootElement(name="employee-report")
public class EmployeeReport extends ResourceSupport implements Serializable {
 
    //rest all code is same
}
 

步骤2)在REST控制器中构建和添加链接

要添加链接,您需要ControllerLinkBuilderLink类。Link是要在REST资源中添加的链接的最终表示形式。而ControllerLinkBuilder有助于使用基于构建器模式的各种方法构建链接。

添加链接到收集资源

这里我们将添加两种类型的链接。在第一个链接中,收集资源将指向自己。在第二种类型的链接中,集合中的每个资源都将指向它的URI位置,其中可以使用完整的表示形式。另外,每个资源都会有方法链接,可以根据这些链接对个别资源执行一些操作。
 

@RequestMapping(value = "/employees")
public EmployeeListVO getAllEmployees()
{
    EmployeeListVO employeesList  = new EmployeeListVO();
 
    for (EmployeeVO employee : EmployeeDB.getEmployeeList())
    {
        //Adding self link employee 'singular' resource
        Link link = ControllerLinkBuilder
                .linkTo(EmployeeRESTController.class)
                .slash(employee.getEmployeeId())
                .withSelfRel();
 
        //Add link to singular resource
        employee.add(link);
         
      //Adding method link employee 'singular' resource
        ResponseEntity<EmployeeReport> methodLinkBuilder = ControllerLinkBuilder
                .methodOn(EmployeeRESTController.class).getReportByEmployeeById(employee.getEmployeeId());
        Link reportLink = ControllerLinkBuilder
                .linkTo(methodLinkBuilder)
                .withRel("employee-report");
 
        //Add link to singular resource
        employee.add(reportLink);
   
        employeesList.getEmployees().add(employee);
    }
     
    //Adding self link employee collection resource
    Link selfLink = ControllerLinkBuilder
            .linkTo(ControllerLinkBuilder
            .methodOn(EmployeeRESTController.class).getAllEmployees())
            .withSelfRel();
 
    //Add link to collection resource
    employeesList.add(selfLink);
      
    return employeesList;
}
输出:
{
    "employees": [
        {
            "employeeId": 1,
            "firstName": "Lokesh",
            "lastName": "Gupta",
            "email": "howtodoinjava@gmail.com",
            "_links": {
                "self": {
                    "href": "http://localhost:8080/1"
                },
                "employee-report": {
                    "href": "http://localhost:8080/employees/1/report"
                }
            }
        },
        {
            "employeeId": 2,
            "firstName": "Amit",
            "lastName": "Singhal",
            "email": "asinghal@yahoo.com",
            "_links": {
                "self": {
                    "href": "http://localhost:8080/2"
                },
                "employee-report": {
                    "href": "http://localhost:8080/employees/2/report"
                }
            }
        },
        {
            "employeeId": 3,
            "firstName": "Kirti",
            "lastName": "Mishra",
            "email": "kmishra@gmail.com",
            "_links": {
                "self": {
                    "href": "http://localhost:8080/3"
                },
                "employee-report": {
                    "href": "http://localhost:8080/employees/3/report"
                }
            }
        }
    ],
    "_links": {
        "self": {
            "href": "http://localhost:8080/employees"
        }
    }
}
 

添加链接到单个资源

添加单数资源的链接与我们在前面部分看到的完全相同。单数资源表示通常具有更多信息/字段以及附加链接。

@RequestMapping(value = "/employees/{id}")
public ResponseEntity<EmployeeVO> getEmployeeById (@PathVariable("id") int id)
{
    if (id <= 3) {
        EmployeeVO employee = EmployeeDB.getEmployeeList().get(id-1);
         
        //Self link
        Link selfLink = ControllerLinkBuilder
                .linkTo(EmployeeRESTController.class)
                .slash(employee.getEmployeeId())
                .withSelfRel();
         
        //Method link
        Link reportLink = ControllerLinkBuilder
                .linkTo(ControllerLinkBuilder.methodOn(EmployeeRESTController.class)
                .getReportByEmployeeById(employee.getEmployeeId()))
                .withRel("report");
         
        employee.add(selfLink);
        employee.add(reportLink);
        return new ResponseEntity<EmployeeVO>(employee, HttpStatus.OK);
    }
    return new ResponseEntity<EmployeeVO>(HttpStatus.NOT_FOUND);
}
输出:
{
    "employeeId": 1,
    "firstName": "Lokesh",
    "lastName": "Gupta",
    "email": "howtodoinjava@gmail.com",
    "_links": {
        "self": {
            "href": "http://localhost:8080/1"
        },
        "report": {
            "href": "http://localhost:8080/employees/1/report"
        }
    }
}

总结

正如你看到上面的演示,使用spring hashoas模块添加HATEOAS链接非常容易和一分钟时间搞定。这将大大增加API的可发现性和实用性。

提示:项目源码下载:demo-springboot2-hateoas.zip

地址:https://www.leftso.com/article/387.html

相关阅读

前言在这个Spring HATEOAS示例中,我们将学习如何将HATEOAS链接添加到在spring boot项目中创建的现有REST API
Spring Boot 2.0 Redis整合,通过spring boot 2.0整合Redis作为spring缓存框架的实现。
spring boot 2.0 security 5.0 整合,实现自定义表单登录。spring boot 2.0框架使用。
Spring Boot 2.0 有哪些新特性_Spring Boot 2.0新功能,在本文中,我们将探讨为Spring Boot 2.0计划的一些更改和功能。我们还会描述这些变化如何帮助我们提高...
Spring Boot 2.0,Spring框架的Spring Boot 中的Spring Boot Actuator变化讲解。并且了解如何在Spring Boot 2.0中使用Actuator...
Spring Boot 1.x升级到Spring Boot 2.0迁移指南
Spring Boot 2.0 绑定properties属性资源文件 Spring Boot 2.0 读取properties配置文件值 Spring Boot 2.0获取properties配...
Spring Boot 2.0 支持的Apache Camel 版本发布了_Apache Camel 2.22发布支持Spring Boot 2.0
Spring Boot 2.0 @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") 注解格式化日期失效原因及解决。