我们是否注意到在创建单个雇员链接时的重复?两次显示了提供指向雇员的单个链接以及指向聚合根的 “雇员” 的链接的代码。如果那引起我们的关注,那就好!有一个解决方案。
简而言之,我们需要定义一个将 Employee
对象转换为 EntityModel<Employee>
对象的函数。尽管我们可以自己轻松地编写该方法,但在实现 Spring HATEOAS 的 RepresentationModelAssember
接口的过程中会有很多好处。
evolution/src/main/java/payroll/EmployeeResourceAssembler.java
package payroll;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.stereotype.Component;
@Component
class EmployeeModelAssembler implements RepresentationModelAssembler<Employee, EntityModel<Employee>> {
@Override
public EntityModel<Employee> toModel(Employee employee) {
return new EntityModel<>(employee,
linkTo(methodOn(EmployeeController.class).one(employee.getId())).withSelfRel(),
linkTo(methodOn(EmployeeController.class).all()).withRel("employees"));
}
}
该简单的接口有一个方法:toModel()
。它基于将非资源对象(Employee
)转换为基于资源的对象(EntityModel<Employee>
)。
我们之前在控制器中看到的所有代码都可以移入该类。通过应用 Spring 框架的 @Component
,该组件将在应用启动时自动创建。
Spring HATEOAS 针对所有资源的抽象基类是
RepresentationModel
。但是为简单起见,教程建议使用EntityModel<T>
作为我们的机制来轻松包装所有 POJO 作为资源。
要利用该组装器,只需要将其注入 EmployeeController
的构造器中即可对其进行变更。
将 EmployeeResourceAssembler 注入控制器。
@RestController
class EmployeeController {
private final EmployeeRepository repository;
private final EmployeeModelAssembler assembler;
EmployeeController(EmployeeRepository repository,
EmployeeModelAssembler assembler) {
this.repository = repository;
this.assembler = assembler;
}
...
}
在这里,我们可以在单项雇员方法中使用它:
使用组装器获取单项资源。
@GetMapping("/employees/{id}")
EntityModel<Employee> one(@PathVariable Long id) {
Employee employee = repository.findById(id)
.orElseThrow(() -> new EmployeeNotFoundException(id));
return assembler.toModel(employee);
}
该段代码几乎是相同的,除了我们不是在这里创建 EntityModel<Employee>
示例,而是将其委托给了组装器。也许看起来不多?
在聚合根控制器方法中应用相同的内容会更加令人印象深刻:
使用组装器获取聚合根资源。
@GetMapping("/employees")
CollectionModel<EntityModel<Employee>> all() {
List<EntityModel<Employee>> employees = repository.findAll().stream()
.map(assembler::toModel)
.collect(Collectors.toList());
return new CollectionModel<>(employees,
linkTo(methodOn(EmployeeController.class).all()).withSelfRel());
}
再次,代码几乎相同,但是我们可以将所有 EntityModel<Employee>
创建逻辑替换为 map(assembler::toModel)
。借助 Java 8 方法引用,可以非常轻松地将其插入并简化我们的控制器。
Spring HATEOAS 的主要涉及目标是使做 “The Right Thing™” 变得容易。在该情况下,无需对事物进行硬编码即可将超媒体添加到我们的服务器中。
在该阶段,我们已经创建了一个 Spring MVC REST 控制器,该控制器实际上可以生成超媒体支持的内容!不使用 HAL 的客户端在使用纯数据时可以忽略多余的比特。会 HAL 的客户端可以浏览我们的授权 API。
但这并不是用 Spring 构建真正 RESTful 服务的唯一方式。