搜索词>>hashoas 耗时0.0030
  • Spring Boot 2.0 – Spring Boot REST HATEOAS例子

    在这个Spring HATEOAS示例中,我们将学习如何将HATEOAS链接添加到在spring boot项目中创建的现有REST API。我们将使用类org.springframework.hateoas.ResourceSupport沿org.springframework.hateoas.mvc.ControllerLinkBuilder和org.springframework.hateoas.Link Spring HATEOAS模块提供的类。<h2>前言</h2> <blockquote> <div style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:varela round,sans-serif">在这个</span><strong>Spring HATEOAS</strong><span style="font-family:varela round,sans-serif">示例中,我们将学习如何将</span><strong>HATEOAS</strong><span style="font-family:varela round,sans-serif">链接添加到在spring boot项目中创建的现有REST API。我们将使用类</span><br /> <code><a href="https://docs.spring.io/spring-hateoas/docs/current/api/org/springframework/hateoas/ResourceSupport.html" rel="external nofollow" style="font-family: "varela round", sans-serif; box-sizing: border-box; transition: all 0.1s ease-in-out; color: rgb(3, 102, 214); text-decoration: none;" target="_blank" >org.springframework.hateoas.ResourceSupport</a><span style="font-family:varela round,sans-serif"> 、</span></code><br /> <code><a href="https://docs.spring.io/spring-hateoas/docs/current/api/org/springframework/hateoas/mvc/ControllerLinkBuilder.html" rel="external nofollow" style="box-sizing:border-box; transition:all 0.1s ease-in-out; color:#0366d6; text-decoration:none" target="_blank" >org.springframework.hateoas.mvc.ControllerLinkBuilder</a></code><span style="font-family:varela round,sans-serif">和</span><br /> <code><a href="https://docs.spring.io/spring-hateoas/docs/current/api/org/springframework/hateoas/Link.html" rel="external nofollow" style="box-sizing:border-box; transition:all 0.1s ease-in-out; color:#0366d6; text-decoration:none" target="_blank" >org.springframework.hateoas.Link</a> </code><span style="font-family:varela round,sans-serif">Spring HATEOAS模块提供的类。</span></span></div> </blockquote> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:"varela round",sans-serif"><span style="background-color:#ffffff">为了演示链接的创建,我们将首先创建一些REST API并查看它们的输出。然后,我们将HATEOAS链接应用到REST资源,然后我们将比较有无链接的输出。</span></span></span><br /> HATEOAS(The Hypermedia As The Engine Of Application Statue)<br />  </p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">项目结构</h2> <img srcset="" width="" size="" class="img-thumbnail" alt="Spring HATEOAS示例 - 项目结构" src="/resources/assist/images/blog/d4448712de3a4ffdadf633d00da45e7d.png" /> <h2 style="margin-left:0px; margin-right:0px; text-align:start">创建REST API</h2> 在这个例子中,我创建了三个带有端点的REST API,如下所示: <ul> <li>/employees</li> <li>/employees/{id}</li> <li>/employees/{id}/report</li> </ul> <h4 style="margin-left:0px; margin-right:0px; text-align:start">REST资源模型</h4> EmployeeListVO: <pre> <code class="language-java">@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; } }</code></pre> EmployeeListVO: <pre> <code class="language-java">@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 + "]"; } }</code></pre> EmployeeReport: <pre> <code class="language-java">@XmlRootElement(name="employee-report") public class EmployeeReport implements Serializable { private static final long serialVersionUID = 1L; //根据需要添加其他信息 }</code></pre> <h4>REST Controller</h4> <strong>EmployeeRESTController:</strong> <pre> <code class="language-java">@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; } }</code></pre> <h4 style="margin-left:0px; margin-right:0px; text-align:start">DAO层</h4> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:"varela round",sans-serif"><span style="background-color:#ffffff">我已经创建了<code>EmployeeDB</code>类来模拟DAO层。在实际应用中,从数据源获取数据将是更复杂的代码。</span></span></span></p> <strong>EmployeeDB</strong> <pre> <code class="language-java">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; } }</code></pre>   <h4 style="margin-left:0px; margin-right:0px; text-align:start">启动类:</h4> <pre> <code class="language-java">@SpringBootApplication public class Application { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); } }</code></pre> <h4 style="margin-left:0px; margin-right:0px; text-align:start"><br /> Maven - pom.xml</h4> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:"varela round",sans-serif"><span style="background-color:#ffffff">我们来看看用于这个项目的pom.xml文件。</span></span></span></p> <div style="text-align:start"> <pre> <code class="language-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></code></pre> </div>   <h4 style="margin-left:0px; margin-right:0px; text-align:start">API输出</h4> <strong>/employees</strong> <pre> <code class="language-json">{ "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" } ] }</code></pre> <strong>/employees/{id}</strong> <pre> <code class="language-json">{ "employeeId": 1, "firstName": "Lokesh", "lastName": "Gupta", "email": "demo@gmail.com" }</code></pre> <h2 style="margin-left:0px; margin-right:0px; text-align:start"><br /> 如何将HATEOAS链接添加到REST资源</h2> <h4 style="margin-left:0px; margin-right:0px; text-align:start">步骤1)使用ResourceSupport类扩展资源模型</h4> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:"varela round",sans-serif"><span style="background-color:#ffffff">扩展您想添加HATEOAS链接的所有模型类 - 包括<code>org.springframework.hateoas.ResourceSupport</code>类。</span></span></span></p> <pre> <code class="language-java">@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 }</code></pre>   <h4 style="margin-left:0px; margin-right:0px; text-align:start">步骤2)在REST控制器中构建和添加链接</h4> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:"varela round",sans-serif"><span style="background-color:#ffffff">要添加链接,您需要<code>ControllerLinkBuilder</code>和<code>Link</code>类。<code>Link</code>是要在REST资源中添加的链接的最终表示形式。而<code>ControllerLinkBuilder</code>有助于使用基于构建器模式的各种方法构建链接。</span></span></span></p> <h4 style="margin-left:0px; margin-right:0px; text-align:start">添加链接到收集资源</h4> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:"varela round",sans-serif"><span style="background-color:#ffffff">这里我们将添加两种类型的链接。在第一个链接中,收集资源将指向自己。在第二种类型的链接中,集合中的每个资源都将指向它的URI位置,其中可以使用完整的表示形式。另外,每个资源都会有方法链接,可以根据这些链接对个别资源执行一些操作。</span></span></span><br />  </p> <pre> <code class="language-java">@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; }</code></pre> 输出: <pre> <code class="language-json">{ "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" } } }</code></pre>   <h4 style="margin-left:0px; margin-right:0px; text-align:start">添加链接到单个资源</h4> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:"varela round",sans-serif"><span style="background-color:#ffffff">添加单数资源的链接与我们在前面部分看到的完全相同。单数资源表示通常具有更多信息/字段以及附加链接。</span></span></span></p> <pre> <code class="language-java">@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); }</code></pre> 输出: <pre> <code class="language-json">{ "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" } } }</code></pre> <h2 style="margin-left:0px; margin-right:0px; text-align:start">总结</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#333333"><span style="font-family:"varela round",sans-serif"><span style="background-color:#ffffff">正如你看到上面的演示,使用<strong>spring hashoas</strong>模块添加HATEOAS链接非常容易和一分钟时间搞定。这将大大增加API的可发现性和实用性。<br /> <a href="http://www.leftso.com/resource/1009.html" target="_blank" >项目源码下载</a></span></span></span></p>