springboot2学习-webflux和mongodb
这里学习下webflux和mongodb的结合,使用mongodb来进行数据的存储,使用docker来启动mongodb容器简化开发。docker资料学习可以参考:https://www.jianshu.com/p/f272726db9c5这篇博客的学习来源是http://gitbook.cn/gitchat/column/5acda6f6d7966c5ae1086f2b/topi
这里学习下webflux和mongodb的结合,使用mongodb来进行数据的存储,使用docker来启动mongodb容器简化开发。docker资料学习可以参考:https://www.jianshu.com/p/f272726db9c5
这篇博客的学习来源是http://gitbook.cn/gitchat/column/5acda6f6d7966c5ae1086f2b/topic/5acda9f9d7966c5ae108705c
详细资料可以参考源文,这里只是做一个学习的总结和实践的过程。springboot和mongodb的使用可以参考我之前的博客:https://blog.csdn.net/j903829182/article/details/78197110
环境:虚拟机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
[root@bogon ~]# 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
更多推荐
所有评论(0)