[SPRING] Spring HATEOAS 임베디드 리소스 지원
SPRINGSpring HATEOAS 임베디드 리소스 지원
내 REST API에 HAL 형식을 사용하여 포함 된 리소스를 포함하고 싶습니다. 내 API에 Spring HATEOAS를 사용하고 있습니다. Spring HATEOAS는 임베디드 리소스를 지원하는 것 같습니다. 그러나 이것을 사용하는 방법에 대한 문서 나 예제는 없습니다.
누군가가 스프링 HATEOAS를 사용하여 임베디드 리소스를 포함하는 방법에 대한 예제를 제공 할 수 있습니까?
해결법
-
==============================
1.이 일을하는 공식적인 방법을 찾지 못했습니다 ... 우리가 한 일이 여기에 있습니다.
이 일을하는 공식적인 방법을 찾지 못했습니다 ... 우리가 한 일이 여기에 있습니다.
public abstract class HALResource extends ResourceSupport { private final Map<String, ResourceSupport> embedded = new HashMap<String, ResourceSupport>(); @JsonInclude(Include.NON_EMPTY) @JsonProperty("_embedded") public Map<String, ResourceSupport> getEmbeddedResources() { return embedded; } public void embedResource(String relationship, ResourceSupport resource) { embedded.put(relationship, resource); } }
우리의 자원을 HALResource로 확장했다.
-
==============================
2.HATEOAS에 대한 Spring의 문서를 읽으십시오. 기본을 얻는 데 도움이됩니다.
HATEOAS에 대한 Spring의 문서를 읽으십시오. 기본을 얻는 데 도움이됩니다.
이 답변에서 핵심 개발자는 Resource, Resources 및 PagedResources의 개념을 지적합니다.이 내용은 문서에서 다루지 않는 필수 항목입니다.
작동 원리를 이해하는 데는 시간이 걸렸으므로 몇 가지 예제를 통해 명확하게 이해해 보겠습니다.
자원
import org.springframework.hateoas.ResourceSupport; public class ProductResource extends ResourceSupport{ final String name; public ProductResource(String name) { this.name = name; } }
제어기
import org.springframework.hateoas.Link; import org.springframework.hateoas.Resource; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @RequestMapping("products/{id}", method = RequestMethod.GET) ResponseEntity<Resource<ProductResource>> get(@PathVariable Long id) { ProductResource productResource = new ProductResource("Apfelstrudel"); Resource<ProductResource> resource = new Resource<>(productResource, new Link("http://example.com/products/1")); return ResponseEntity.ok(resource); } }
응답
{ "name": "Apfelstrudel", "_links": { "self": { "href": "http://example.com/products/1" } } }
Spring HATEOAS에는 Resource가 여러 자원에 대한 응답을 반영하기 위해 사용하는 임베디드 지원이 함께 제공됩니다.
@RequestMapping("products/", method = RequestMethod.GET) ResponseEntity<Resources<Resource<ProductResource>>> getAll() { ProductResource p1 = new ProductResource("Apfelstrudel"); ProductResource p2 = new ProductResource("Schnitzel"); Resource<ProductResource> r1 = new Resource<>(p1, new Link("http://example.com/products/1")); Resource<ProductResource> r2 = new Resource<>(p2, new Link("http://example.com/products/2")); Link link = new Link("http://example.com/products/"); Resources<Resource<ProductResource>> resources = new Resources<>(Arrays.asList(r1, r2), link); return ResponseEntity.ok(resources); }
응답
{ "_links": { "self": { "href": "http://example.com/products/" } }, "_embedded": { "productResources": [{ "name": "Apfelstrudel", "_links": { "self": { "href": "http://example.com/products/1" } }, { "name": "Schnitzel", "_links": { "self": { "href": "http://example.com/products/2" } } }] } }
리소스에 주석을 달아야하는 주요 productResources를 변경하려면 다음 단계를 따르세요.
@Relation(collectionRelation = "items") class ProductResource ...
이것은 봄 포주를 시작할 필요가있을 때입니다. HALResource가 @ chris-damour에 의해 소개 된 또 다른 대답은 완벽하게 맞습니다.
public class OrderResource extends HalResource { final float totalPrice; public OrderResource(float totalPrice) { this.totalPrice = totalPrice; } }
제어기
@RequestMapping(name = "orders/{id}", method = RequestMethod.GET) ResponseEntity<OrderResource> getOrder(@PathVariable Long id) { ProductResource p1 = new ProductResource("Apfelstrudel"); ProductResource p2 = new ProductResource("Schnitzel"); Resource<ProductResource> r1 = new Resource<>(p1, new Link("http://example.com/products/1")); Resource<ProductResource> r2 = new Resource<>(p2, new Link("http://example.com/products/2")); Link link = new Link("http://example.com/order/1/products/"); OrderResource resource = new OrderResource(12.34f); resource.add(new Link("http://example.com/orders/1")); resource.embed("products", new Resources<>(Arrays.asList(r1, r2), link)); return ResponseEntity.ok(resource); }
응답
{ "_links": { "self": { "href": "http://example.com/products/1" } }, "totalPrice": 12.34, "_embedded": { "products": { "_links": { "self": { "href": "http://example.com/orders/1/products/" } }, "_embedded": { "items": [{ "name": "Apfelstrudel", "_links": { "self": { "href": "http://example.com/products/1" } }, { "name": "Schnitzel", "_links": { "self": { "href": "http://example.com/products/2" } } }] } } } }
-
==============================
3.여기에 우리가 찾은 작은 예가 있습니다. 우선 우리는 봄 - hateoas-0.16을 사용합니다.
여기에 우리가 찾은 작은 예가 있습니다. 우선 우리는 봄 - hateoas-0.16을 사용합니다.
이미징에는 임베디드 이메일 목록이있는 사용자 프로필을 반환해야하는 GET / 프로필이 있습니다.
우리는 이메일 자원을 가지고 있습니다.
@Data @JsonIgnoreProperties(ignoreUnknown = true) @Relation(value = "email", collectionRelation = "emails") public class EmailResource { private final String email; private final String type; }
프로필 응답에 포함하려는 두 개의 이메일
Resource primary = new Resource(new Email("neo@matrix.net", "primary")); Resource home = new Resource(new Email("t.anderson@matrix.net", "home"));
이러한 리소스가 포함되어 있음을 나타내려면 EmbeddedWrappers 인스턴스가 필요합니다.
import org.springframework.hateoas.core.EmbeddedWrappers EmbeddedWrappers wrappers = new EmbeddedWrappers(true);
래퍼의 도움으로 각 이메일에 대해 EmbeddedWrapper 인스턴스를 생성하고 목록에 넣을 수 있습니다.
List<EmbeddedWrapper> embeddeds = Arrays.asList(wrappers.wrap(primary), wrappers.wrap(home))
유일하게 남아있는 것은 이러한 임베디드로 프로파일 자원을 구성하는 것입니다. 아래 예제에서는 코드를 짧게하기 위해 lombok을 사용합니다.
@Data @Relation(value = "profile") public class ProfileResource { private final String firstName; private final String lastName; @JsonUnwrapped private final Resources<EmbeddedWrapper> embeddeds; }
@JsonUnwrapped 내장 필드에 주석 달기
그리고 우리는이 모든 것을 컨트롤러에서 돌려 줄 준비가되어 있습니다.
... Resources<EmbeddedWrapper> embeddedEmails = new Resources(embeddeds, linkTo(EmailAddressController.class).withSelfRel()); return ResponseEntity.ok(new Resource(new ProfileResource("Thomas", "Anderson", embeddedEmails), linkTo(ProfileController.class).withSelfRel())); }
이제 응답에서 우리는
{ "firstName": "Thomas", "lastName": "Anderson", "_links": { "self": { "href": "http://localhost:8080/profile" } }, "_embedded": { "emails": [ { "email": "neo@matrix.net", "type": "primary" }, { "email": "t.anderson@matrix.net", "type": "home" } ] } }
Resources
임베디드 사용에 흥미로운 부분은 서로 다른 리소스를 넣을 수 있고 릴레이션별로 자동으로 그룹화한다는 점입니다. 이를 위해 org.springframework.hateoas.core 패키지의 주석 @Relation을 사용합니다. 또한 HAL에 임베디드 리소스에 대한 좋은 기사가 있습니다.
-
==============================
4.일반적으로 HATEOAS는 REST 출력을 나타내는 POJO를 생성하고 HATEOAS가 제공 한 ResourceSupport를 확장해야합니다. POJO를 추가로 만들지 않고이 작업을 수행 할 수 있으며 아래 코드와 같이 Resource, Resources 및 Link 클래스를 직접 사용할 수 있습니다.
일반적으로 HATEOAS는 REST 출력을 나타내는 POJO를 생성하고 HATEOAS가 제공 한 ResourceSupport를 확장해야합니다. POJO를 추가로 만들지 않고이 작업을 수행 할 수 있으며 아래 코드와 같이 Resource, Resources 및 Link 클래스를 직접 사용할 수 있습니다.
@RestController class CustomerController { List<Customer> customers; public CustomerController() { customers = new LinkedList<>(); customers.add(new Customer(1, "Peter", "Test")); customers.add(new Customer(2, "Peter", "Test2")); } @RequestMapping(value = "/customers", method = RequestMethod.GET, produces = "application/hal+json") public Resources<Resource> getCustomers() { List<Link> links = new LinkedList<>(); links.add(linkTo(methodOn(CustomerController.class).getCustomers()).withSelfRel()); List<Resource> resources = customerToResource(customers.toArray(new Customer[0])); return new Resources<>(resources, links); } @RequestMapping(value = "/customer/{id}", method = RequestMethod.GET, produces = "application/hal+json") public Resources<Resource> getCustomer(@PathVariable int id) { Link link = linkTo(methodOn(CustomerController.class).getCustomer(id)).withSelfRel(); Optional<Customer> customer = customers.stream().filter(customer1 -> customer1.getId() == id).findFirst(); List<Resource> resources = customerToResource(customer.get()); return new Resources<Resource>(resources, link); } private List<Resource> customerToResource(Customer... customers) { List<Resource> resources = new ArrayList<>(customers.length); for (Customer customer : customers) { Link selfLink = linkTo(methodOn(CustomerController.class).getCustomer(customer.getId())).withSelfRel(); resources.add(new Resource<Customer>(customer, selfLink)); } return resources; } }
-
==============================
5.위의 답변을 결합하여 훨씬 쉬운 접근 방식을 만들었습니다.
위의 답변을 결합하여 훨씬 쉬운 접근 방식을 만들었습니다.
return resWrapper(domainObj, embeddedRes(domainObj.getSettings(), "settings"))
이것은 사용자 정의 유틸리티 클래스입니다 (아래 참조). 노트 :
유틸리티 클래스를 만듭니다.
import com.fasterxml.jackson.annotation.JsonUnwrapped; import java.util.Arrays; import org.springframework.hateoas.Link; import org.springframework.hateoas.Resource; import org.springframework.hateoas.Resources; import org.springframework.hateoas.core.EmbeddedWrapper; import org.springframework.hateoas.core.EmbeddedWrappers; public class ResourceWithEmbeddable<T> extends Resource<T> { @SuppressWarnings("FieldCanBeLocal") @JsonUnwrapped private Resources<EmbeddedWrapper> wrappers; private ResourceWithEmbeddable(final T content, final Iterable<EmbeddedWrapper> wrappers, final Link... links) { super(content, links); this.wrappers = new Resources<>(wrappers); } public static <T> ResourceWithEmbeddable<T> resWrapper(final T content, final EmbeddedWrapper... wrappers) { return new ResourceWithEmbeddable<>(content, Arrays.asList(wrappers)); } public static EmbeddedWrapper embeddedRes(final Object source, final String rel) { return new EmbeddedWrappers(false).wrap(source, rel); } }
이 패키지를 사용하려면 서비스 클래스에 정적 static package.ResourceWithEmbeddable. *을 가져와야합니다.
JSON은 다음과 같습니다.
{ "myField1": "1field", "myField2": "2field", "_embedded": { "settings": [ { "settingName": "mySetting", "value": "1337", "description": "umh" }, { "settingName": "other", "value": "1488", "description": "a" },... ] } }
from https://stackoverflow.com/questions/25858698/spring-hateoas-embedded-resource-support by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring에서 다중 ViewResolvers를 사용하는 방법? (0) | 2019.01.26 |
---|---|
[SPRING] Spring MVC에서 컨트롤러의 라이프 사이클 (0) | 2019.01.26 |
[SPRING] 스프링 3 MVC 애플리케이션을위한 maven 2 아키타 입을 가지고 있습니까? (0) | 2019.01.26 |
[SPRING] 스프링 ApplicationContext를 닫는 방법? (0) | 2019.01.26 |
[SPRING] intellij가 autowired 저장소에 대해 발견 된 유형의 빈을 잘못 말함 (0) | 2019.01.26 |