springboot2學習-webflux和mongodb
這裡學習下webflux和mongodb的結合,使用mongodb來進行資料的儲存,使用docker來啟動mongodb容器簡化開發。docker資料學習可以參考:https://www.jianshu.com/p/f272726db9c5
這篇部落格的學習來源是http://gitbook.cn/gitchat/column/5acda6f6d7966c5ae1086f2b/topic/5acda9f9d7966c5ae108705c
環境:虛擬機器cenos7,安裝了docker,jdk1.8,IDEA
mongodb參考資料:https://www.mongodb.com/
什麼是mongodb:
MongoDB是一個基於分散式檔案儲存的資料庫。由C++語言編寫。旨在為WEB應用提供可擴充套件的高效能資料儲存解決方案。
MongoDB 是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的。他支援的資料結構非常鬆散,是類似json的bson格式,因此可以儲存比較複雜的資料型別。Mongo最大的特點是他支援的查詢語言非常強大,其語法有點類似於面向物件的查詢語言,幾乎可以實現類似關係資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。
一 docker 安裝mongodb
1,安裝好docker
2,使用docker從阿里或者網易映象庫拉取mongodb的映象,速度比較快
上圖我是從網易的docker映象倉庫裡面拉取的一個mongodb映象,網易蜂巢改版了,一下沒找到倉庫地址了,這裡有一個阿里雲的docker倉庫地址:https://dev.aliyun.com/search.html
3,建立掛載目錄
docker volume create mongo_data_db
docker volume create mongo_data_configdb
4,啟動mongodb
docker run -d \
--name mongo \
-v mongo_data_configdb:/data/configdb \
-v mongo_data_db:/data/db \
-p 27017:27017 \
ed27e79af407 \
--auth jack
其中ed27e79af407為mongodb的映象id
上圖是啟動mongodb成功的圖
5,初始化管理員賬號
docker exec -it mongo mongo admin
// 容器名 // mongo命令 資料庫名
# 建立最高許可權使用者
db.createUser({ user: 'admin', pwd: 'admin', roles: [ { role: "root", db: "admin" } ] });
說明:“docker exec -it mongo mongo admin“命令是進入到容器裡面執行命令
如果此時需要退出容器裡面的使用快捷鍵:ctr +p+q
MongoDB的基本命令:
類似 MySQL 命令,顯示庫列表:
show dbs
> use admin
switched to db admin
> show collections
使用某資料庫:use admin
> use admin
switched to db admin
顯示錶列表:show collections
> show collections
system.users
system.version
如果存在 city 表,格式化顯示 city 表內容:
db.city.find().pretty()
二 專案開發
1,建立一個spring boot專案
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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jack</groupId> <artifactId>webflux_mongodb</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>webflux_mongodb</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- Spring Boot 響應式 MongoDB 依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</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> </plugin> </plugins> </build> </project>
2,配置mongodb的連線配置
修改application.properties,如下:
spring.data.mongodb.host=192.168.0.104
spring.data.mongodb.database=admin
spring.data.mongodb.port=27017
spring.data.mongodb.username=admin
spring.data.mongodb.password=admin
3,建立一個city類
程式碼如下:
package com.jack.webflux_mongodb.domain;
import lombok.Data;
import org.springframework.data.annotation.Id;
/**
* create by jack 2018/5/12
* 城市實體類
*/
@Data
public class City {
/**
* 城市編號
* @Id 註解標記對應庫表的主鍵或者唯一識別符號。因為這個是我們的 DO,資料訪問物件一一對映到資料儲存。
*/
@Id
private Long id;
/**
* 省份編號
*/
private Long provinceId;
/**
* 城市名稱
*/
private String cityName;
/**
* 描述
*/
private String description;
}
4,MongoDB 資料訪問層 CityRepository
修改 CityRepository 類,程式碼如下:
package com.jack.webflux_mongodb.dao;
import com.jack.webflux_mongodb.domain.City;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
/**
* create by jack 2018/5/12
*/
@Repository
public interface CityRepository extends ReactiveMongoRepository<City, Long> {
}
CityRepository 介面只要繼承 ReactiveMongoRepository 類即可,預設會提供很多實現,比如 CRUD 和列表查詢引數相關的實現。ReactiveMongoRepository 介面預設實現瞭如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.mongodb.repository;
import org.reactivestreams.Publisher;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@NoRepositoryBean
public interface ReactiveMongoRepository<T, ID> extends ReactiveSortingRepository<T, ID>, ReactiveQueryByExampleExecutor<T> {
<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);
}
ReactiveMongoRepository 的整合介面ReactiveSortingRepository、ReactiveQueryByExampleExecutor。
ReactiveSortingRepository介面程式碼如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.repository.reactive;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import reactor.core.publisher.Flux;
@NoRepositoryBean
public interface ReactiveSortingRepository<T, ID> extends ReactiveCrudRepository<T, ID> {
Flux<T> findAll(Sort var1);
}
ReactiveCrudRepository介面有很多方法如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.repository.reactive;
import org.reactivestreams.Publisher;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@NoRepositoryBean
public interface ReactiveCrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> Mono<S> save(S var1);
<S extends T> Flux<S> saveAll(Iterable<S> var1);
<S extends T> Flux<S> saveAll(Publisher<S> var1);
Mono<T> findById(ID var1);
Mono<T> findById(Publisher<ID> var1);
Mono<Boolean> existsById(ID var1);
Mono<Boolean> existsById(Publisher<ID> var1);
Flux<T> findAll();
Flux<T> findAllById(Iterable<ID> var1);
Flux<T> findAllById(Publisher<ID> var1);
Mono<Long> count();
Mono<Void> deleteById(ID var1);
Mono<Void> deleteById(Publisher<ID> var1);
Mono<Void> delete(T var1);
Mono<Void> deleteAll(Iterable<? extends T> var1);
Mono<Void> deleteAll(Publisher<? extends T> var1);
Mono<Void> deleteAll();
}
另外可以看出,介面的命名是遵循規範的,常用命名規則如下:
關鍵字方法命名
And 》findByNameAndPwd
Or》findByNameOrSex
Is》findById
Between 》findByIdBetween
Like 》findByNameLike
NotLike 》findByNameNotLike
OrderBy 》findByIdOrderByXDesc
Not 》findByNameNot
常用程式碼示例:
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();
方法的命名和JPA的命名有相似
5,處理器類 Handler 和控制器類 Controller
修改下 Handler,程式碼如下:
package com.jack.webflux_mongodb.handler;
import com.jack.webflux_mongodb.dao.CityRepository;
import com.jack.webflux_mongodb.domain.City;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* create by jack 2018/5/12
*/
@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));
}
}
6,控制器程式碼如下:
package com.jack.webflux_mongodb.webflux.controller;
import com.jack.webflux_mongodb.domain.City;
import com.jack.webflux_mongodb.handler.CityHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* create by jack 2018/5/12
*/
@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);
}
}
7,執行程式
使用postman進行測試:
測試結果如上圖
8,連線 MongoDB,驗證資料
連線 MongoDB:
docker run -it --rm --link mongo:mongo mongo mongo -u admin -p admin --authenticationDatabase admin mongo/admin
[[email protected] ~]# docker run -it --rm --link mongo:mongo mongo mongo -u admin -p admin --authenticationDatabase admin mongo/admin
Unable to find image 'mongo:latest' locally
Trying to pull repository docker.io/library/mongo ...
latest: Pulling from docker.io/library/mongo
4d0d76e05f3c: Already exists
2da2ecd7fdbd: Already exists
c3a86da34d0f: Already exists
e2b1f447e420: Already exists
c9e820834b36: Already exists
ffa34fa64bf4: Already exists
63127ea58ee0: Already exists
ccb46836c598: Already exists
7b0abf374ec4: Already exists
Digest: sha256:c6d2b2f8c054210db26b492bab81ffab171ee54eb58925fa98fabb4faca3a9cb
MongoDB shell version v3.6.4
connecting to: mongodb://mongo:27017/admin
MongoDB server version: 3.2.0
WARNING: shell and server versions do not match
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
http://docs.mongodb.org/
Questions? Try the support group
http://groups.google.com/group/mongodb-user
2018-05-12T03:32:38.834+0000 I STORAGE [main] In File::open(), ::open for '/home/mongodb/.mongorc.js' failed with No such file or directory
Server has startup warnings:
2018-05-12T10:36:02.745+0800 I CONTROL [initandlisten]
2018-05-12T10:36:02.745+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2018-05-12T10:36:02.745+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2018-05-12T10:36:02.745+0800 I CONTROL [initandlisten]
2018-05-12T10:36:02.745+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2018-05-12T10:36:02.745+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2018-05-12T10:36:02.745+0800 I CONTROL [initandlisten]
>
顯示資料庫列表:
> show dbs
admin 0.000GB
local 0.000GB
>
使用某資料庫:
> use admin
switched to db admin
>
顯示所有的表:
> show collections
city
system.users
system.version
>
如果存在city表,格式化輸出city表的內容
> db.city.find().pretty()
{
"_id" : NumberLong(3),
"provinceId" : NumberLong(7705),
"cityName" : "深圳",
"description" : "深圳市一個充滿活力的城市",
"_class" : "com.jack.webflux_mongodb.domain.City"
}
>
總結:總的來說,主要的還是webflux的知識,在https://blog.csdn.net/j903829182/article/details/80034665文章中是使用map儲存的資訊,這裡改成了mongodb儲存資料了,然後使用了docker來執行mongodb的容器。重點還是Flux和Mono,結合不同的資料儲存方式儲存資料。
原始碼地址:https://github.com/wj903829182/springcloud5/tree/master/webflux_mongodb