복붙노트

[SPRING] Spring 데이터 저장소의 커스텀 메소드 구현 및 REST를 통한 노출

SPRING

Spring 데이터 저장소의 커스텀 메소드 구현 및 REST를 통한 노출

Spring 데이터 저장소를위한 1.3 사용자 정의 구현에서 설명 된대로 Spring 데이터 저장소 인 PersonRepository에 사용자 정의 메소드를 추가하고 REST를 통해이 메소드를 노출하려고합니다. 초기 코드는 REST 샘플을 사용하여 JPA 데이터에 액세스 한 것입니다. 다음은 추가 / 수정 된 클래스의 코드입니다.

interface PersonRepositoryCustom {
  List<Person> findByFistName(String name);
}

class PersonRepositoryImpl implements PersonRepositoryCustom, InitializingBean {
  @Override
  public void afterPropertiesSet() throws Exception {
    // initialization here
  }
  @Override
  public List<Person> findByFistName(String name) {
    // find the list of persons with the given firstname
  }
}

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
  List<Person> findByLastName(@Param("name") String name);  
}

애플리케이션을 실행하고 http : // localhost : 8080 / portfolio / search /를 방문하면 다음과 같은 응답 본문이 표시됩니다.

{
  "_links" : {
    "findByLastName" : {
      "href" : "http://localhost:8080/people/search/findByLastName{?name}",
      "templated" : true
     }
  }
}

findByFirstName이 PersonRepository 인터페이스에서 사용 가능하더라도 노출되지 않는 이유는 무엇입니까?

또한 동적으로 / 프로그래밍 방식으로 저장소를 추가하여 REST를 통해 노출되도록하는 방법이 있습니까?

해결법

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

    1.이러한 메소드가 노출되지 않는 이유는 사용자 정의 저장소 메소드에서 원하는 것을 구현하기 위해 기본적으로 자유롭게 구현할 수 있으므로 해당 특정 자원을 지원하는 올바른 HTTP 메소드를 추론하는 것은 불가능합니다.

    이러한 메소드가 노출되지 않는 이유는 사용자 정의 저장소 메소드에서 원하는 것을 구현하기 위해 기본적으로 자유롭게 구현할 수 있으므로 해당 특정 자원을 지원하는 올바른 HTTP 메소드를 추론하는 것은 불가능합니다.

    귀하의 경우에는 평범한 GET을 사용하는 것이 좋을 수도 있고, 다른 경우에는 메소드의 실행이 부작용을 갖기 때문에 POST가되어야 할 수도 있습니다.

    현재이 솔루션은 저장소 메소드를 호출하는 사용자 정의 컨트롤러를 만드는 것입니다.

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

    2.이틀 후에 나는 이런 식으로 풀었다.

    이틀 후에 나는 이런 식으로 풀었다.

    사용자 정의 저장소 인터페이스 :

    public interface PersonRepositoryCustom {
        Page<Person> customFind(String param1, String param2, Pageable pageable);
    }
    

    사용자 지정 저장소 구현

    public class PersonRepositoryImpl implements PersonRepositoryCustom{
    
        @Override
        public Page<Person> customFind(String param1, String param2, Pageable pageable) {
            // custom query by mongo template, entity manager...
        }
    }
    

    스프링 데이터 저장소 :

    @RepositoryRestResource(collectionResourceRel = "person", path = "person")
    public interface PersonRepository extends MongoRepository<Person, String>, PersonRepositoryCustom {
        Page<Person> findByName(@Param("name") String name, Pageable pageable);
    }
    

    콩 자원 표현

    public class PersonResource extends org.springframework.hateoas.Resource<Person>{
    
        public PersonResource(Person content, Iterable<Link> links) {
            super(content, links);
        }
    }
    

    리소스 어셈블러

    @Component
    public class PersonResourceAssembler extends ResourceAssemblerSupport<Person, PersonResource> {
    
        @Autowired
        RepositoryEntityLinks repositoryEntityLinks;
    
        public PersonResourceAssembler() {
            super(PersonCustomSearchController.class, PersonResource.class);
        }
    
        @Override
        public PersonResource toResource(Person person) {
            Link personLink = repositoryEntityLinks.linkToSingleResource(Person.class, person.getId());
            Link selfLink = new Link(personLink.getHref(), Link.REL_SELF);
            return new PersonResource(person, Arrays.asList(selfLink, personLink));
        }
    
    }
    

    커스텀 Spring MVC 컨트롤러

    @BasePathAwareController
    @RequestMapping("person/search")
    public class PersonCustomSearchController implements ResourceProcessor<RepositorySearchesResource> {
    
        @Autowired
        PersonRepository personRepository;
    
        @Autowired
        PersonResourceAssembler personResourceAssembler;
    
        @Autowired
        private PagedResourcesAssembler<Person> pagedResourcesAssembler;
    
        @RequestMapping(value="customFind", method=RequestMethod.GET)
        public ResponseEntity<PagedResources> customFind(@RequestParam String param1, @RequestParam String param2, @PageableDefault Pageable pageable) {
            Page personPage = personRepository.customFind(param1, param2, pageable);
            PagedResources adminPagedResources = pagedResourcesAssembler.toResource(personPage, personResourceAssembler);
    
            if (personPage.getContent()==null || personPage.getContent().isEmpty()){
                EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
                EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(Person.class);
                List<EmbeddedWrapper> embedded = Collections.singletonList(wrapper);
                adminPagedResources = new PagedResources(embedded, adminPagedResources.getMetadata(), adminPagedResources.getLinks());
            }
    
            return new ResponseEntity<PagedResources>(adminPagedResources, HttpStatus.OK);
        }
    
        @Override
        public RepositorySearchesResource process(RepositorySearchesResource repositorySearchesResource) {
            final String search = repositorySearchesResource.getId().getHref();
            final Link customLink = new Link(search + "/customFind{?param1,param2,page,size,sort}").withRel("customFind");
            repositorySearchesResource.add(customLink);
            return repositorySearchesResource;
        }
    
    }
    
  3. ==============================

    3.GET 방법의 경우 다음 방법을 사용했습니다.

    GET 방법의 경우 다음 방법을 사용했습니다.

    이 접근 방식을 사용하면 계획 및 자원 조합을 관리 할 필요가 없습니다.

    @RepositoryRestResource(collectionResourceRel = "log", path = "log")
    public interface LogRepository extends PagingAndSortingRepository<Log, Long>, 
                                           LogRepositoryCustom {
        //NOTE: This query is just a dummy query
        @Query("select l from Log l where l.id=-1")
        Page<Log> findAllFilter(@Param("options") String options,
            @Param("eid") Long[] entityIds,
            @Param("class") String cls,
            Pageable pageable);
    
    }
    
    public interface LogRepositoryCustom {
    
        Page<Log> findAllFilter(@Param("options") String options,
            @Param("eid") Long[] entityIds,
            @Param("class") String cls,
            Pageable pageable);
    }
    

    구현시 저장소 메소드를 자유롭게 사용하거나 지속성 계층으로 직접 이동할 수 있습니다.

    public class LogRepositoryImpl implements LogRepositoryCustom{
    
        @Autowired
        EntityManager entityManager;
    
        @Autowired
        LogRepository logRepository;
    
        @Override
        public Page<Log> findAllFilter(
            @Param("options") String options,
            @Param( "eid") Long[] entityIds,
            @Param( "class"   ) String cls,
            Pageable pageable) {
    
            //Transform kendoui json options to java object
            DataSourceRequest dataSourceRequest=null;
            try {
                dataSourceRequest = new ObjectMapper().readValue(options, DataSourceRequest.class);
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
    
    
            Session s = entityManager.unwrap(Session.class);
            Junction junction = null;
            if (entityIds != null || cls != null) {
                junction = Restrictions.conjunction();
                if (entityIds != null && entityIds.length > 0) {
                    junction.add(Restrictions.in("entityId", entityIds));
                }
                if (cls != null) {
                    junction.add(Restrictions.eq("cls", cls));
                }
            }
    
        return dataSourceRequest.toDataSourceResult(s, Log.class, junction);
    }
    
  4. ==============================

    4.대답은 당신이 지시를 따르지 않았다는 것입니다. PersonRepository는 PagingAndSortingRepository 및 PersonRepositoryCustomin 순서를 모두 확장하여 사용자가 원하는 것을 성취해야합니다. https://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#repositories.custom-implementations를 참조하십시오.

    대답은 당신이 지시를 따르지 않았다는 것입니다. PersonRepository는 PagingAndSortingRepository 및 PersonRepositoryCustomin 순서를 모두 확장하여 사용자가 원하는 것을 성취해야합니다. https://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#repositories.custom-implementations를 참조하십시오.

  5. ==============================

    5.또 다른 옵션은 특정 저장소 유형에 대한 사용자 지정 저장소 팩토리를 구현하는 것입니다.

    또 다른 옵션은 특정 저장소 유형에 대한 사용자 지정 저장소 팩토리를 구현하는 것입니다.

    RepositoryFactoryBeanSupport에서 확장하고, 고유 한 PersistentEntityInformation을 빌드하고, 사용자 정의 데이터 저장 유형의 기본 repo impl에서 CRUD 작업을 처리 할 수 ​​있습니다. 예를 들어 JpaRepositoryFactoryBean을 참조하십시오. 총 10 개의 클래스를 구현해야하지만 다시 사용할 수 있습니다.

  6. from https://stackoverflow.com/questions/25201306/implementing-custom-methods-of-spring-data-repository-and-exposing-them-through by cc-by-sa and MIT license