복붙노트

[SPRING] 맞춤 컨트롤러가 Spring-Data-Rest / Spring-Hateoas 클래스의 형식을 미러링하도록 만들 수 있습니까?

SPRING

맞춤 컨트롤러가 Spring-Data-Rest / Spring-Hateoas 클래스의 형식을 미러링하도록 만들 수 있습니까?

나는 정말로 간단해야한다고 생각하는 것을하려고 노력하고 있습니다. 나는 Question 객체를 가지고 있으며, Spring-Boot, Spring-Data-Rest, Spring-Hateo와 함께 설치한다. 모든 기본 작동합니다. 나는 / questions url과 동일한 형식으로 List 를 반환하는 사용자 정의 컨트롤러를 추가하여 둘 사이의 응답이 호환되도록하고 싶습니다.

여기 내 컨트롤러가 있습니다 :

@Controller
public class QuestionListController {

    @Autowired private QuestionRepository questionRepository;

    @Autowired private PagedResourcesAssembler<Question> pagedResourcesAssembler;

    @Autowired private QuestionResourceAssembler questionResourceAssembler;

    @RequestMapping(
            value = "/api/questions/filter", method = RequestMethod.GET,
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody PagedResources<QuestionResource> filter(
            @RequestParam(value = "filter", required = false) String filter,
            Pageable p) {

        // Using queryDSL here to get a paged list of Questions
        Page<Question> page = 
            questionRepository.findAll(
                QuestionPredicate.findWithFilter(filter), p);

        // Option 1 - default resource assembler
        return pagedResourcesAssembler.toResource(page);

        // Option 2 - custom resource assembler
        return pagedResourcesAssembler.toResource(page, questionResourceAssembler);
    }

}

옵션 1 : 제공된 SimplePagedResourceAssembler를 사용합니다.

이 옵션의 문제점은 필요한 _links가 렌더링되지 않습니다. 이것에 대한 해결책이 있다면 가장 쉬운 해결책이 될 것입니다.

옵션 2 : 오픈 리소스 어셈블러 구현

이 옵션의 문제점은 Spring-Hateoas 문서에 따라 QuestionResourceAssembler를 구현하면 QuestionResource가 Question의 거의 중복되는 경로로 이어지고 어셈블러가 두 객체간에 수동으로 데이터를 복사해야한다는 것입니다. 관련 _links를 모두 직접 작성하십시오. 이것은 많은 낭비 된 노력처럼 보입니다.

무엇을해야합니까?

Spring이 QuestionRepository를 내보낼 때 이미이 모든 작업을 수행하는 코드를 생성했다는 것을 알고 있습니다. 해당 코드를 탭하여 사용할 수있는 방법이 있습니까? 내 컨트롤러의 출력이 생성 된 응답과 원활하고 상호 교환 가능하도록하려면 어떻게해야합니까?

해결법

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

    1.Spring Data Rest의 동작을 완전히 모방하는 방법을 찾았습니다. 속임수는 PagedResourcesAssembler와 인수가 삽입 된 PersistentEntityResourceAssembler 인스턴스를 조합하여 사용합니다. 다음과 같이 컨트롤러를 정의하십시오.

    Spring Data Rest의 동작을 완전히 모방하는 방법을 찾았습니다. 속임수는 PagedResourcesAssembler와 인수가 삽입 된 PersistentEntityResourceAssembler 인스턴스를 조합하여 사용합니다. 다음과 같이 컨트롤러를 정의하십시오.

    @RepositoryRestController
    @RequestMapping("...")
    public class ThingController {
    
        @Autowired
        private PagedResourcesAssembler pagedResourcesAssembler;
    
        @SuppressWarnings("unchecked") // optional - ignores warning on return statement below...
        @RequestMapping(value = "...", method = RequestMethod.GET)
        @ResponseBody
        public PagedResources<PersistentEntityResource> customMethod(
                ...,
                Pageable pageable,
                // this gets automatically injected by Spring...
                PersistentEntityResourceAssembler resourceAssembler) {
    
            Page<MyEntity> page = ...;
            ...
            return pagedResourcesAssembler.toResource(page, resourceAssembler);
        }
    }
    

    이것은 Spring이 PersistentEntityResourceAssembler를 삽입하기 위해 사용하는 PersistentEntityResourceAssemblerArgumentResolver의 존재 덕분입니다. 결과는 저장소 쿼리 방법 중 하나에서 기대할 수있는 결과입니다.

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

    2.이 오래된 질문에 대한 답변이 업데이트되었습니다. 이제 PersistentEntityResourceAssembler를 사용하여이 작업을 수행 할 수 있습니다.

    이 오래된 질문에 대한 답변이 업데이트되었습니다. 이제 PersistentEntityResourceAssembler를 사용하여이 작업을 수행 할 수 있습니다.

    @RepositoryRestController 내부 :

    @RequestMapping(value = "somePath", method = POST)
    public @ResponseBody PersistentEntityResource postEntity(@RequestBody Resource<EntityModel> newEntityResource, PersistentEntityResourceAssembler resourceAssembler)
    {
      EntityModel newEntity = newEntityResource.getContent();
      // ... do something additional with new Entity if you want here ...  
      EntityModel savedEntity = entityRepo.save(newEntity);
    
      return resourceAssembler.toResource(savedEntity);  // this will create the complete HATEOAS response
    }
    
  3. ==============================

    3.나는이 문제를 비교적 직접적으로 해결했다고 믿는다.

    나는이 문제를 비교적 직접적으로 해결했다고 믿는다.

    SimplePagedResourceAssembler 구현을 읽은 후에 나는 하이브리드 솔루션이 작동 할 수 있음을 깨달았습니다. 제공된 Resource 클래스는 엔티티를 올바르게 렌더링하지만 링크는 포함하지 않으므로 엔티티를 추가하면됩니다.

    내 질문 ResourceAssembler 구현은 다음과 같습니다.

    @Component
    public class QuestionResourceAssembler implements ResourceAssembler<Question, Resource<Question>> {
    
        @Autowired EntityLinks entityLinks;
    
        @Override
        public Resource<Question> toResource(Question question) {
            Resource<Question> resource = new Resource<Question>(question);
    
            final LinkBuilder lb = 
                entityLinks.linkForSingleResource(Question.class, question.getId());
    
            resource.add(lb.withSelfRel());
            resource.add(lb.slash("answers").withRel("answers"));
            // other links
    
            return resource;
        }
    }
    

    그게 끝나면 내 컨트롤러에서 위의 옵션 2를 사용했습니다.

        return pagedResourcesAssembler.toResource(page, questionResourceAssembler);
    

    이것은 잘 작동하며 너무 많은 코드가 아닙니다. 유일한 번거 로움은 필요한 각 참조에 대한 링크를 수동으로 추가해야한다는 것입니다.

  4. from https://stackoverflow.com/questions/26538156/can-i-make-a-custom-controller-mirror-the-formatting-of-spring-data-rest-sprin by cc-by-sa and MIT license