共计 6554 个字符,预计需要花费 17 分钟才能阅读完成。
书接上文⬆⬆⬆一直倒退的 REST API 通过一个额定的库和几行额定的代码,您已将超媒体增加到您的应用程序中。但这并不是使您的服务成为 RESTful 所需的惟一事件。REST 的一个重要方面是它既不是技术堆栈也不是繁多规范。REST 是架构束缚的汇合,采纳这些束缚会使您的应用程序更具弹性。弹性的一个关键因素是,当您对服务进行降级时,您的客户不会蒙受停机工夫的困扰。在“过来”的日子里,降级因毁坏客户端而臭名远扬。换句话说,降级到服务器须要更新客户端。在当今时代,破费数小时甚至数分钟进行降级的停机工夫可能会造成数百万美元的支出损失。有些公司要求您向管理层提出一个打算,以尽量减少停机工夫。过来,您能够在周日凌晨 2:00 进行降级,此时负载最低。但在明天的基于互联网的电子商务中,国内客户在其余时区,这样的策略就没有那么无效了。基于 SOAP 的服务和基于 CORBA 的服务十分软弱。很难推出能够同时反对新旧客户端的服务器。应用基于 REST 的实际,这要容易得多。特地是应用 Spring 堆栈。反对对 API 的更改设想一下这个设计问题:您曾经推出了一个具备 Employee 基于此记录的零碎。该零碎大受欢迎。你曾经把你的零碎卖给了有数的企业。忽然,须要拆分员工的姓名 firstName 并 lastName 呈现。哦哦。没想到。在您关上课程并用 andEmployee 替换单个字段之前,请停下来想一想。这会毁坏任何客户吗?降级它们须要多长时间。您甚至管制所有拜访您服务的客户端吗?namefirstNamelastName 停机工夫 = 损失金钱。管理层筹备好了吗?有一个比 REST 早几年的旧策略。永远不要删除数据库中的列。— 未知您始终能够将列(字段)增加到数据库表中。但不要带走一个。RESTful 服务中的原理是雷同的。将新字段增加到您的 JSON 示意中,但不要带走任何字段。像这样:反对多个客户端的 JSON{“id”: 1, “firstName”: “Bilbo”, “lastName”: “Baggins”, “role”: “burglar”, “name”: “Bilbo Baggins”, “_links”: { “self”: { “href”: “http://localhost:8080/employees/1”}, “employees”: {“href”: “http://localhost:8080/employees”} }}请留神此格局如何显示 firstName, lastName, AND name?尽管它蕴含反复信息,但其目标是同时反对新老客户。这意味着您能够降级服务器,而无需同时降级客户端。一个能够缩小停机工夫的好动作。您不仅应该以“旧形式”和“新形式”显示这些信息,还应该以两种形式解决传入的数据。如何?简略的。像这样:解决“旧”和“新”客户的员工记录 package payroll;import java.util.Objects;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;@Entityclass Employee {private @Id @GeneratedValue Long id; private String firstName; private String lastName; private String role; Employee() {} Employee(String firstName, String lastName, String role) {this.firstName = firstName; this.lastName = lastName; this.role = role;} public String getName() { return this.firstName + ” ” + this.lastName;} public void setName(String name) {String[] parts = name.split(” “); this.firstName = parts[0]; this.lastName = parts[1]; } public Long getId() { return this.id;} public String getFirstName() { return this.firstName;} public String getLastName() { return this.lastName;} public String getRole() { return this.role;} public void setId(Long id) {this.id = id;} public void setFirstName(String firstName) {this.firstName = firstName;} public void setLastName(String lastName) {this.lastName = lastName;} public void setRole(String role) {this.role = role;} @Override public boolean equals(Object o) {if (this == o) return true; if (!(o instanceof Employee)) return false; Employee employee = (Employee) o; return Objects.equals(this.id, employee.id) && Objects.equals(this.firstName, employee.firstName) && Objects.equals(this.lastName, employee.lastName) && Objects.equals(this.role, employee.role); } @Override public int hashCode() { return Objects.hash(this.id, this.firstName, this.lastName, this.role); } @Override public String toString() { return “Employee{” + “id=” + this.id + “, firstName='” + this.firstName + ‘\” + “, lastName='” + this.lastName + ‘\” + “, role='” + this.role + ‘\” + ‘}’; }}这个类与以前版本的 Employee. 让咱们回顾一下变动:字段 name 已替换为 firstName 和 lastName。定义了旧 name 属性的“虚构”吸气剂。getName()它应用 firstNameandlastName 字段来产生一个值。name 还定义了旧属性的“虚构”设置器,setName(). 它解析传入的字符串并将其存储到适当的字段中。当然,并非对 API 的每一次更改都像拆分字符串或合并两个字符串一样简略。然而对于大多数场景来说,想出一组转换必定不是不可能的,对吧?不要遗记更改预加载数据库的形式(在 中 LoadDatabase)以应用这个新的构造函数。log.info(“Preloading ” + repository.save(new Employee(“Bilbo”, “Baggins”, “burglar”)));log.info(“Preloading ” + repository.save(new Employee(“Frodo”, “Baggins”, “thief”))); 适当的反馈朝着正确方向迈出的另一个步骤是确保您的每个 REST 办法都返回正确的响应。像这样更新 POST 办法:解决“旧”和“新”客户端申请的 POST@PostMapping(“/employees”)ResponseEntity<?> newEmployee(@RequestBody Employee newEmployee) {EntityModel<Employee> entityModel = assembler.toModel(repository.save(newEmployee)); return ResponseEntity // .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) // .body(entityModel);}复制新 Employee 对象像以前一样保留。然而生成的对象应用 EmployeeModelAssembler.Spring MVCResponseEntity 用于创立 HTTP 201 Created 状态音讯。这种类型的响应通常蕴含一个 Location 响应头,咱们应用从模型的自相干链接派生的 URI。此外,返回已保留对象的基于模型的版本。通过这些调整,您能够应用雷同的端点来创立新的员工资源,并应用遗留 name 字段:$ curl -v -X POST localhost:8080/employees -H ‘Content-Type:application/json’ -d ‘{“name”: “Samwise Gamgee”, “role”: “gardener”}’ 输入如下所示:> POST / 员工 HTTP/1.1> 主机:本地主机:8080> 用户代理:curl/7.54.0> 承受:*/*> 内容类型:应用程序 /json> 内容长度:46>< 地位:http://localhost:8080/employees/3< 内容类型:application/hal+json;charset=UTF-8< 传输编码:分块 < 日期:格林威治规范工夫 2018 年 8 月 10 日星期五 19:44:43<{“身份证”:3,“firstName”: “Samwise”, “lastName”: “Gamgee”,“角色”:“园丁”,“name”: “Samwise Gamgee”,“_链接”:{“本人”:{“href”:“http://localhost:8080/employees/3”},“雇员”:{“href”: “http://localhost:8080/employees”} }}这不仅使生成的对象在 HAL(name 以及 firstName/ lastName)中出现,而且 Location 标头也填充了 http://localhost:8080/employees/3. 超媒体驱动的客户端能够抉择“冲浪”到这个新资源并持续与之交互。PUT 控制器办法须要相似的调整:为不同的客户端解决 PUT@PutMapping(“/employees/{id}”)ResponseEntity<?> replaceEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {Employee updatedEmployee = repository.findById(id) // .map(employee -> { employee.setName(newEmployee.getName()); employee.setRole(newEmployee.getRole()); return repository.save(employee); }) // .orElseGet(() -> { newEmployee.setId(id); return repository.save(newEmployee); }); EntityModel<Employee> entityModel = assembler.toModel(updatedEmployee); return ResponseEntity // .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) // .body(entityModel);}复制而后应用 将操作 Employee 构建的对象包装到一个对象中。应用该办法,您能够检索由 rel 创立的。这个办法返回一个必须用办法变成一个的。save()EmployeeModelAssemblerEntityModel<Employee>getRequiredLink()LinkEmployeeModelAssemblerSELFLinkURItoUri 因为咱们想要一个比 200 OK 更具体的 HTTP 响应代码,咱们将应用 Spring MVC 的 ResponseEntity 包装器。它有一个不便的静态方法 created(),咱们能够在其中插入资源的 URI。HTTP 201 Created 是否具备正确的语义值得商讨,因为咱们不肯定要“创立”新资源。但它预装了一个 Location 响应头,所以用它运行。$ curl -v -X PUT localhost:8080/employees/3 -H ‘Content-Type:application/json’ -d ‘{“name”: “Samwise Gamgee”, “role”: “ring bearer”}’ TCP_NODELAY 设置 连贯到 localhost (::1) 端口 8080 (#0)> PUT /employees/3 HTTP/1.1> 主机:本地主机:8080> 用户代理:curl/7.54.0> 承受:/> 内容类型:应用程序 /json> 内容长度:49>< HTTP/1.1 201< 地位:http://localhost:8080/employe…; 内容类型:application/hal+json;charset=UTF-8< 传输编码:分块 < 日期:格林威治规范工夫 2018 年 8 月 10 日星期五 19:52:56{“身份证”:3,”firstName”: “Samwise”,”lastName”: “Gamgee”,“角色”:“戒指持有者”,”name”: “Samwise Gamgee”,“_链接”:{“本人”:{“href”:“http://localhost:8080/employe…”},“雇员”:{“href”: “http://localhost:8080/employees”}}} 该员工资源现已更新,并且地位 URI 已发回。最初,适当地更新 DELETE 操作:解决 DELETE 申请 @DeleteMapping(“/employees/{id}”)ResponseEntity<?> deleteEmployee(@PathVariable Long id) {repository.deleteById(id); return ResponseEntity.noContent().build();}复制这将返回 HTTP 204 No Content 响应。$ curl -v -X 删除本地主机:8080/employees/1 TCP_NODELAY 设置 连贯到 localhost (::1) 端口 8080 (#0)> 删除 /employees/1 HTTP/1.1> 主机:本地主机:8080> 用户代理:curl/7.54.0> 承受:/>< HTTP/1.1 204< 日期:格林威治规范工夫 2018 年 8 月 10 日星期五 21:30:26 对类中的字段进行更改 Employee 须要与您的数据库团队协调,以便他们能够正确地将现有内容迁徙到新列中。您当初已筹备好进行降级,不会烦扰现有客户端,而新客户端能够利用这些加强性能!顺便说一句,您是否放心通过网络发送太多信息?在某些每个字节都很重要的零碎中,API 的倒退可能须要退居二线。然而在你测量之前不要谋求这种过早的优化。#java##spring 认证 ## 程序员##spring##2022 待业季#2022 待业季|Spring 认证教你,如何应用 Spring 构建 REST 服务 2022 待业季|Spring 认证教你,如何应用 Spring 构建 REST 服务(二)2022 待业季|Spring 认证教你,如何应用 Spring 构建 REST 服务(三)
以上就是明天对于 Spring 的一些探讨,对你有帮忙吗?如果你有趣味深刻理解,欢送到 Spring 中国教育管理中心留言交换!