4.7. 집계 루트에서 이벤트 공개
리포지토리로 관리되는 엔터티는 집계 루트입니다. 도메인 기반 디자인 응용 프로그램에서 이러한 집계 루트는 일반적으로 도메인 이벤트를 게시합니다. Spring Data는 @DomainEvents
다음 예제와 같이 집계 루트의 메소드에서 사용하여 해당 발행물을 가능한 한 쉽게 만들 수 있는 주석을 제공합니다 .
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와의 통합을 제공합니다 .
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
다음 예제와 같이 저장소 인터페이스를 확장 하십시오.
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 구성 클래스 의 어노테이션 을 사용하여 통합 지원이 사용 가능합니다 .
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration {}
@EnableSpringDataWebSupport
주석은 우리가 조금 논의하는 몇 가지 구성 요소를 등록합니다. 또한 클래스 경로에서 Spring HATEOAS를 감지하고 통합 구성 요소 (있는 경우)를 등록합니다.
또는 XML 구성을 사용하는 경우 다음 예제 (for )에 표시된대로 SpringDataWebConfiguration
또는 HateoasAwareSpringDataWebConfiguration
Spring Bean으로 등록 하십시오 SpringDataWebConfiguration
.
<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의 해결 인스턴스를 할 수 있습니다. HandlerMethodArgumentResolver
Spring MVC 가 요청 매개 변수에서 인스턴스를 확인Pageable
하고 해결할 수 있도록 구현합니다Sort
.
DomainClassConverter
이를 DomainClassConverter
통해 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
. 등록은 다음 예제 Pageable
와 Sort
같이 유효한 컨트롤러 메소드 인수를 사용 가능하게 합니다.
@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
가 다음 기본 구성을 사용하여 요청 매개 변수에서 인스턴스 를 파생 시키도록 합니다.
|
검색하려는 페이지입니다. 인덱스가 0이며 기본값은 0입니다. |
|
검색하려는 페이지의 크기입니다. 기본값은 20입니다. |
|
형식으로 정렬해야하는 속성입니다 |
이 동작을 사용자 정의하려면 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를 컨트롤러 메소드 인수로 사용하는 방법을 보여줍니다 .Page
Page
PagedResources
ResourceAssembler
PagedResourcesAssembler
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
얻을 수prev
및next
링크는 페이지의 상태에 따라 부착. 링크는 메소드가 맵핑하는 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 필요 ))을 사용하여 수신 요청 페이로드를 바인딩하는 데 사용할 수 있습니다 .
@ProjectedPayload
public interface UserPayload {
@XBRead("//firstname")
@JsonPath("$..firstname")
String getFirstname();
@XBRead("/lastname")
@JsonPath({ "$.lastname", "$.user.lastname" })
String getLastname();
}
앞의 예제에 표시된 유형은 Spring MVC 핸들러 메소드 인수로 사용하거나 의 메소드 ParameterizedTypeReference
중 하나를 사용하여 사용할 수 있습니다 RestTemplate
. 앞의 메소드 선언은 firstname
주어진 문서의 아무 곳이나 찾으려고 시도합니다 . lastname
XML 조회는 수신 문서의 최상위에 수행됩니다. 해당 JSON 변형은 최상위 수준을 lastname
먼저 시도하지만 전자가 값을 반환하지 않으면 하위 문서에 lastname
중첩을 시도 user
합니다. 이렇게하면 클라이언트가 노출 된 메소드를 호출하지 않고도 소스 문서 구조의 변경을 쉽게 완화 할 수 있습니다 (일반적으로 클래스 기반 페이로드 바인딩의 단점).
에 기술 된 바와 같이 중첩 돌기 지원 계획 . 메소드가 복잡한 비 인터페이스 유형을 리턴하면 Jackson ObjectMapper
이 최종 값을 맵핑하는 데 사용됩니다.
Spring MVC의 경우 필요한 변환기 @EnableSpringDataWebSupport
는 활성화 되 자마자 자동으로 등록 되며 필요한 종속성은 클래스 경로에서 사용할 수 있습니다. 로 사용하려면 (JSON) 또는 수동으로 RestTemplate
등록하십시오 .ProjectingJackson2HttpMessageConverter
XmlBeamHttpMessageConverter
자세한 정보 는 표준 스프링 데이터 예제 저장소 에서 웹 프로젝션 예제 를 참조하십시오 .
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 모듈로 작업하는 경우 DataSource
SQL 스크립트 로 채우기 지원에 익숙 할 것입니다 . 저장소 레벨에서 유사한 추상화를 사용할 수 있지만, SQL은 저장소 독립적이어야하므로 SQL을 데이터 정의 언어로 사용하지 않습니다. 따라서, populator는 XML (Spring의 OXM 추상화를 통해)과 JSON (Jackson을 통해)을 지원하여 리포지토리를 채울 데이터를 정의합니다.
data.json
다음 내용 의 파일이 있다고 가정하십시오 .
[ { "_class" : "com.acme.Person",
"firstname" : "Dave",
"lastname" : "Matthews" },
{ "_class" : "com.acme.Person",
"firstname" : "Carter",
"lastname" : "Beauford" } ]
Spring Data Commons에 제공된 저장소 네임 스페이스의 populator 요소를 사용하여 저장소를 채울 수 있습니다. 위의 데이터를 PersonRepository에 채우려면 다음과 유사한 populator를 선언하십시오.
<?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.json
Jackson 이 파일을 읽고 역 직렬화하도록합니다 ObjectMapper
.
JSON 객체가 비 정렬 화되는 유형 _class
은 JSON 문서 의 속성을 검사하여 결정됩니다 . 인프라는 결국 역 직렬화 된 객체를 처리 할 적절한 저장소를 선택합니다.
대신 XML을 사용하여 리포지토리를 채워야하는 데이터를 정의하기 위해 unmarshaller-populator
요소를 사용할 수 있습니다 . Spring OXM에서 사용 가능한 XML 마샬 러 옵션 중 하나를 사용하도록 구성합니다. 자세한 내용은 Spring 참조 설명서 를 참조하십시오. 다음 예제는 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 DocumentationOliver 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
'IT > Spring-Data-JPA' 카테고리의 다른 글
스프링 데이터 JPA #Reference:쿼리 (0) | 2020.06.19 |
---|---|
스프링 데이터 JPA #Reference:지속 엔티티 (0) | 2020.06.19 |
스프링 데이터 JPA #Intro:레포지터리 작업 (3) (0) | 2020.06.19 |
스프링 데이터 JPA #Intro:레포지터리 작업 (2) (0) | 2020.06.19 |
스프링 데이터 JPA #Intro:레포지터리 작업 (1) (0) | 2020.06.19 |