Use Spring Data R2DBC + Postgres to realize the function of adding deleting modifying and checking
- 2021-09-05 00:08:00
- OfStack
In this tutorial, I want to show you how to perform various Postgres CRUD operations with Spring WebFlux Spring Data R2DBC.
R2DBC stands for a reactive relational database connection.
Like JPA (Java persistent API) 1, R2DBC is a specification for reactive drivers for relational databases. Since it is a separate specification, do not compare it with JPA/Hibernate features such as @ OneToMany, @ ManyToMany, and so on.
We will develop an Spring Boot application called product-service, which is responsible for creating new products/retrieving all products/deleting or updating existing products to perform various Postgres CRUD operations of R2DBC.
Entity class
@Data
@ToString
<b>public</b> <b>class</b> Product {
@Id
<b>private</b> Integer id;
<b>private</b> String description;
<b>private</b> Double price;
}
We can't add @ Entity here because this is not JPA.
Spring Data Reactivity Repository
Spring Data does all the heavy work as usual. We need to create a repository for our entity classes by extending ReactiveCrudRepository.
<b>import</b> org.springframework.data.repository.reactive.ReactiveCrudRepository;
<b>import</b> org.springframework.stereotype.Repository;
@Repository
<b>public</b> <b>interface</b> ProductRepository <b>extends</b> ReactiveCrudRepository<Product, Integer> {
}
CRUD operation
Let's create a service class to perform the Postgres CRUD operation via Spring Data Reactive Repository.
@Service
<b>public</b> <b>class</b> ProductService {
@Autowired
<b>private</b> ProductRepository repository;
<b>public</b> Flux<Product> getAllProducts(){
<b>return</b> <b>this</b>.repository.findAll();
}
<b>public</b> Mono<Product> getProductById(<b>int</b> productId){
<b>return</b> <b>this</b>.repository.findById(productId);
}
<b>public</b> Mono<Product> createProduct(<b>final</b> Product product){
<b>return</b> <b>this</b>.repository.save(product);
}
<b>public</b> Mono<Product> updateProduct(<b>int</b> productId, <b>final</b> Mono<Product> productMono){
<b>return</b> <b>this</b>.repository.findById(productId)
.flatMap(p -> productMono.map(u -> {
p.setDescription(u.getDescription());
p.setPrice(u.getPrice());
<b>return</b> p;
}))
.flatMap(p -> <b>this</b>.repository.save(p));
}
<b>public</b> Mono<Void> deleteProduct(<b>final</b> <b>int</b> id){
<b>return</b> <b>this</b>.repository.deleteById(id);
}
}
REST API
It's time to expose the service through REST API:
@RestController
@RequestMapping(<font>"product"</font><font>)
<b>public</b> <b>class</b> ProductController {
@Autowired
<b>private</b> ProductService productService;
@GetMapping(</font><font>"all"</font><font>)
<b>public</b> Flux<Product> getAll(){
<b>return</b> <b>this</b>.productService.getAllProducts();
}
@GetMapping(</font><font>"{productId}"</font><font>)
<b>public</b> Mono<ResponseEntity<Product>> getProductById(@PathVariable <b>int</b> productId){
<b>return</b> <b>this</b>.productService.getProductById(productId)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@PostMapping
<b>public</b> Mono<Product> createProduct(@RequestBody Mono<Product> productMono){
<b>return</b> productMono.flatMap(<b>this</b>.productService::createProduct);
}
@PutMapping(</font><font>"{productId}"</font><font>)
<b>public</b> Mono<Product> updateProduct(@PathVariable <b>int</b> productId,
@RequestBody Mono<Product> productMono){
<b>return</b> <b>this</b>.productService.updateProduct(productId, productMono);
}
@DeleteMapping(</font><font>"/{id}"</font><font>)
<b>public</b> Mono<Void> deleteProduct(@PathVariable <b>int</b> id){
<b>return</b> <b>this</b>.productService.deleteProduct(id);
}
}
</font>
Configure
This configuration is required for the Spring Data reaction driver to connect to Postgres DB.
Method 1: Use application. properties
spring.r2dbc.url=r2dbc:postgresql:<font><i>//localhost:5432/productdb</i></font><font>
spring.r2dbc.username=vinsguru
spring.r2dbc.password=admin
</font>
Method 2: Expose the connection factory bean
@Configuration
<b>public</b> <b>class</b> R2DBCConfig {
@Bean
<b>public</b> ConnectionFactory connectionFactory() {
<b>return</b> ConnectionFactories.get(
ConnectionFactoryOptions.builder()
.option(DRIVER, <font>"postgresql"</font><font>)
.option(HOST, </font><font>"localhost"</font><font>)
.option(PORT, 5432)
.option(USER, </font><font>"vinsguru"</font><font>)
.option(PASSWORD, </font><font>"admin"</font><font>)
.option(DATABASE, </font><font>"productdb"</font><font>)
.option(MAX_SIZE, 40)
.build());
}
}
</font>
The complete source code is here.