如何在不修改整个响应的情况下 return 基于 HATEOAS 的 URL?

How to return URLs based on HATEOAS without modifying the whole response?

我使用 Spring Boot 开发了一项服务。这是代码(简化):

@RestController
@RequestMapping("/cars")
public class CarController {
    @Autowired
    private CarService carService;

    @Autowired
    private CarMapper carMapper;

    @GetMapping("/{id}")
    public CarDto findById(@PathVariable Long id) {
        Car car = carService.findById(id);
        return carMapper.mapToCarDto(car);
    }
}

CarMapper 是使用 mapstruct 定义的。这是代码(也经过简化):

@Mapper(componentModel="spring",
        uses={ MakeModelMapper.class })
public interface CarMapper {
    @Mappings({
        //fields omitted
        @Mapping(source="listaImagenCarro", target="rutasImagenes")
    })
    CarDto mapToCarDto(Car car);

    String CAR_IMAGE_URL_FORMAT = "/cars/%d/images/%d"
    /*
        MapStruct will invoke this method to map my car image domain object into a String. Here's my issue.
    */
    default String mapToUrl(CarImage carImage) {
        if (carImage == null) return null;
        return String.format(
                   CAR_IMAGE_URL_FORMAT,
                   carImage.getCar().getId(),
                   carImage.getId()
               );
    }
}

调用服务时得到的JSON响应:

{
    "id": 9,
    "make": { ... },
    "model": { ... },
    //more fields...
    //the urls for the car images
    "images": [
        "/cars/9/images/1"
    ]
}

我需要 images 字段 returns 关于我的应用部署的服务器和路径的有效 URL。例如,如果我通过端口 8080 使用 localhost 部署应用程序,我想得到这个:

{
    "id": 9,
    "make": { ... },
    "model": { ... },
    //more fields...
    "imagenes": [
        "http://localhost:8080/cars/9/images/1"
    ]
}

我已经查看了 Building a Hypermedia-Driven RESTful Web Service,这似乎是我想要的。除了我只需要这些 url,我不想改变我的整个响应对象。

还有其他方法可以实现吗?

Spring HATEOAS 专门为此提供了 LinkBuilder 服务。

尝试以下操作:

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
//...//

linkTo(methodOn(CarController.class).findById(9)).withRel("AddYourRelHere");

这应该输出一个指向您的资源的绝对 URL。您没有遵守 HAL 约定,因此您应该更改或删除 "withRel("")"

部分

您可以将此添加到要更改的特定 DTO:

CarDto dto = carMapper.mapToCarDto(car);
if(dto.matches(criteria)){
    dto.setUrl(linkTo...);
}
return dto;

顺便说一下,所有这些都显示在您提到的教程的 "Create a RestController" 部分。