在这个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)
@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;
//根据需要添加其他信息
}
@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;
}
}
我已经创建了EmployeeDB
类来模拟DAO层。在实际应用中,从数据源获取数据将是更复杂的代码。
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);
}
}
我们来看看用于这个项目的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>
{
"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链接的所有模型类 - 包括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
}
要添加链接,您需要ControllerLinkBuilder
和Link
类。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的可发现性和实用性。
http://blog.xqlee.com/article/387.html