Spring HATEOAS 和 Entity DTO - ModelAssembler 的问题



我正在开发Spring HATEOAS REST api。现在我遇到了需要隐藏 Employee 类的某些字段(我想隐藏其中的一些(。 据我了解,必须使用DTO(数据传输对象(。所以我创建了新类(EmployeeDTO(,只有我需要的这个字段。我正在使用ModelMapper来映射适当的字段。

所以现在,我对数据类型有问题。我是否必须将控制器中的所有返回值从"员工"更改为"员工DTO"?然后更改模型汇编器中的所有内容?

或者也许DTO类应该extends RepresentationModel?(这也迫使它在实体中扩展(。 期待您的帮助,所有这些看起来有点混乱(更改所有返回类型(,我觉得应该有更智能的解决方案。

这就是我现在的做法:

EmployeeController中的方法:

@GetMapping(value = "/{id}", produces = "application/hal+json")
public EntityModel<Employee> getEmployeeById(@PathVariable Long id) {
Optional<Employee> employee = employeeService.findById(id);
return employeeModelAssembler.toModel(employee.get());
}
@GetMapping(value = "", produces = "application/hal+json")
public CollectionModel<EntityModel<Employee>> getAllEmployees() {
List<Employee> employeesList = EmployeeService.findall();
return employeeModelAssembler.toCollectionModel(EmployeesList);
}

EmployeeModelAssembler(在控制器中自动连线(:

public class EmployeeModelAssembler implements RepresentationModelAssembler<Employee, EntityModel<Employee>> {
@Override
public EntityModel<Employee> toModel(Employee employee) {
EntityModel<Employee> employeeEntityModel = EntityModel.of(employee);
Link selfLink = linkTo(methodOn(EmployeeController.class).getEmployeeById(employee.getId())).withSelfRel();
employeeEntityModel.add(selfLink);
return employeeEntityModel;
}
@Override
public CollectionModel<EntityModel<Employee>> toCollectionModel(Iterable<? extends Employee> entities) {
List<Employee> employeesList = (List<Employee>) entities;
List<EntityModel<Employee>> employeeEML = employeesList.stream().map(this::toModel).collect(Collectors.toList());
Link selfLink = linkTo(methodOn(EmployeeController.class).getAllEmployees()).withSelfRel();
return CollectionModel.of(employeeEML, selfLink);
}
}

编辑

这是我在另一个控制器中访问此 hal+json 响应的方式。目标是获取 EmployeeDTO 对象列表:

String uri = "http://localhost:8080/api/employees";
Traverson traverson = new Traverson(URI.create(uri), MediaTypes.HAL_JSON);
Traverson.TraversalBuilder tb = traverson.follow("href");
ParameterizedTypeReference<CollectionModel<EmployeeDTO>> typeReference = new ParameterizedTypeReference<CollectionModel<EmployeeDTO>>() {};
CollectionModel<EmployeeDTO> resEmployees = tb.toObject(typeReference);
Collection<EmployeeDTO> employees = resEmployees.getContent();
ArrayList<EmployeesDTO> employeesList = new ArrayList<>(employees);
for(EmployeesDTO x : employeesList) {
System.out.println(x);
System.out.println(x.getLinks());
}

如果要将API 公开的资源与 JPA 实体分离(这是一个好主意(,则必须更新控制器以处理适当的类型。

请参阅以下示例:

首先,假设您有以下 DTO:

public class EmployeeDTO extends RepresentationModel<EmployeeDTO> {
private long id;
private String surname;
private String departmentId;
// getters and setters
}

请注意,我没有将您的 JPA 实体(员工(与 DTO 混合在一起。

现在,您的控制器应已更新以返回适当的类型。

@GetMapping(value = "/{id}", produces = "application/hal+json")
public EmployeeDTO getEmployeeById(@PathVariable long id) {
Optional<Employee> employee = employeeService.findById(id);
return employeeModelAssembler.toModel(employee.get());
}
@GetMapping(value = "", produces = "application/hal+json")
public CollectionModel<EmployeeDTO> getAllEmployees() {
List<Employee> employeesList = employeeService.findAll();
return employeeModelAssembler.toCollectionModel(employeesList);
}

以及模型汇编程序的示例

@Component
public class EmployeeModelAssembler implements RepresentationModelAssembler<Employee, EmployeeDTO> {
@Override
public EmployeeDTO toModel(Employee employee) {
ModelMapper modelMapper = new ModelMapper();
EmployeeDTO employeeDto = modelMapper.map(employee, EmployeeDTO.class);
Link selfLink = linkTo(methodOn(EmployeeController.class).getEmployeeById(employee.getId())).withSelfRel();
employeeDto.add(selfLink);
return employeeDto;
}
@Override
public CollectionModel<EmployeeDTO> toCollectionModel(Iterable<? extends Employee> employeesList) {
ModelMapper modelMapper = new ModelMapper();
List<EmployeeDTO> employeeDTOS = new ArrayList<>();
for (Employee employee : employeesList){
EmployeeDTO employeeDto = modelMapper.map(employee, EmployeeDTO.class);
employeeDto.add(linkTo(methodOn(EmployeeController.class)
.getEmployeeById(employeeDto.getId())).withSelfRel());
employeeDTOS.add(employeeDto);
}
return new CollectionModel<>(employeeDTOS);
}
}

我测试了它并得到了以下响应,假设我有一个员工端点

获取员工/1

{
"id": 1,
"surname": "teste",
"departmentId": "1",
"_links": {
"self": {
"href": "http://localhost:8080/employees/1"
}
}
}

获取员工

{
"_embedded": {
"employeeDtoList": [
{
"id": 1,
"surname": "teste",
"departmentId": "1",
"_links": {
"self": {
"href": "http://localhost:8080/employees/1"
}
}
},
{
"id": 2,
"surname": "teste",
"departmentId": "2",
"_links": {
"self": {
"href": "http://localhost:8080/employees/2"
}
}
}
]
}
}

相关内容

  • 没有找到相关文章

最新更新