[SPRING] Spring 데이터 저장소의 커스텀 메소드 구현 및 REST를 통한 노출
SPRINGSpring 데이터 저장소의 커스텀 메소드 구현 및 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.이러한 메소드가 노출되지 않는 이유는 사용자 정의 저장소 메소드에서 원하는 것을 구현하기 위해 기본적으로 자유롭게 구현할 수 있으므로 해당 특정 자원을 지원하는 올바른 HTTP 메소드를 추론하는 것은 불가능합니다.
이러한 메소드가 노출되지 않는 이유는 사용자 정의 저장소 메소드에서 원하는 것을 구현하기 위해 기본적으로 자유롭게 구현할 수 있으므로 해당 특정 자원을 지원하는 올바른 HTTP 메소드를 추론하는 것은 불가능합니다.
귀하의 경우에는 평범한 GET을 사용하는 것이 좋을 수도 있고, 다른 경우에는 메소드의 실행이 부작용을 갖기 때문에 POST가되어야 할 수도 있습니다.
현재이 솔루션은 저장소 메소드를 호출하는 사용자 정의 컨트롤러를 만드는 것입니다.
-
==============================
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.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.대답은 당신이 지시를 따르지 않았다는 것입니다. 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.또 다른 옵션은 특정 저장소 유형에 대한 사용자 지정 저장소 팩토리를 구현하는 것입니다.
또 다른 옵션은 특정 저장소 유형에 대한 사용자 지정 저장소 팩토리를 구현하는 것입니다.
RepositoryFactoryBeanSupport에서 확장하고, 고유 한 PersistentEntityInformation을 빌드하고, 사용자 정의 데이터 저장 유형의 기본 repo impl에서 CRUD 작업을 처리 할 수 있습니다. 예를 들어 JpaRepositoryFactoryBean을 참조하십시오. 총 10 개의 클래스를 구현해야하지만 다시 사용할 수 있습니다.
from https://stackoverflow.com/questions/25201306/implementing-custom-methods-of-spring-data-repository-and-exposing-them-through by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] junit 테스트 클래스 전체에서 스프링 응용 프로그램 컨텍스트 재사용 (0) | 2018.12.08 |
---|---|
[SPRING] 데이터 읽기를위한 데이터베이스 트랜잭션이 필요합니까? (0) | 2018.12.08 |
[SPRING] Spring Data JPA GROUP BY 쿼리에서 커스텀 객체를 반환하는 방법 (0) | 2018.12.07 |
[SPRING] @Scope ( "prototype") 빈 범위는 새 빈을 생성하지 않습니다. (0) | 2018.12.07 |
[SPRING] 컨텍스트에서 여러 패키지 : 구성 요소 검사, 봄 구성 (0) | 2018.12.07 |