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

时间:2017-08-20 20:09:59

标签: java spring rest spring-boot hateoas

我使用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字段返回有关部署我的应用的服务器和路径的有效网址。例如,如果我使用localhost通过端口8080部署应用程序,我想得到这个:

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

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

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

1 个答案:

答案 0 :(得分:2)

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;

顺便说一句,所有这些都显示在你提到的教程的“创建一个RestController”部分。