1. Introduzione
In questo tutorial, vedremo come configurare e implementare operazioni di database utilizzando la programmazione reattiva tramite Spring Data Reactive Repositories con MongoDB.
Esamineremo gli utilizzi di base di ReactiveCrud Archivio, ReactiveMongoRepository , così come ReactiveMongoTemplate.
Anche se queste implementazioni utilizzano la programmazione reattiva, questo non è l'obiettivo principale di questo tutorial.
2. Ambiente
Per utilizzare Reactive MongoDB, dobbiamo aggiungere la dipendenza al nostro pom.xml.
Aggiungeremo anche un MongoDB incorporato per il test:
<dependencies>
// ...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3. Configurazione
Per attivare il supporto reattivo, dobbiamo utilizzare il @EnableReactiveMongoRepositories insieme ad alcune impostazioni dell'infrastruttura:
@EnableReactiveMongoRepositories
public class MongoReactiveApplication
extends AbstractReactiveMongoConfiguration {
@Bean
public MongoClient mongoClient() {
return MongoClients.create();
}
@Override
protected String getDatabaseName() {
return "reactive";
}
}
Nota che quanto sopra sarebbe necessario se stessimo utilizzando l'installazione autonoma di MongoDB. Tuttavia, poiché nel nostro esempio utilizziamo Spring Boot con MongoDB incorporato, la configurazione sopra non è necessaria.
4. Creazione di un documento
Per gli esempi seguenti, creiamo un Account classe e annotalo con @Document per usarlo nelle operazioni di database:
@Document
public class Account {
@Id
private String id;
private String owner;
private Double value;
// getters and setters
}
5. Utilizzo di repository reattivi
Abbiamo già familiarità con il modello di programmazione dei repository, con i metodi CRUD già definiti oltre al supporto anche per altre cose comuni.
Ora con il modello reattivo otteniamo lo stesso insieme di metodi e specifiche, tranne per il fatto che tratteremo i risultati e i parametri in modo reattivo.
5.1. ReactiveCrudRepository
Possiamo usare questo repository allo stesso modo del blocco CrudRepository :
@Repository
public interface AccountCrudRepository
extends ReactiveCrudRepository<Account, String> {
Flux<Account> findAllByValue(String value);
Mono<Account> findFirstByOwner(Mono<String> owner);
}
Possiamo passare diversi tipi di argomenti come plain (String ), avvolto (Facoltativo , Stream ) o reattivo (Mono , Flusso ) come possiamo vedere in findFirstByOwner() metodo.
5.2. ReactiveMongoRepository
C'è anche il ReactiveMongoRepository interfaccia, che eredita da ReactiveCrudRepository e aggiunge alcuni nuovi metodi di query:
@Repository
public interface AccountReactiveRepository
extends ReactiveMongoRepository<Account, String> { }
Utilizzando il ReactiveMongoRepository , possiamo interrogare per esempio:
Flux<Account> accountFlux = repository
.findAll(Example.of(new Account(null, "owner", null)));
Di conseguenza, otterremo ogni Account è lo stesso dell'esempio passato.
Con i nostri repository creati, hanno già definito metodi per eseguire alcune operazioni sul database che non dobbiamo implementare:
Mono<Account> accountMono
= repository.save(new Account(null, "owner", 12.3));
Mono<Account> accountMono2 = repository
.findById("123456");
5.3. RxJava2CrudRepository
Con RxJava2CrudRepository, abbiamo lo stesso comportamento di ReactiveCrudRepository, ma con i risultati e i tipi di parametri di RxJava :
@Repository
public interface AccountRxJavaRepository
extends RxJava2CrudRepository<Account, String> {
Observable<Account> findAllByValue(Double value);
Single<Account> findFirstByOwner(Single<String> owner);
}
5.4. Testare le nostre operazioni di base
Per testare i nostri metodi di repository, utilizzeremo l'iscritto di test:
@Test
public void givenValue_whenFindAllByValue_thenFindAccount() {
repository.save(new Account(null, "Bill", 12.3)).block();
Flux<Account> accountFlux = repository.findAllByValue(12.3);
StepVerifier
.create(accountFlux)
.assertNext(account -> {
assertEquals("Bill", account.getOwner());
assertEquals(Double.valueOf(12.3) , account.getValue());
assertNotNull(account.getId());
})
.expectComplete()
.verify();
}
@Test
public void givenOwner_whenFindFirstByOwner_thenFindAccount() {
repository.save(new Account(null, "Bill", 12.3)).block();
Mono<Account> accountMono = repository
.findFirstByOwner(Mono.just("Bill"));
StepVerifier
.create(accountMono)
.assertNext(account -> {
assertEquals("Bill", account.getOwner());
assertEquals(Double.valueOf(12.3) , account.getValue());
assertNotNull(account.getId());
})
.expectComplete()
.verify();
}
@Test
public void givenAccount_whenSave_thenSaveAccount() {
Mono<Account> accountMono = repository.save(new Account(null, "Bill", 12.3));
StepVerifier
.create(accountMono)
.assertNext(account -> assertNotNull(account.getId()))
.expectComplete()
.verify();
}
6. ReactiveMongoTemplate
Oltre all'approccio dei repository, abbiamo il ReactiveMongoTemplate .
Prima di tutto, dobbiamo registrarci ReactiveMongoTemplate come un fagiolo:
@Configuration
public class ReactiveMongoConfig {
@Autowired
MongoClient mongoClient;
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate() {
return new ReactiveMongoTemplate(mongoClient, "test");
}
}
E poi, possiamo iniettare questo bean nel nostro servizio per eseguire le operazioni di database:
@Service
public class AccountTemplateOperations {
@Autowired
ReactiveMongoTemplate template;
public Mono<Account> findById(String id) {
return template.findById(id, Account.class);
}
public Flux<Account> findAll() {
return template.findAll(Account.class);
}
public Mono<Account> save(Mono<Account> account) {
return template.save(account);
}
}
ReactiveMongoTemplate ha anche una serie di metodi che non riguardano il dominio che abbiamo, puoi verificarli nella documentazione.