복붙노트

[SPRING] 스프링 HATEOAS와의 정식 _links

SPRING

스프링 HATEOAS와의 정식 _links

Spring.io 가이드 "REST를 사용하여 JPA 데이터에 액세스"와 비슷한 RESTful 웹 서비스를 구축 중입니다. 아래의 샘플 출력을 재현하려면 다음과 같이 Person에 ManyToOne-Relation을 추가하면됩니다.

// ...

@Entity
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  private String firstName;
  private String lastName;

  @ManyToOne
  private Person father;

  // getters and setters
}

몇 가지 샘플 데이터를 추가 한 후에 GET 요청이 발생합니다.

{
  "firstName" : "Paul",
  "lastName" : "Mustermann",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/1"
    },
    "father" : {
      "href" : "http://localhost:8080/people/1/father"
    }
  }
}

그러나 Paul의 아버지가 ID 2로 저장되어 있기 때문에, 우리가 원하는 결과는 관계에 대한 표준 URL이됩니다.

// ...
    "father" : {
      "href" : "http://localhost:8080/people/2"
    }
// ...

물론 아버지가 일부 사람에게 null 인 경우 문제가 발생할 것입니다. (OK, 여기서는 별 의미가 없지만 ...)),이 경우에는 JSON에서 링크를 전혀 렌더링하지 않으려합니다.

우리는 이미 이것을 달성하기 위해 ResourceProcessor를 구현하려고 시도했지만, 프로세서가 호출 될 즈음에는 링크가 아직 채워지지 않은 것으로 보입니다. 우리는 원하는 정식 URL을 가리키는 추가 링크를 추가 할 수 있었지만 나중에 링크를 수정하는 데 실패했습니다.

질문 : 모든 리소스에 대해 링크 생성을 사용자 정의하는 일반적인 방법이 있습니까?

정식 URL에 대한 필요성을 명확히하기 위해 : SproutCore Javascript 프레임 워크를 사용하여 RESTful 웹 서비스에 액세스합니다. Spring이 생성하는 JSON 출력의 일반적인 핸들러를 구현 한 데이터 소스의 "ORM과 유사한"추상화를 사용합니다. 모든 사람을 질의 할 때 우리는 클라이언트 측 데이터 소스와 q 관계를 가진 n 명을 다른 사람들과 동기화하기 위해 n * (1 + q) 요청 (n 대신)을 보내야합니다. 이는 기본 "비표준"링크가 설정되는 아버지 또는 아버지의 ID에 대한 정보가 전혀 포함되어 있지 않기 때문입니다. 초기 응답이 처음에 조금 더 많은 정보를 포함한다면 쉽게 피할 수있는 엄청난 양의 불필요한 요청이 발생하는 것 같습니다.

또 다른 해결책은 아버지의 ID를 관계에 추가하는 것입니다 (예 :

"father" : {
  "href" : "http://localhost:8080/people/1/father",
  "id" : 2
}

해결법

  1. ==============================

    1.Spring Data Rest 팀은 속성이 왜 그런 식으로 링크로 렌더링되는지 설명했습니다. SDR에서 생성 된 링크를 억제하고 ResourceProcessor를 구현함으로써 원하는 것을 얻을 수 있다고 말했 다. 따라서 Person 클래스는 아래처럼 보일 것입니다. @RestResource (exported = false) 주석을 참고하여 링크를 표시하지 않습니다.

    Spring Data Rest 팀은 속성이 왜 그런 식으로 링크로 렌더링되는지 설명했습니다. SDR에서 생성 된 링크를 억제하고 ResourceProcessor를 구현함으로써 원하는 것을 얻을 수 있다고 말했 다. 따라서 Person 클래스는 아래처럼 보일 것입니다. @RestResource (exported = false) 주석을 참고하여 링크를 표시하지 않습니다.

    @Entity
    public class Person {
    
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private long id;
    
      private String firstName;
      private String lastName;
    
      @ManyToOne
      @RestResource(exported = false)
      private Person father;
    
      // getters and setters
    }
    

    ResourceProcessor 클래스는 다음과 같습니다.

    public class EmployeeResourceProcessor implements
            ResourceProcessor<Resource<Person>> {
    
        @Autowired
        private EntityLinks entityLinks;
    
        @Override
        public Resource<Person> process(Resource<Person> resource) {
            Person person = resource.getContent();
            if (person.getFather() != null) {
                resource.add(entityLinks.linkForSingleResour(Person.class, person.getFather().getId())
                    .withRel("father"));
            }
            return resource;
        }
    
    }
    

    위의 솔루션은 Person과 함께 아버지의 가치를 열심히 가져 오는 경우에만 작동합니다. 그렇지 않으면 당신은 fatherId 속성이 있어야하며 father 속성 대신 사용하십시오. Jackson @ignore ...를 사용하여 JSON에 대한 응답으로 fatherId를 숨기는 것을 잊지 마십시오.

    참고 : 나는 이것을 직접 테스트하지는 않았지만 그것이 작동 할 것이라고 추측했다.

  2. ==============================

    2.같은 문제가 발생했기 때문에 spring-data-rest에서 Jira 문제를 만들었습니다. https://jira.spring.io/browse/DATAREST-682

    같은 문제가 발생했기 때문에 spring-data-rest에서 Jira 문제를 만들었습니다. https://jira.spring.io/browse/DATAREST-682

    충분한 사람들이 투표한다면, 개발자 중 일부는 그것을 구현하도록 설득 할 수 있습니다 :-).

  3. ==============================

    3.이상한 당신이 표준 링크를 표시하려고합니다. / father에있는 리소스가 검색되면 자체 링크가 정식이어야합니다 ...하지만 아버지 관계가 정식이되도록 강제하는 좋은 이유는 없습니다. 아마도 일부 캐시 체계일까요?

    이상한 당신이 표준 링크를 표시하려고합니다. / father에있는 리소스가 검색되면 자체 링크가 정식이어야합니다 ...하지만 아버지 관계가 정식이되도록 강제하는 좋은 이유는 없습니다. 아마도 일부 캐시 체계일까요?

    귀하의 특정 질문에 ... 당신은 자동 생성 컨트롤러에 의존하므로 많은 링크에 대한 결정을 내릴 권리를 포기했습니다. 자신 만의 PersonController를 가지고 있다면 링크 구조를 담당하게 될 것입니다. 자체 컨트롤러를 만든 경우 EntityLinks https://github.com/spring-projects/spring-hateoas#entitylinks를 Father 's ID ..와 함께 사용할 수 있습니다 .IE

    @Controller
    @ExposesResourceFor(Person.class)
    @RequestMapping("/people")
    class PersonController {
    
      @RequestMapping
      ResponseEntity people(…) { … }
    
      @RequestMapping("/{id}")
      ResponseEntity person(@PathVariable("id") … ) {
        PersonResource p = ....
        if(p.father){
          p.addLink(entityLinks.linkToSingleResource(Person.class, orderId).withRel("father");
        }
      }
    }
    

    하지만 URL을 변경하는 작업이 많은 것처럼 보입니다.

  4. from https://stackoverflow.com/questions/24570279/canonical-links-with-spring-hateoas by cc-by-sa and MIT license