Mongo WebFlux integration

preface

The last lecture used Map data structures to store data in memory. In this way, the data will not be persistent. In this paper, we use MongoDB to realize WebFlux operation on the data source.

What is MongoDB?

Website: https://www.mongodb.com/

MongoDB is a database based on distributed file storage, written by C++ language, aiming to provide scalable high-performance data storage solutions for WEB applications.

MongoDB is a product between relational database and non-relational database. Among non-relational databases, it has the most rich functions and is the most like relational database.

For ease of operation, this article uses Docker to start a MognoDB service. If the Docker won’t install, please refer to the article: Docker installation and basic operation of https://www.jianshu.com/p/f272726db9c5

Docker installs MognoDB and launches as follows:

1. Create a mount directory

docker volume create mongo_data_db
docker volume create mongo_data_configdbCopy the code

2. Start MognoDB

docker run -d \
    --name mongo \
    -v mongo_data_configdb:/data/configdb \
    -v mongo_data_db:/data/db \
    -p 27017:27017 \
    mongo \
    --authCopy the code

3. Initialize the administrator account

Docker exec -it mongo mongo admin docker exec -it mongo mongo admin docker exec -it mongo mongo admin docker exec -it mongo mongo admin [ { role: "root", db: "admin" } ] });Copy the code

4. Test connectivity

docker run -it --rm --link mongo:mongo mongo mongo -u admin -p admin --authenticationDatabase admin mongo/adminCopy the code

MognoDB basic operation:

Similar to MySQL, display library list:

show dbsCopy the code

Using a database

use adminCopy the code

Display table list

show collectionsCopy the code

If a city table exists, format and display the city table

db.city.find().pretty()Copy the code

structure

Similar to the above mentioned project construction, create a new project to write this case. Engineering picture:

The core of the directory is as follows

  • Maven pom. The XML configuration
  • Application.properties configuration file
  • Dao data access layer, highlights of this article

Added POM dependency and configuration

Configure the new dependency in pom.xml:

<! <dependency> <groupId>org.springframework. Boot </groupId> <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId> </dependency>Copy the code

Similar to MySQL and JDBC drivers, you must configure the database. The MongoDB configuration started above under the application.properties configuration:

The database name is admin, and the account password is admin.

spring.data.mongodb.host=localhost
spring.data.mongodb.database=admin
spring.data.mongodb.port=27017
spring.data.mongodb.username=admin
spring.data.mongodb.password=adminCopy the code

This is a huge question, why not use our common MySQL database?

Spring Data Reactive Repositories currently supports Mongo, Cassandra, Redis, Couchbase. MySQL is not supported, so why on earth? That explains the relationship between JDBC and Spring Data.

Spring Data Reactive Repositories is Reactive. The differences are as follows:

  • Jdbc-based implementations of Spring Data, such as Spring Data JPA, are blocked. The principle is to consume each thread calling the database based on the blocking IO model.
  • Transactions can only be used in one Java.sqL. Connection, that is, one operation per transaction.

The idea of asynchronous non-blocking encapsulation of JDBC is not new either, and the Scala library Slick 3 implements it. The simple implementation principle is as follows:

  • Multiple operations in a transaction share a java.sql.Connection. You can use transparent transaction management, using the callback programming model for passing
  • Keep a limited number of free connections

Finally, I firmly believe that non-blocking JDBC is coming soon. So we are happy to call MySQL.

object

Modify org. Spring. Springboot. Domain packages inside city entity object classes. Modify the City object City as follows:

import org.springframework.data.annotation.Id; /** * public class City {** * private Long Id; /** * private Long provinceId; /** * cityName */ private String cityName; /** * description */ private String description; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getProvinceId() { return provinceId; } public void setProvinceId(Long provinceId) { this.provinceId = provinceId; } public String getCityName() { return cityName; } public void setCityName(String cityName) { this.cityName = cityName; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; }}Copy the code

The @ID annotation marks the primary key or unique identifier of the corresponding library table. Because this is our DO, the data access object maps to the data store one by one.

MongoDB data access layer CityRepository

Modify the CityRepository class as follows:

import org.spring.springboot.domain.City;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CityRepository extends ReactiveMongoRepository<City, Long> {

}Copy the code

The CityRepository interface simply inherits the ReactiveMongoRepository class. Many implementations are provided by default, such as CRUD and list query parameters-related implementations. The ReactiveMongoRepository interface is implemented by default as follows:

    <S extends T> Mono<S> insert(S var1);

    <S extends T> Flux<S> insert(Iterable<S> var1);

    <S extends T> Flux<S> insert(Publisher<S> var1);

    <S extends T> Flux<S> findAll(Example<S> var1);

    <S extends T> Flux<S> findAll(Example<S> var1, Sort var2);Copy the code

As shown in figure, ReactiveMongoRepository integration ReactiveSortingRepository, ReactiveCrudRepository implements many commonly used interface:

The ReactiveCrudRepository interface is shown below:

As you can also see, the naming of interfaces follows the specification. Common naming rules are as follows:

  • Keyword: : Method name
  • And :: findByNameAndPwd
  • Or :: findByNameOrSex
  • Is :: findById
  • Between :: findByIdBetween
  • Like :: findByNameLike
  • NotLike :: findByNameNotLike
  • OrderBy :: findByIdOrderByXDesc
  • Not :: findByNameNot

Common cases, the code is as follows:

Flux<Person> findByLastname(String lastname); @Query("{ 'firstname': ? 0, 'lastname': ? 1}") Mono<Person> findByFirstnameAndLastname(String firstname, String lastname); // Accept parameter inside a reactive type for deferred execution Flux<Person> findByLastname(Mono<String> lastname); Mono<Person> findByFirstnameAndLastname(Mono<String> firstname, String lastname); @Tailable // Use a tailable cursor Flux<Person> findWithTailableCursorBy();Copy the code

The source code level

ReactiveCrudRepository is abstracted from reactive, as shown in figure 2.

As you can see here, support for Reactive also supports RxJava. ReactiveCrudRepository interface and various storage implementations are added to the old CrudRepository.

The processor class Handler and the Controller class Controller

Modify Handler as follows:

@Component public class CityHandler { private final CityRepository cityRepository; @Autowired public CityHandler(CityRepository cityRepository) { this.cityRepository = cityRepository; } public Mono<City> save(City city) { return cityRepository.save(city); } public Mono<City> findCityById(Long id) { return cityRepository.findById(id); } public Flux<City> findAllCity() { return cityRepository.findAll(); } public Mono<City> modifyCity(City city) { return cityRepository.save(city); } public Mono<Long> deleteCity(Long id) { cityRepository.deleteById(id); return Mono.create(cityMonoSink -> cityMonoSink.success(id)); }}Copy the code

Don’t be strange to Mono, Flux, treat him as an object. Modify the Controller class Controller as follows:

@RestController @RequestMapping(value = "/city") public class CityWebFluxController { @Autowired private CityHandler cityHandler; @GetMapping(value = "/{id}") public Mono<City> findCityById(@PathVariable("id") Long id) { return cityHandler.findCityById(id); } @GetMapping() public Flux<City> findAllCity() { return cityHandler.findAllCity(); } @PostMapping() public Mono<City> saveCity(@RequestBody City city) { return cityHandler.save(city); } @PutMapping() public Mono<City> modifyCity(@RequestBody City city) { return cityHandler.modifyCity(city); } @DeleteMapping(value = "/{id}") public Mono<Long> deleteCity(@PathVariable("id") Long id) { return cityHandler.deleteCity(id); }}Copy the code

Run the project

A CRUD Spring Boot Webflux project is developed, the following run project verification. On the toolbar on the right side of IDEA, click the Maven Project Tab, and then click install to use the Maven plugin. Or, from the project root directory, execute Maven cleanup and installation commands:

cd springboot-webflux-3-mongodb
mvn clean installCopy the code

See successful output in the console:

. Omit [INFO] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 01:30 min [INFO] Finished at: 2017-10-15T10:00:54+08:00 [INFO] Final Memory: 31M/174M [INFO] ------------------------------------------------------------------------Copy the code

Perform Application class startup in IDEA, either in normal mode or Debug mode. You can see the output of a successful run on the console:

. Omit the 08:43:39 2018-04-10. 2052-932 the INFO [ctor - HTTP - nio - 1] r.ipc.net ty. TCP. BlockingNettyContext: Started HttpServer on / 0:0:0:0:0:0:0:0:0:0:0:8080 2018-04-10 08:43:39.935 INFO 2052 -- [main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080 the 2018-04-10 08:43:39. 2052-960 the INFO [main] org. Spring. Springboot. Application: Started Application in 6.547 seconds (JVM running for 9.851)Copy the code

Open the POST MAN tool, development requirements. Do the following:

New city information POST at http://127.0.0.1:8080/city

Connect to MongoDB and validate the data

Connect the mongo

docker run -it --rm --link mongo:mongo mongo mongo -u admin -p admin --authenticationDatabase admin mongo/adminCopy the code

Display library list:

show dbsCopy the code

Using a database

use adminCopy the code

Display table list

show collectionsCopy the code

If there is a city table, format the contents of the city table:

db.city.find().pretty()Copy the code

conclusion

Here, we explore how Spring WebFlux integrates MongoDB. Combine Cassandra, Redis, Couchbase with other stores, and you’re pretty much the same. Next, we can put together Thymeleaf, a better page to show you. By the way, let’s learn the basic usage of Thymeleaf.

This article is published by OpenWrite!