본문 바로가기

IT/Spring-Data-JPA

스프링 데이터 JPA #Intro:레포지터리 작업 (4)

반응형

4.7. 집계 루트에서 이벤트 공개

리포지토리로 관리되는 엔터티는 집계 루트입니다. 도메인 기반 디자인 응용 프로그램에서 이러한 집계 루트는 일반적으로 도메인 이벤트를 게시합니다. Spring Data는 @DomainEvents다음 예제와 같이 집계 루트의 메소드에서 사용하여 해당 발행물을 가능한 한 쉽게 만들 수 있는 주석을 제공합니다 .

예 42. 집계 루트에서 도메인 이벤트 노출
class AnAggregateRoot {

    @DomainEvents (1)
    Collection<Object> domainEvents() {
        // … return events you want to get published here
    }

    @AfterDomainEventPublication (2)
    void callbackMethod() {
       // … potentially clean up domain events list
    }
}
1 사용하는 메소드 @DomainEvents는 단일 이벤트 인스턴스 또는 이벤트 콜렉션을 리턴 할 수 있습니다. 인수를 취해서는 안됩니다.
2 모든 이벤트가 게시 된 후로 주석이 추가 된 메소드가 @AfterDomainEventPublication있습니다. 공개 할 이벤트 목록을 잠재적으로 정리하는 데 사용할 수 있습니다 (다른 용도로도).

Spring Data 저장소의 save(…)메소드 중 하나가 호출 될 때마다 메소드가 호출됩니다.

4.8. 스프링 데이터 확장

이 섹션은 다양한 컨텍스트에서 스프링 데이터 사용을 가능하게하는 스프링 데이터 확장 세트를 설명합니다. 현재 대부분의 통합은 Spring MVC를 대상으로합니다.

4.8.1. Querydsl 확장

Querydsl 은 유창한 API를 통해 정적으로 형식화 된 SQL 유사 쿼리를 구성 할 수있는 프레임 워크입니다.

QuerydslPredicateExecutor다음 예제와 같이 여러 Spring Data 모듈은 Querydsl through와의 통합을 제공합니다 .

예 43. QuerydslPredicateExecutor 인터페이스
public interface QuerydslPredicateExecutor<T> {

  Optional<T> findById(Predicate predicate);  (1)

  Iterable<T> findAll(Predicate predicate);   (2)

  long count(Predicate predicate);            (3)

  boolean exists(Predicate predicate);        (4)

  // … more functionality omitted.
}
1 와 일치하는 단일 엔터티를 찾아 반환합니다 Predicate.
2 와 일치하는 모든 항목을 찾아 반환합니다 Predicate.
3 에 일치하는 엔터티 수를 반환합니다 Predicate.
4 일치하는 엔티티가 Predicate존재 하는지 여부를 리턴합니다 .

Querydsl 지원을 사용하려면 QuerydslPredicateExecutor다음 예제와 같이 저장소 인터페이스를 확장 하십시오.

예 44. 저장소에서 Querydsl 통합
interface UserRepository extends CrudRepository<User, Long>, QuerydslPredicateExecutor<User> {
}

앞의 예에서는 Predicate다음 예와 같이 Querydsl 인스턴스를 사용하여 형식이 안전한 쿼리를 작성할 수 있습니다 .

Predicate predicate = user.firstname.equalsIgnoreCase("dave")
	.and(user.lastname.startsWithIgnoreCase("mathews"));

userRepository.findAll(predicate);

4.8.2. 웹 지원

  이 섹션에는 Spring Data Commons의 현재 버전 이상에서 구현되는 Spring Data 웹 지원에 대한 문서가 포함되어 있습니다. 새로 도입 된 지원이 많은 사항을 변경함에 따라 이전 동작에 대한 문서를 [web.legacy]에 보관했습니다 .

저장소 프로그래밍 모델을 지원하는 스프링 데이터 모듈은 다양한 웹 지원과 함께 제공됩니다. 웹 관련 컴포넌트는 Spring MVC JAR가 클래스 경로에 있어야합니다. 그들 중 일부는 Spring HATEOAS 와의 통합도 제공합니다 . 일반적으로 @EnableSpringDataWebSupport다음 예제와 같이 JavaConfig 구성 클래스 어노테이션 을 사용하여 통합 지원이 사용 가능합니다 .

예 45. 스프링 데이터 웹 지원 활성화
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration {}

@EnableSpringDataWebSupport주석은 우리가 조금 논의하는 몇 가지 구성 요소를 등록합니다. 또한 클래스 경로에서 Spring HATEOAS를 감지하고 통합 구성 요소 (있는 경우)를 등록합니다.

또는 XML 구성을 사용하는 경우 다음 예제 (for )에 표시된대로 SpringDataWebConfiguration또는 HateoasAwareSpringDataWebConfigurationSpring Bean으로 등록 하십시오 SpringDataWebConfiguration.

예제 46. XML에서 Spring Data 웹 지원 활성화
<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />

<!-- If you use Spring HATEOAS, register this one *instead* of the former -->
<bean class="org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration" />
기본 웹 지원

이전 섹션에 표시된 구성 은 몇 가지 기본 구성 요소를 등록합니다.

  • A는 DomainClassConverter요청 매개 변수 또는 경로 변수에서 저장소 관리 도메인 클래스의 스프링 MVC의 해결 인스턴스를 할 수 있습니다.
  • HandlerMethodArgumentResolverSpring MVC 가 요청 매개 변수에서 인스턴스를 확인 Pageable하고 해결할 수 있도록 구현합니다 Sort.
DomainClassConverter

이를 DomainClassConverter통해 Spring MVC 컨트롤러 메소드 서명에서 도메인 유형을 직접 사용할 수 있으므로 다음 예제와 같이 저장소를 통해 인스턴스를 수동으로 검색 할 필요가 없습니다.

예제 47. 메소드 서명에 도메인 유형을 사용하는 Spring MVC 컨트롤러
@Controller
@RequestMapping("/users")
class UserController {

  @RequestMapping("/{id}")
  String showUserForm(@PathVariable("id") User user, Model model) {

    model.addAttribute("user", user);
    return "userForm";
  }
}

보시다시피, 메소드는 User인스턴스를 직접 수신하므로 추가 조회가 필요하지 않습니다. Spring MVC가 경로 변수를 id먼저 도메인 클래스 유형 으로 변환 하고 결국 findById(…)도메인 유형에 등록 된 저장소 인스턴스 를 호출하여 인스턴스에 액세스하게함으로써 인스턴스를 해결할 수 있습니다 .

  현재 리포지토리는 CrudRepository변환 할 수 있도록 구현 되어야합니다.
페이징 가능 및 정렬을위한 HandlerMethodArgumentResolvers

이전 섹션에 표시된 구성 스 니펫 PageableHandlerMethodArgumentResolver은의 인스턴스뿐만 아니라를 등록합니다 SortHandlerMethodArgumentResolver. 등록은 다음 예제 PageableSort같이 유효한 컨트롤러 메소드 인수를 사용 가능하게 합니다.

예 48. 컨트롤러 메소드 인수로 Pageable 사용
@Controller
@RequestMapping("/users")
class UserController {

  private final UserRepository repository;

  UserController(UserRepository repository) {
    this.repository = repository;
  }

  @RequestMapping
  String showUsers(Model model, Pageable pageable) {

    model.addAttribute("users", repository.findAll(pageable));
    return "users";
  }
}

위의 메소드 서명은 Spring MVC Pageable가 다음 기본 구성을 사용하여 요청 매개 변수에서 인스턴스 를 파생 시키도록 합니다.

표 1. Pageable인스턴스에 대해 평가 된 요청 매개 변수

page

검색하려는 페이지입니다. 인덱스가 0이며 기본값은 0입니다.

size

검색하려는 페이지의 크기입니다. 기본값은 20입니다.

sort

형식으로 정렬해야하는 속성입니다 property,property(,ASC|DESC)(,IgnoreCase). 기본 정렬 방향은 대소 문자를 구분합니다. sort방향 또는 대소 문자 구분을 전환 하려면 여러 매개 변수를 사용하십시오 ( 예 :) ?sort=firstname&sort=lastname,asc&sort=city,ignorecase.

이 동작을 사용자 정의하려면 PageableHandlerMethodArgumentResolverCustomizer인터페이스 또는 SortHandlerMethodArgumentResolverCustomizer인터페이스를 각각 구현하는 Bean을 등록하십시오 . customize()다음 예에서와 같이 방법은 당신이 설정을 변경시키는, 호출됩니다 :

@Bean SortHandlerMethodArgumentResolverCustomizer sortCustomizer() {
    return s -> s.setPropertyDelimiter("<-->");
}

기존의 특성을 설정 MethodArgumentResolver하기에 충분하지 않은 경우 SpringDataWebConfiguration, HATEOAS 가능 기능을 확장하거나 pageableResolver()또는 sortResolver()메소드를 대체 하고 @Enable주석 을 사용하는 대신 사용자 정의 된 구성 파일을 가져 오십시오 .

요청에서 여러 개 Pageable또는 Sort인스턴스를 해결 해야하는 경우 (예 : 여러 테이블의 경우) Spring의 @Qualifier주석을 사용 하여 서로 구별 할 수 있습니다 . 그런 다음 요청 매개 변수 앞에 접두사를 붙여야합니다 ${qualifier}_. followig 예제는 결과 메소드 서명을 보여줍니다.

String showUsers(Model model,
      @Qualifier("thing1") Pageable first,
      @Qualifier("thing2") Pageable second) { … }

당신은 채울해야 thing1_page하고 thing2_page등등합니다.

Pageable메소드에 전달 된 기본값 은 a와 동일 PageRequest.of(0, 20)하지만 매개 변수 @PageableDefault주석을 사용하여 사용자 정의 할 수 있습니다 Pageable.

페이저 블에 대한 하이퍼 미디어 지원

Spring HATEOAS 에는 필요한 메타 데이터와 클라이언트가 페이지를 쉽게 탐색 할 수있는 링크로 인스턴스 PagedResources의 컨텐츠를 보강 할 수있는 표현 모델 클래스 ( )가 제공됩니다. 페이지를에서 로의 변환은 이라고하는 Spring HATEOAS 인터페이스 의 구현에 의해 수행됩니다 . 다음 예제는 a를 컨트롤러 메소드 인수로 사용하는 방법을 보여줍니다 .PagePagePagedResourcesResourceAssemblerPagedResourcesAssemblerPagedResourcesAssembler

예 49. 컨트롤러 메소드 인수로 PagedResourcesAssembler 사용
@Controller
class PersonController {

  @Autowired PersonRepository repository;

  @RequestMapping(value = "/persons", method = RequestMethod.GET)
  HttpEntity<PagedResources<Person>> persons(Pageable pageable,
    PagedResourcesAssembler assembler) {

    Page<Person> persons = repository.findAll(pageable);
    return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);
  }
}

앞의 예제에 표시된대로 구성을 PagedResourcesAssembler사용하면 컨트롤러 메소드 인수로 사용할 수 있습니다 . 호출 toResources(…)하면 다음과 같은 효과가 있습니다.

  • 의 내용은 인스턴스 Page의 내용이됩니다 PagedResources.
  • PagedResources개체는 가져 PageMetadata부착 된 인스턴스를하고,이 정보로 채워집니다 Page및 기본 PageRequest.
  • PagedResources얻을 수 prevnext링크는 페이지의 상태에 따라 부착. 링크는 메소드가 맵핑하는 URI를 가리 킵니다. 메소드에 추가 된 페이지 매김 매개 변수는 설정을 일치시켜 PageableHandlerMethodArgumentResolver나중에 링크를 분석 할 수 있도록합니다.

데이터베이스에 30 개의 Person 인스턴스가 있다고 가정하십시오. 이제 요청 ( )을 트리거 하고 다음과 유사한 출력을 볼 수 있습니다 .GET http://localhost:8080/persons

{ "links" : [ { "rel" : "next",
                "href" : "http://localhost:8080/persons?page=1&size=20 }
  ],
  "content" : [
     … // 20 Person instances rendered here
  ],
  "pageMetadata" : {
    "size" : 20,
    "totalElements" : 30,
    "totalPages" : 2,
    "number" : 0
  }
}

어셈블러가 올바른 URI를 생성하고 기본 구성을 선택 Pageable하여 곧 나오는 요청에 대한 매개 변수를 해결 함 을 알 수 있습니다. 즉, 해당 구성을 변경하면 링크가 자동으로 변경 사항을 준수합니다. 기본적으로 어셈블러는 호출 된 컨트롤러 메소드를 가리 Link키지 만 페이지 매김 링크를 빌드하기위한 기반으로 사용 되도록 사용자 정의를 전달하여 사용자 정의 할 수 있으며, 이는 PagedResourcesAssembler.toResource(…)메소드에 과부하를줍니다 .

웹 데이터 바인딩 지원

SpringData 프로젝션 ( Projections에 설명 )은 다음 예제와 같이 JSONPath 표현식 ( Jayway JsonPath 필요 또는 XPath 표현식 ( XmlBeam 필요 ))을 사용하여 수신 요청 페이로드를 바인딩하는 데 사용할 수 있습니다 .

예 50. JSONPath 또는 XPath 표현식을 사용하는 HTTP 페이로드 바인딩
@ProjectedPayload
public interface UserPayload {

  @XBRead("//firstname")
  @JsonPath("$..firstname")
  String getFirstname();

  @XBRead("/lastname")
  @JsonPath({ "$.lastname", "$.user.lastname" })
  String getLastname();
}

앞의 예제에 표시된 유형은 Spring MVC 핸들러 메소드 인수로 사용하거나 의 메소드 ParameterizedTypeReference중 하나를 사용하여 사용할 수 있습니다 RestTemplate. 앞의 메소드 선언은 firstname주어진 문서의 아무 곳이나 찾으려고 시도합니다 . lastnameXML 조회는 수신 문서의 최상위에 수행됩니다. 해당 JSON 변형은 최상위 수준을 lastname먼저 시도하지만 전자가 값을 반환하지 않으면 하위 문서에 lastname중첩을 시도 user합니다. 이렇게하면 클라이언트가 노출 된 메소드를 호출하지 않고도 소스 문서 구조의 변경을 쉽게 완화 할 수 있습니다 (일반적으로 클래스 기반 페이로드 바인딩의 단점).

에 기술 된 바와 같이 중첩 돌기 지원 계획 . 메소드가 복잡한 비 인터페이스 유형을 리턴하면 Jackson ObjectMapper이 최종 값을 맵핑하는 데 사용됩니다.

Spring MVC의 경우 필요한 변환기 @EnableSpringDataWebSupport는 활성화 되 자마자 자동으로 등록 되며 필요한 종속성은 클래스 경로에서 사용할 수 있습니다. 로 사용하려면 (JSON) 또는 수동으로 RestTemplate등록하십시오 .ProjectingJackson2HttpMessageConverterXmlBeamHttpMessageConverter

자세한 정보 는 표준 스프링 데이터 예제 저장소 에서 웹 프로젝션 예제참조하십시오 .

Querydsl 웹 지원

QueryDSL 통합이 있는 상점의 경우 , Request쿼리 문자열에 포함 된 속성에서 쿼리를 파생시킬 수 있습니다 .

다음 쿼리 문자열을 고려하십시오.

?firstname=Dave&lastname=Matthews

User이전 예제 개체를 고려하면을 사용 하여 쿼리 문자열을 다음 값으로 확인할 수 있습니다 QuerydslPredicateArgumentResolver.

QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews"))
  @EnableSpringDataWebSupport클래스 경로에서 Querydsl이 발견되면 이 기능이 자동으로 활성화됩니다 .

@QuerydslPredicate메소드 서명에 a 추가하면 바로 사용할 Predicate수 있으며,를 사용하여 실행할 수 있습니다 QuerydslPredicateExecutor.

  유형 정보는 일반적으로 메소드의 리턴 유형에서 분석됩니다. 해당 정보가 도메인 유형과 반드시 ​​일치 할 필요는 없으므로의 root속성 을 사용하는 것이 좋습니다 QuerydslPredicate.

다음 시험은 @QuerydslPredicate메소드 서명 에 사용하는 방법을 보여줍니다 .

@Controller
class UserController {

  @Autowired UserRepository repository;

  @RequestMapping(value = "/", method = RequestMethod.GET)
  String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate,    (1)
          Pageable pageable, @RequestParam MultiValueMap<String, String> parameters) {

    model.addAttribute("users", repository.findAll(predicate, pageable));

    return "index";
  }
}
1 일치에 쿼리 문자열 인수를 해결 Predicate하기위한 User.

기본 바인딩은 다음과 같습니다.

  • Object로 간단한 속성에 eq.
  • Object같은 속성과 같은 컬렉션 contains.
  • Collection로 간단한 속성에 in.

이러한 바인딩은 Java 8 bindings속성을 사용 @QuerydslPredicate하거나 Java 8을 사용 default methods하고 QuerydslBinderCustomizer메소드를 저장소 인터페이스에 추가하여 사용자 정의 할 수 있습니다 .

interface UserRepository extends CrudRepository<User, String>,
                                 QuerydslPredicateExecutor<User>,                (1)
                                 QuerydslBinderCustomizer<QUser> {               (2)

  @Override
  default void customize(QuerydslBindings bindings, QUser user) {

    bindings.bind(user.username).first((path, value) -> path.contains(value))    (3)
    bindings.bind(String.class)
      .first((StringPath path, String value) -> path.containsIgnoreCase(value)); (4)
    bindings.excluding(user.password);                                           (5)
  }
}
1 QuerydslPredicateExecutor에 대한 특정 파인더 메소드에 대한 액세스를 제공합니다 Predicate.
2 QuerydslBinderCustomizer리포지토리 인터페이스에 정의 된 것은 자동으로 선택되고 바로 가기 @QuerydslPredicate(bindings=…​)입니다.
3 username속성 의 바인딩을 간단한 contains바인딩으로 정의하십시오 .
4 String대 / 소문자를 구분하지 않도록 속성 의 기본 바인딩을 정의하십시오 contains.
5 해상도 에서 password속성을 제외하십시오 Predicate.

4.8.3. 리포지토리 포퓰 레이터

Spring JDBC 모듈로 작업하는 경우 DataSourceSQL 스크립트 로 채우기 지원에 익숙 할 것입니다 . 저장소 레벨에서 유사한 추상화를 사용할 수 있지만, SQL은 저장소 독립적이어야하므로 SQL을 데이터 정의 언어로 사용하지 않습니다. 따라서, populator는 XML (Spring의 OXM 추상화를 통해)과 JSON (Jackson을 통해)을 지원하여 리포지토리를 채울 데이터를 정의합니다.

data.json다음 내용 의 파일이 있다고 가정하십시오 .

예 51. JSON에 정의 된 데이터
[ { "_class" : "com.acme.Person",
 "firstname" : "Dave",
  "lastname" : "Matthews" },
  { "_class" : "com.acme.Person",
 "firstname" : "Carter",
  "lastname" : "Beauford" } ]

Spring Data Commons에 제공된 저장소 네임 스페이스의 populator 요소를 사용하여 저장소를 채울 수 있습니다. 위의 데이터를 PersonRepository에 채우려면 다음과 유사한 populator를 선언하십시오.

예 52. Jackson 저장소 채우기 프로그램 선언
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:repository="http://www.springframework.org/schema/data/repository"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/repository
    https://www.springframework.org/schema/data/repository/spring-repository.xsd">

  <repository:jackson2-populator locations="classpath:data.json" />

</beans>

위의 선언은 data.jsonJackson 파일을 읽고 역 직렬화하도록합니다 ObjectMapper.

JSON 객체가 비 정렬 화되는 유형 _class은 JSON 문서 속성을 검사하여 결정됩니다 . 인프라는 결국 역 직렬화 된 객체를 처리 할 적절한 저장소를 선택합니다.

대신 XML을 사용하여 리포지토리를 채워야하는 데이터를 정의하기 위해 unmarshaller-populator요소를 사용할 수 있습니다 . Spring OXM에서 사용 가능한 XML 마샬 러 옵션 중 하나를 사용하도록 구성합니다. 자세한 내용은 Spring 참조 설명서 를 참조하십시오. 다음 예제는 JAXB를 사용하여 저장소 채우기를 비 정렬 화하는 방법을 보여줍니다.

예 53. 비 정렬 리포지토리 저장소 채우기 (JAXB 사용) 선언
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:repository="http://www.springframework.org/schema/data/repository"
  xmlns:oxm="http://www.springframework.org/schema/oxm"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/repository
    https://www.springframework.org/schema/data/repository/spring-repository.xsd
    http://www.springframework.org/schema/oxm
    https://www.springframework.org/schema/oxm/spring-oxm.xsd">

  <repository:unmarshaller-populator locations="classpath:data.json"
    unmarshaller-ref="unmarshaller" />

  <oxm:jaxb2-marshaller contextPath="com.acme" />

</beans>

Spring Data JPA - Reference Documentation

Oliver Gierke,Thomas Darimont,Christoph Strobl,Mark Paluch,Jay Bryant
version 2.3.1.RELEASE,2020-06-10

2.3.1.RELEASE

© 2008-2019 The original authors.

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.

출처 : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.domain-events

반응형