Spring Boot WebFlux with Reactive MongoDB แบบง่ายๆ

Chiwa Kantawong (Pea)
3 min readJul 23, 2021

--

WebFlux คือการเขียนโปรแกรมแบบ Reactive programming คือการเขียนแบบ asynchronous, non-blocking หรือคือ Implementation Observer Pattern อย่างหนึ่ง และที่ Reactive programming เป็นที่ได้รับความนิยมอย่างมากในทุกวันนี้ เพราะมี reactive frameworks หรือ libraries มากมายที่รองรับ เช่น Spring version 5 เป็นต้นมาและ Spring Boot version 2 เป็นต้นมา นอกจากนี้ ถ้าเราต้องการทำ Reactive Programming แบบสมบูรณ์แล้วส่วนของ Data Layer (Database ต่างๆ) ก็ต้องรองรับการทำงานแบบ Reactive ด้วยเช่นกัน เท่าที่ผมรู้ตอนนี้ สำหรับ RDBMS ที่รองรับก็จะมี ProsgresSQL ส่วน NoSql ก็จะมี MongoDB, Cassanda, Couchbase และ Redis ซึ่งอาจจะมีมากกว่านี้นะครับ อันนี้ผมไม่แน่ใจลองไปค้นหากันดูนะคับ

สำหรับ Blog นี้เราจะใช้ Embed MongoDB กันเพื่อให้ง่ายต่อการทำเป็นตัวอย่างโดยไม่ต้อง install MongoDB นะครับ เช่นเคยครับเราจะมาสร้าง Spring Boot Application ด้วย Maven กันนะครับ ไป https://start.spring.io/ เลยครับ

แก้ pom.xml แบบนี้นะครับ

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zengcode.webflux</groupId>
<artifactId>webflux-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>webflux-demo</name>
<description>webflux-demo</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>

สร้าง Entity สำหรับ Customer

package com.zengcode.webflux.webfluxdemo.entity;

import com.sun.istack.internal.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "customers")
public class Customer {

@Id
@NotNull
private String id;
private String name;
private String email;

}

สร้าง Repository

package com.zengcode.webflux.webfluxdemo.repository;

import com.zengcode.webflux.webfluxdemo.entity.Customer;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CustomerRepository extends ReactiveMongoRepository<Customer, String> {
}

สร้าง CustomerService

package com.zengcode.webflux.webfluxdemo.service;

import com.zengcode.webflux.webfluxdemo.entity.Customer;
import com.zengcode.webflux.webfluxdemo.repository.CustomerRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
@Slf4j
public class CustomerService {

@Autowired
private CustomerRepository customerRepository;

public Flux<Customer> getAllCustomer() {
Flux<Customer> customers = customerRepository.findAll();
return customers;
}

public Mono<Customer> findById(String id) throws InterruptedException {
Mono<Customer> customer = customerRepository.findById(id);
return customer;
}
}

ต่อไปมาสร้าง Controller กันครับ

package com.zengcode.webflux.webfluxdemo.controller;

import com.zengcode.webflux.webfluxdemo.entity.Customer;
import com.zengcode.webflux.webfluxdemo.repository.CustomerRepository;
import com.zengcode.webflux.webfluxdemo.service.CustomerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@Slf4j
public class CustomerController {

@Autowired
private CustomerService customerService;

@Autowired
private CustomerRepository customerRepository;

@GetMapping("/customers")
public Flux<Customer> getAllCustomer() {
return customerService.getAllCustomer();
}

@GetMapping("/customers/{id}")
public Mono<ResponseEntity<Customer>> getCustomer(@PathVariable String id) throws InterruptedException {
return customerService.findById(id).map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}


@GetMapping("/create")
public String create() {
Customer customer = new Customer();
customer.setId("cust001");
customer.setName("Chiwa Kantawong");
customer.setEmail("kchiwa@gmail.com");
customerRepository.save(customer).subscribe(result -> log.info("Entity has been saved: {}", result));

customer = new Customer();
customer.setId("cust002");
customer.setName("Pee Kantawong");
customer.setEmail("pee@gmail.com");
customerRepository.save(customer).subscribe(result -> log.info("Entity has been saved: {}", result));
return "Done";
}

}

ขออนุญาติสร้าง /create แบบง่ายๆ นะครับ ขอภัย

ต่อไปลองเข้า http://localhost:8080/create ก็จะเป็นการสร้าง customer ขึ้นมา 2 คน

ต่อไป http://localhost:8080/customers

ต่อไป http://localhost:8080/customers/cust001

ไม่ยากเลยเนอะ ลองเอาไปใช้กันนะครับ

--

--

Chiwa Kantawong (Pea)
Chiwa Kantawong (Pea)

Written by Chiwa Kantawong (Pea)

Software Development Expert at Central Tech

No responses yet