1 下载并安装MongoDB

  1.1 MongoDB官网

    

  1.2 下载

    solutions -> download center

    

  1.3 安装

    双击进入安装即可

    1.3.1 安装时常见bug01

      

    1.3.2 bug01解决办法

      

  1.4 启动mongodb

    技巧01:需要在同安装目录同一级别创建一个data目录来存放数据

    技巧02:将下下面的命令存储成一个 bat 文件,下次启动时双击即可

  1. C:\tool\mongoDB\bin\mongod --dbpath C:\tool\data --smallfiles

  1.5 mongodb正常启动后的控制台信息

    

  1.6 启动MongoDB客户端

    双击mongoDB安装目录下 -> bin -> mongo.exe

    

    1.6.1 常用命令

      show databases -> 显示数据库

      use 数据库名称 -> 更换当前数据库

      show tables -> 查看当前数据库中的数据表

      db.表名.find() -> 查看某个表中的所有数据

      db.表名.find().pretty() -> 查看某个表中的所有数据并进行格式化输出

      

2 SpringBootWebFlux集成MongoDB

  2.1 创建一个项目

    引入相关依赖:webflux、mongodb、devtool、lombok

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5.  
  6. <groupId>cn.xiangxu</groupId>
  7. <artifactId>webflux_demo</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. <packaging>jar</packaging>
  10.  
  11. <name>webflux_demo</name>
  12. <description>Demo project for Spring Boot</description>
  13.  
  14. <parent>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-starter-parent</artifactId>
  17. <version>2.0.3.RELEASE</version>
  18. <relativePath/> <!-- lookup parent from repository -->
  19. </parent>
  20.  
  21. <properties>
  22. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  23. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  24. <java.version>1.8</java.version>
  25. </properties>
  26.  
  27. <dependencies>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-webflux</artifactId>
  31. </dependency>
  32.  
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-devtools</artifactId>
  36. <!--<scope>runtime</scope>-->
  37. <optional>true</optional>
  38. </dependency>
  39. <dependency>
  40. <groupId>org.projectlombok</groupId>
  41. <artifactId>lombok</artifactId>
  42. <optional>true</optional>
  43. </dependency>
  44.  
  45. <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb-reactive -->
  46. <dependency>
  47. <groupId>org.springframework.boot</groupId>
  48. <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
  49. </dependency>
  50.  
  51. <dependency>
  52. <groupId>org.springframework.boot</groupId>
  53. <artifactId>spring-boot-starter-test</artifactId>
  54. <scope>test</scope>
  55. </dependency>
  56. <dependency>
  57. <groupId>io.projectreactor</groupId>
  58. <artifactId>reactor-test</artifactId>
  59. <scope>test</scope>
  60. </dependency>
  61. <dependency>
  62. <groupId>org.junit.jupiter</groupId>
  63. <artifactId>junit-jupiter-api</artifactId>
  64. </dependency>
  65. </dependencies>
  66.  
  67. <build>
  68. <plugins>
  69. <plugin>
  70. <groupId>org.springframework.boot</groupId>
  71. <artifactId>spring-boot-maven-plugin</artifactId>
  72. <configuration>
  73. <fork>true</fork>
  74. </configuration>
  75. </plugin>
  76. </plugins>
  77. </build>
  78.  
  79. </project>

pom.xml

  2.2 启动类

    在启动类上添加 @EnableReactiveMongoRepositories 注解来开启mongodb相关的配置

  1. package cn.xiangxu.webflux_demo;
  2.  
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
  6.  
  7. @SpringBootApplication
  8. @EnableReactiveMongoRepositories
  9. public class WebfluxDemoApplication {
  10.  
  11. public static void main(String[] args) {
  12. SpringApplication.run(WebfluxDemoApplication.class, args);
  13. }
  14. }

  2.3 实体类

    @Document(collection = "user") 目的时定义在mongodb中的表名,相当于JPA中的@Table注解

    技巧01:在mongodb中的主键一般都是String类型的

  1. package cn.xiangxu.webflux_demo.domain;
  2.  
  3. import lombok.Data;
  4. import org.springframework.data.annotation.Id;
  5. import org.springframework.data.mongodb.core.mapping.Document;
  6.  
  7. /**
  8. * @author 王杨帅
  9. * @create 2018-06-27 8:42
  10. * @desc
  11. **/
  12. @Document(collection = "user")
  13. @Data
  14. public class User {
  15. @Id
  16. private String id;
  17.  
  18. private String name;
  19.  
  20. private int age;
  21. }

User.java

  2.4 持久层

    只需要继承 ReactiveMongoRepository 接口就行啦,和JPA差不多

  1. package cn.xiangxu.webflux_demo.repository;
  2.  
  3. import cn.xiangxu.webflux_demo.domain.User;
  4. import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
  5. import org.springframework.stereotype.Repository;
  6.  
  7. /**
  8. * @author 王杨帅
  9. * @create 2018-06-27 8:44
  10. * @desc
  11. **/
  12. @Repository
  13. public interface UserRepository extends ReactiveMongoRepository<User, String> {
  14. }

UserRepository.java

  2.5 控制层

    技巧01:有两种返回方式,一种是把所有数据一次性返回,另一种是像流一样的进行返回

  1. package cn.xiangxu.webflux_demo.web;
  2.  
  3. import cn.xiangxu.webflux_demo.domain.User;
  4. import cn.xiangxu.webflux_demo.repository.UserRepository;
  5. import org.springframework.http.MediaType;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. import reactor.core.publisher.Flux;
  10.  
  11. /**
  12. * @author 王杨帅
  13. * @create 2018-06-27 8:45
  14. * @desc
  15. **/
  16. @RestController
  17. @RequestMapping(value = "/user")
  18. public class UserController {
  19.  
  20. private final UserRepository userRepository;
  21.  
  22. /**
  23. * 利用构造器注入持久层对象
  24. * @param userRepository
  25. */
  26. public UserController(UserRepository userRepository) {
  27. this.userRepository = userRepository;
  28. }
  29.  
  30. /**
  31. * 一次性返回
  32. * @return
  33. */
  34. @GetMapping(value = "/")
  35. public Flux<User> getAll() {
  36. return userRepository.findAll();
  37. }
  38.  
  39. /**
  40. * 流式返回
  41. * @return
  42. */
  43. @GetMapping(value = "/stream/all", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  44. public Flux<User> streamGetAll() {
  45. return userRepository.findAll();
  46. }
  47.  
  48. }

UserController.java

  2.6 配置文件

    前提:安装好mongodb并启动

  1. spring.data.mongodb.uri=mongodb://localhost:27017/webflux

  2.7 启动并测试

    技巧01:利用postman进行测试

    

3 WebFlux实现CRUD

  准备:SpringBootWebFlux项目搭建以及SpringBootWebFlux集成MongoDB请参见上面的

  3.1 新增

    ReactiveCrudRepository 接口中的 save 方法可以实现更新和新增操作

    技巧01:利用save方法进行更新操作时,如果接收到的ID在mongodb中没有对应的记录就会执行新增操作,而且新增数据的ID就是传过来的ID信息

    技巧02:利用save方法进行新增操作时,不需要前端传ID信息,mongodb会自动根据实体类生成ID信息;如果传了ID信息就会变成更新操作了

  1. <S extends T> Mono<S> save(S var1);
  1. /**
  2. * 新增用户
  3. * @param user
  4. * @return
  5. */
  6. @PostMapping
  7. public Mono<User> createUser(@RequestBody User user
  8. ) {
  9. return userRepository.save(user);
  10.  
  11. /**
  12. * Note
  13. * 1 save 可以修改和新增,如果有ID就是修改【该ID存在,如果该ID不存在直接新增】,没有就是新增
  14. */
  15. }

    

  3.2 删除

    需求:根据前端传过来的ID信息删除用户信息,如果删除成功就返回200状态码,删除失败就返回404状态码

    坑01:ReactiveCrudRepository接口提供的一系列delete方法都没有返回自,所以不确定是否已经删除成功

  1. Mono<Void> deleteById(ID var1);
  2.  
  3. Mono<Void> deleteById(Publisher<ID> var1);
  4.  
  5. Mono<Void> delete(T var1);
  6.  
  7. Mono<Void> deleteAll(Iterable<? extends T> var1);
  8.  
  9. Mono<Void> deleteAll(Publisher<? extends T> var1);
  10.  
  11. Mono<Void> deleteAll();

    解坑01:根据前端I传过来的ID查询信息 -> 查到就进行删除操作 -> 返回200状态码

                       -> 查不到就直接返回404状态码

    技巧01:map和flatMap的使用时机

      当要操作数据并返回Mono时使用flatMap; 如果不操作数据,仅仅转换数据时使用Map

    技巧02:如果一个stream没有返回值但方法有要求有返回值时,可以利用then来返回数据

  1. /**
  2. * 删除用户
  3. * 需求:删除成功后返回200状态码,删除失败就返回404状态码
  4. * @param id
  5. * @return
  6. */
  7. @DeleteMapping(value = "/{id}")
  8. public Mono<ResponseEntity<Void>> deleteUser(@PathVariable("id") String id) {
  9. // userRepository.deleteById(id); // deleteById 方法没有返回值,我们无法知道是否删除成功
  10. return userRepository.findById(id)
  11. .flatMap( // 根据ID找到数据进行删除操作,并返回200状态码
  12. user -> userRepository.delete(user)
  13. .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK)))
  14. )
  15. .defaultIfEmpty(new ResponseEntity<Void>(HttpStatus.NOT_FOUND)); // 如果没有查找到数据就返回404状态码
  16.  
  17. /**
  18. * Note
  19. * 1 map和flatMap的使用时机
  20. * 当要操作数据并返回Mono时使用flatMap
  21. * 如果不操作数据,仅仅转换数据时使用Map
  22. * 2 如果一个stream没有返回值但方法有要求有返回值时,可以利用then来返回数据
  23. */
  24.  
  25. }

  3.3 更新

    需求:根据前端传过来的ID和更新数据类进行更新操作;更新成功后返回200状态码和更新后的数据,更新失败后就返回404状态码

    坑01:直接利用save方法进行更新操作时容易产生歧义,因为save方法可以进行更新和删除操作;当接收到对象没有id信息时就进行新增操作,如果有ID信息而且数据库有该ID对应的数据时就进行更新操作,如果有ID信息但是数据库中没有改ID对应的数据时也会进行新增操作

    解坑01: 根据前端传过来的ID查询数据 -> 查到数据就进行更新操作 -> 返回200状态码和更新过后的数据

                       -> 没查到数据就返回404状态码

  1. /**
  2. * 修改数据
  3. * 修改成功返回200和修改成功后的数据,不存在时返回404
  4. * @param id 要修改的用户ID
  5. * @param user 修改数据
  6. * @return
  7. */
  8. @PutMapping(value = "/{id}")
  9. public Mono<ResponseEntity<User>> updateUser(
  10. @PathVariable("id") String id,
  11. @RequestBody User user
  12. ) {
  13. return userRepository.findById(id)
  14. .flatMap( // 操作数据
  15. u -> {
  16. u.setAge(user.getAge());
  17. u.setName(user.getName());
  18. return userRepository.save(u);
  19. }
  20. )
  21. .map(u -> new ResponseEntity<User>(u, HttpStatus.OK)) // 转化数据
  22. .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
  23. }

  3.4 查询

    需求:根据前端传过来的ID查询数据,如果查到就直接返回200状态码和查到的数据,如果不存在该ID对应的数据就直接返回404状态码

  1. /**
  2. * 根据ID查找用户
  3. * 存在时返回200和查到的数据,不存在时就返回404
  4. * @param id 用户ID
  5. * @return
  6. */
  7. @GetMapping(value = "/{id}")
  8. public Mono<ResponseEntity<User>> getById(@PathVariable("id") String id) {
  9.  
  10. return userRepository.findById(id)
  11. .map(u -> new ResponseEntity<User>(u, HttpStatus.OK)) // 转化数据
  12. .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
  13.  
  14. }

  ·3.5 代码汇总

  1. package cn.xiangxu.webflux_demo.web;
  2.  
  3. import cn.xiangxu.webflux_demo.domain.User;
  4. import cn.xiangxu.webflux_demo.repository.UserRepository;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.http.MediaType;
  7. import org.springframework.http.ResponseEntity;
  8. import org.springframework.web.bind.annotation.*;
  9. import reactor.core.publisher.Flux;
  10. import reactor.core.publisher.Mono;
  11.  
  12. /**
  13. * @author 王杨帅
  14. * @create 2018-06-27 8:45
  15. * @desc
  16. **/
  17. @RestController
  18. @RequestMapping(value = "/user")
  19. public class UserController {
  20.  
  21. private final UserRepository userRepository;
  22.  
  23. /**
  24. * 利用构造器注入持久层对象
  25. * @param userRepository
  26. */
  27. public UserController(UserRepository userRepository) {
  28. this.userRepository = userRepository;
  29. }
  30.  
  31. /**
  32. * 以数组形式一次性返回
  33. * @return
  34. */
  35. @GetMapping(value = "/")
  36. public Flux<User> getAll() {
  37. return userRepository.findAll();
  38. }
  39.  
  40. /**
  41. * 以SSE形式流式返回
  42. * @return
  43. */
  44. @GetMapping(value = "/stream/all", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  45. public Flux<User> streamGetAll() {
  46. return userRepository.findAll();
  47. }
  48.  
  49. /**
  50. * 新增用户
  51. * @param user
  52. * @return
  53. */
  54. @PostMapping
  55. public Mono<User> createUser(@RequestBody User user
  56. ) {
  57. return userRepository.save(user);
  58.  
  59. /**
  60. * Note
  61. * 1 save 可以修改和新增,如果有ID就是修改【该ID存在,如果该ID不存在直接新增】,没有就是新增
  62. */
  63. }
  64.  
  65. /**
  66. * 删除用户
  67. * 需求:删除成功后返回200状态码,删除失败就返回404状态码
  68. * @param id
  69. * @return
  70. */
  71. @DeleteMapping(value = "/{id}")
  72. public Mono<ResponseEntity<Void>> deleteUser(@PathVariable("id") String id) {
  73. // userRepository.deleteById(id); // deleteById 方法没有返回值,我们无法知道是否删除成功
  74. return userRepository.findById(id)
  75. .flatMap( // 根据ID找到数据进行删除操作,并返回200状态码
  76. user -> userRepository.delete(user)
  77. .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK)))
  78. )
  79. .defaultIfEmpty(new ResponseEntity<Void>(HttpStatus.NOT_FOUND)); // 如果没有查找到数据就返回404状态码
  80.  
  81. /**
  82. * Note
  83. * 1 map和flatMap的使用时机
  84. * 当要操作数据并返回Mono时使用flatMap
  85. * 如果不操作数据,仅仅转换数据时使用Map
  86. * 2 如果一个stream没有返回值但方法有要求有返回值时,可以利用then来返回数据
  87. */
  88.  
  89. }
  90.  
  91. /**
  92. * 修改数据
  93. * 修改成功返回200和修改成功后的数据,不存在时返回404
  94. * @param id 要修改的用户ID
  95. * @param user 修改数据
  96. * @return
  97. */
  98. @PutMapping(value = "/{id}")
  99. public Mono<ResponseEntity<User>> updateUser(
  100. @PathVariable("id") String id,
  101. @RequestBody User user
  102. ) {
  103. return userRepository.findById(id)
  104. .flatMap( // 操作数据
  105. u -> {
  106. u.setAge(user.getAge());
  107. u.setName(user.getName());
  108. return userRepository.save(u);
  109. }
  110. )
  111. .map(u -> new ResponseEntity<User>(u, HttpStatus.OK)) // 转化数据
  112. .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
  113. }
  114.  
  115. /**
  116. * 根据ID查找用户
  117. * 存在时返回200和查到的数据,不存在时就返回404
  118. * @param id 用户ID
  119. * @return
  120. */
  121. @GetMapping(value = "/{id}")
  122. public Mono<ResponseEntity<User>> getById(@PathVariable("id") String id) {
  123.  
  124. return userRepository.findById(id)
  125. .map(u -> new ResponseEntity<User>(u, HttpStatus.OK)) // 转化数据
  126. .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
  127.  
  128. }
  129.  
  130. /**
  131. * 根据年龄段查询:数组形式返回
  132. * @param start 最小年龄
  133. * @param end 最大年龄
  134. * @return
  135. */
  136. @GetMapping(value = "/age/{start}/{end}")
  137. public Flux<User> findByAge(
  138. @PathVariable("start") Integer start,
  139. @PathVariable("end") Integer end
  140. ) {
  141. return userRepository.findByAgeBetween(start, end);
  142. }
  143.  
  144. /**
  145. * 根据年龄段查询:流式返回
  146. * @param start
  147. * @param end
  148. * @return
  149. */
  150. @GetMapping(value = "/stream/age/{start}/{end}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  151. public Flux<User> streamFindByAge(
  152. @PathVariable("start") Integer start,
  153. @PathVariable("end") Integer end
  154. ) {
  155. return userRepository.findByAgeBetween(start, end);
  156. }
  157.  
  158. /**
  159. * 查询年龄在20-30的用户
  160. * @return
  161. */
  162. @GetMapping(value = "/age/oldUser")
  163. public Flux<User> oldUser() {
  164. return userRepository.oldUser();
  165. }
  166.  
  167. /**
  168. * 查询年龄在20-30的用户
  169. * @return
  170. */
  171. @GetMapping(value = "/stream/age/oldUser", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  172. public Flux<User> streamFindByAge() {
  173. return userRepository.oldUser();
  174. }
  175.  
  176. }

  

4 WebFlux实现JPA

  ReactiveCrudRepository接口除了提供简单的CRUD操作外,还可以进行自定义数据操作方法,但是自定义方法的方法名有一定的要求;如果定义的方法名不满足 SpringData JPA 也可以利用 @Query 注解使用原生的注解进行实现

  4.1 符合JPA规范的写法

    4.1.1 持久层

  1. /**
  2. * 根据年龄段查询用户【PS: 不包括端点值】
  3. * @param start
  4. * @param end
  5. * @return
  6. */
  7. Flux<User> findByAgeBetween(Integer start, Integer end);
  1. package cn.xiangxu.webflux_demo.repository;
  2.  
  3. import cn.xiangxu.webflux_demo.domain.User;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. import org.springframework.data.mongodb.repository.Query;
  6. import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
  7. import org.springframework.stereotype.Repository;
  8. import reactor.core.publisher.Flux;
  9.  
  10. /**
  11. * @author 王杨帅
  12. * @create 2018-06-27 8:44
  13. * @desc
  14. **/
  15. @Repository
  16. public interface UserRepository extends ReactiveMongoRepository<User, String> {
  17.  
  18. /**
  19. * 根据年龄段查询用户【PS: 不包括端点值】
  20. * @param start
  21. * @param end
  22. * @return
  23. */
  24. Flux<User> findByAgeBetween(Integer start, Integer end);
  25.  
  26. /**
  27. * 查询年龄在20-30的用户【PS: 包括端点值】
  28. * 利用MongoDB的 SQL 语句实现
  29. * @return
  30. */
  31. @Query("{'age':{'$gte':20, '$lte':30}}")
  32. Flux<User> oldUser();
  33.  
  34. }

    4.1.2 控制层

  1. /**
  2. * 根据年龄段查询:数组形式返回
  3. * @param start 最小年龄
  4. * @param end 最大年龄
  5. * @return
  6. */
  7. @GetMapping(value = "/age/{start}/{end}")
  8. public Flux<User> findByAge(
  9. @PathVariable("start") Integer start,
  10. @PathVariable("end") Integer end
  11. ) {
  12. return userRepository.findByAgeBetween(start, end);
  13. }
  14.  
  15. /**
  16. * 根据年龄段查询:流式返回
  17. * @param start
  18. * @param end
  19. * @return
  20. */
  21. @GetMapping(value = "/stream/age/{start}/{end}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  22. public Flux<User> streamFindByAge(
  23. @PathVariable("start") Integer start,
  24. @PathVariable("end") Integer end
  25. ) {
  26. return userRepository.findByAgeBetween(start, end);
  27. }

  4.2 @Query的写法

    4.2.1 持久层

  1. /**
  2. * 查询年龄在20-30的用户【PS: 包括端点值】
  3. * 利用MongoDB的 SQL 语句实现
  4. * @return
  5. */
  6. @Query("{'age':{'$gte':20, '$lte':30}}")
  7. Flux<User> oldUser();
  1. package cn.xiangxu.webflux_demo.repository;
  2.  
  3. import cn.xiangxu.webflux_demo.domain.User;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. import org.springframework.data.mongodb.repository.Query;
  6. import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
  7. import org.springframework.stereotype.Repository;
  8. import reactor.core.publisher.Flux;
  9.  
  10. /**
  11. * @author 王杨帅
  12. * @create 2018-06-27 8:44
  13. * @desc
  14. **/
  15. @Repository
  16. public interface UserRepository extends ReactiveMongoRepository<User, String> {
  17.  
  18. /**
  19. * 根据年龄段查询用户【PS: 不包括端点值】
  20. * @param start
  21. * @param end
  22. * @return
  23. */
  24. Flux<User> findByAgeBetween(Integer start, Integer end);
  25.  
  26. /**
  27. * 查询年龄在20-30的用户【PS: 包括端点值】
  28. * 利用MongoDB的 SQL 语句实现
  29. * @return
  30. */
  31. @Query("{'age':{'$gte':20, '$lte':30}}")
  32. Flux<User> oldUser();
  33.  
  34. }

    4.2.2 控制层

  1. /**
  2. * 查询年龄在20-30的用户
  3. * @return
  4. */
  5. @GetMapping(value = "/age/oldUser")
  6. public Flux<User> oldUser() {
  7. return userRepository.oldUser();
  8. }
  9.  
  10. /**
  11. * 查询年龄在20-30的用户
  12. * @return
  13. */
  14. @GetMapping(value = "/stream/age/oldUser", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  15. public Flux<User> streamFindByAge() {
  16. return userRepository.oldUser();
  17. }

  4.3 代码汇总

    4.3.1 持久层

  1. package cn.xiangxu.webflux_demo.repository;
  2.  
  3. import cn.xiangxu.webflux_demo.domain.User;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  5. import org.springframework.data.mongodb.repository.Query;
  6. import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
  7. import org.springframework.stereotype.Repository;
  8. import reactor.core.publisher.Flux;
  9.  
  10. /**
  11. * @author 王杨帅
  12. * @create 2018-06-27 8:44
  13. * @desc
  14. **/
  15. @Repository
  16. public interface UserRepository extends ReactiveMongoRepository<User, String> {
  17.  
  18. /**
  19. * 根据年龄段查询用户【PS: 不包括端点值】
  20. * @param start
  21. * @param end
  22. * @return
  23. */
  24. Flux<User> findByAgeBetween(Integer start, Integer end);
  25.  
  26. /**
  27. * 查询年龄在20-30的用户【PS: 包括端点值】
  28. * 利用MongoDB的 SQL 语句实现
  29. * @return
  30. */
  31. @Query("{'age':{'$gte':20, '$lte':30}}")
  32. Flux<User> oldUser();
  33.  
  34. }

    4.3.2 控制层

  1. package cn.xiangxu.webflux_demo.web;
  2.  
  3. import cn.xiangxu.webflux_demo.domain.User;
  4. import cn.xiangxu.webflux_demo.repository.UserRepository;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.http.MediaType;
  7. import org.springframework.http.ResponseEntity;
  8. import org.springframework.web.bind.annotation.*;
  9. import reactor.core.publisher.Flux;
  10. import reactor.core.publisher.Mono;
  11.  
  12. /**
  13. * @author 王杨帅
  14. * @create 2018-06-27 8:45
  15. * @desc
  16. **/
  17. @RestController
  18. @RequestMapping(value = "/user")
  19. public class UserController {
  20.  
  21. private final UserRepository userRepository;
  22.  
  23. /**
  24. * 利用构造器注入持久层对象
  25. * @param userRepository
  26. */
  27. public UserController(UserRepository userRepository) {
  28. this.userRepository = userRepository;
  29. }
  30.  
  31. /**
  32. * 以数组形式一次性返回
  33. * @return
  34. */
  35. @GetMapping(value = "/")
  36. public Flux<User> getAll() {
  37. return userRepository.findAll();
  38. }
  39.  
  40. /**
  41. * 以SSE形式流式返回
  42. * @return
  43. */
  44. @GetMapping(value = "/stream/all", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  45. public Flux<User> streamGetAll() {
  46. return userRepository.findAll();
  47. }
  48.  
  49. /**
  50. * 新增用户
  51. * @param user
  52. * @return
  53. */
  54. @PostMapping
  55. public Mono<User> createUser(@RequestBody User user
  56. ) {
  57. return userRepository.save(user);
  58.  
  59. /**
  60. * Note
  61. * 1 save 可以修改和新增,如果有ID就是修改【该ID存在,如果该ID不存在直接新增】,没有就是新增
  62. */
  63. }
  64.  
  65. /**
  66. * 删除用户
  67. * 需求:删除成功后返回200状态码,删除失败就返回404状态码
  68. * @param id
  69. * @return
  70. */
  71. @DeleteMapping(value = "/{id}")
  72. public Mono<ResponseEntity<Void>> deleteUser(@PathVariable("id") String id) {
  73. // userRepository.deleteById(id); // deleteById 方法没有返回值,我们无法知道是否删除成功
  74. return userRepository.findById(id)
  75. .flatMap( // 根据ID找到数据进行删除操作,并返回200状态码
  76. user -> userRepository.delete(user)
  77. .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK)))
  78. )
  79. .defaultIfEmpty(new ResponseEntity<Void>(HttpStatus.NOT_FOUND)); // 如果没有查找到数据就返回404状态码
  80.  
  81. /**
  82. * Note
  83. * 1 map和flatMap的使用时机
  84. * 当要操作数据并返回Mono时使用flatMap
  85. * 如果不操作数据,仅仅转换数据时使用Map
  86. * 2 如果一个stream没有返回值但方法有要求有返回值时,可以利用then来返回数据
  87. */
  88.  
  89. }
  90.  
  91. /**
  92. * 修改数据
  93. * 修改成功返回200和修改成功后的数据,不存在时返回404
  94. * @param id 要修改的用户ID
  95. * @param user 修改数据
  96. * @return
  97. */
  98. @PutMapping(value = "/{id}")
  99. public Mono<ResponseEntity<User>> updateUser(
  100. @PathVariable("id") String id,
  101. @RequestBody User user
  102. ) {
  103. return userRepository.findById(id)
  104. .flatMap( // 操作数据
  105. u -> {
  106. u.setAge(user.getAge());
  107. u.setName(user.getName());
  108. return userRepository.save(u);
  109. }
  110. )
  111. .map(u -> new ResponseEntity<User>(u, HttpStatus.OK)) // 转化数据
  112. .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
  113. }
  114.  
  115. /**
  116. * 根据ID查找用户
  117. * 存在时返回200和查到的数据,不存在时就返回404
  118. * @param id 用户ID
  119. * @return
  120. */
  121. @GetMapping(value = "/{id}")
  122. public Mono<ResponseEntity<User>> getById(@PathVariable("id") String id) {
  123.  
  124. return userRepository.findById(id)
  125. .map(u -> new ResponseEntity<User>(u, HttpStatus.OK)) // 转化数据
  126. .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
  127.  
  128. }
  129.  
  130. /**
  131. * 根据年龄段查询:数组形式返回
  132. * @param start 最小年龄
  133. * @param end 最大年龄
  134. * @return
  135. */
  136. @GetMapping(value = "/age/{start}/{end}")
  137. public Flux<User> findByAge(
  138. @PathVariable("start") Integer start,
  139. @PathVariable("end") Integer end
  140. ) {
  141. return userRepository.findByAgeBetween(start, end);
  142. }
  143.  
  144. /**
  145. * 根据年龄段查询:流式返回
  146. * @param start
  147. * @param end
  148. * @return
  149. */
  150. @GetMapping(value = "/stream/age/{start}/{end}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  151. public Flux<User> streamFindByAge(
  152. @PathVariable("start") Integer start,
  153. @PathVariable("end") Integer end
  154. ) {
  155. return userRepository.findByAgeBetween(start, end);
  156. }
  157.  
  158. /**
  159. * 查询年龄在20-30的用户
  160. * @return
  161. */
  162. @GetMapping(value = "/age/oldUser")
  163. public Flux<User> oldUser() {
  164. return userRepository.oldUser();
  165. }
  166.  
  167. /**
  168. * 查询年龄在20-30的用户
  169. * @return
  170. */
  171. @GetMapping(value = "/stream/age/oldUser", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  172. public Flux<User> streamFindByAge() {
  173. return userRepository.oldUser();
  174. }
  175.  
  176. }

5 参数校验

  技巧01:参数校验和MVC模式相同,只需要在实体类的成员属性上添加相应的注解即可;然后在请求控制方法的参数上加上@Valid即可

  5.1 实体类

  1. package cn.xiangxu.webflux_test.domain.domain_do;
  2.  
  3. import lombok.Data;
  4. import org.hibernate.validator.constraints.Range;
  5. import org.springframework.data.annotation.Id;
  6. import org.springframework.data.mongodb.core.mapping.Document;
  7.  
  8. import javax.validation.constraints.NotBlank;
  9.  
  10. /**
  11. * @author 王杨帅
  12. * @create 2018-08-02 15:30
  13. * @desc 学生实体类
  14. **/
  15. @Document(collection = "student")
  16. @Data
  17. public class StudentDO {
  18. @Id
  19. private String id;
  20.  
  21. @NotBlank
  22. private String name;
  23. private String address;
  24. @Range(min = 12, max = 50)
  25. private Integer age;
  26. }

StudentDO.java

  5.2 持久层

  1. package cn.xiangxu.webflux_test.reposigory;
  2.  
  3. import cn.xiangxu.webflux_test.domain.domain_do.StudentDO;
  4. import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
  5. import org.springframework.stereotype.Repository;
  6.  
  7. /**
  8. * @author 王杨帅
  9. * @create 2018-08-02 15:31
  10. * @desc 学生持久层
  11. **/
  12. @Repository
  13. public interface StudentRepository extends ReactiveMongoRepository<StudentDO, String> {
  14. }

StudentRepository.java

  5.3 控制层

    坑01:在MVC模式时可以在控制方法上使用  BindingResult ,但是在 WebFlux 模式下不可以使用;只能通过创建切面进行异常捕获

    技巧02:添加了@Valid注解后如果有参数不合法时抛出的异常是 WebExchangeBindException

  1. package cn.xiangxu.webflux_test.controller;
  2.  
  3. import cn.xiangxu.webflux_test.domain.domain_do.StudentDO;
  4. import cn.xiangxu.webflux_test.reposigory.StudentRepository;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.http.HttpStatus;
  8. import org.springframework.http.ResponseEntity;
  9. import org.springframework.web.bind.annotation.*;
  10. import reactor.core.publisher.Flux;
  11. import reactor.core.publisher.Mono;
  12.  
  13. import javax.validation.Valid;
  14.  
  15. import static cn.xiangxu.webflux_test.util.CheckUtil.checkeName;
  16.  
  17. /**
  18. * @author 王杨帅
  19. * @create 2018-08-02 15:44
  20. * @desc 学生控制层
  21. **/
  22. @RestController
  23. @RequestMapping(value = "/stu")
  24. @Slf4j
  25. public class StudentController {
  26.  
  27. @Autowired
  28. private StudentRepository studentRepository;
  29.  
  30. @GetMapping
  31. public Flux<StudentDO> findList() {
  32. return studentRepository.findAll();
  33. }
  34.  
  35. @PostMapping
  36. public Mono<StudentDO> create(
  37. @Valid @RequestBody StudentDO studentDO) {
  38. System.out.println(studentDO);
  39. checkeName(studentDO.getName());
  40. return studentRepository.save(studentDO);
  41. }
  42.  
  43. @PutMapping()
  44. public Mono<ResponseEntity<String>> update(
  45. @Valid @RequestBody StudentDO studentDO
  46. ) {
  47. log.info("前端传过来的数据为:" + studentDO);
  48. checkeName(studentDO.getName());
  49. return studentRepository.findById(studentDO.getId())
  50. .flatMap(student -> studentRepository.save(studentDO))
  51. .map(student -> new ResponseEntity<String>("更新成功", HttpStatus.OK))
  52. .defaultIfEmpty(new ResponseEntity<String>("ID不合法", HttpStatus.BAD_REQUEST));
  53. }
  54.  
  55. @DeleteMapping(value = "/{id}")
  56. public Mono<ResponseEntity<Void>> delete(
  57. @PathVariable(value = "id") String id
  58. ) {
  59. log.info("从前端获取到的ID信息为:" + id);
  60. return studentRepository.findById(id)
  61. .flatMap(
  62. student -> {
  63. return studentRepository.deleteById(student.getId())
  64. .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK)));
  65. }
  66. )
  67. .defaultIfEmpty(new ResponseEntity<Void>(HttpStatus.NOT_FOUND));
  68. }
  69.  
  70. @GetMapping(value = "/{id}")
  71. public Mono<ResponseEntity<StudentDO>> findById(
  72. @PathVariable("id") String id
  73. ) {
  74. log.info("从前端获取到的参数信息为:" + id);
  75. return studentRepository.findById(id)
  76. .map(student -> new ResponseEntity<StudentDO>(student, HttpStatus.OK))
  77. .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
  78. }
  79.  
  80. }

StudentController.java

  5.4 编写异常处理切面

  1. package cn.xiangxu.webflux_test.exception.handler;
  2.  
  3. import cn.xiangxu.webflux_test.exception.CheckException;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
  6. import org.springframework.http.HttpStatus;
  7. import org.springframework.http.ResponseEntity;
  8. import org.springframework.web.bind.annotation.ControllerAdvice;
  9. import org.springframework.web.bind.annotation.ExceptionHandler;
  10. import org.springframework.web.bind.support.WebExchangeBindException;
  11.  
  12. import java.util.Optional;
  13.  
  14. /**
  15. * @author 王杨帅
  16. * @create 2018-08-02 16:31
  17. * @desc
  18. **/
  19. @ControllerAdvice
  20. @Slf4j
  21. public class CheckAdvice {
  22. @ExceptionHandler(WebExchangeBindException.class)
  23. public ResponseEntity handleWebExchangeBindException(WebExchangeBindException e) {
  24. log.error(e.getMessage());
  25.  
  26. return new ResponseEntity<String>(toStr(e), HttpStatus.BAD_REQUEST);
  27. }
  28.  
  29. @ExceptionHandler(CheckException.class)
  30. public ResponseEntity handleCheckException(CheckException e) {
  31. log.error(e.getMessage());
  32. return new ResponseEntity<String>(toStr(e), HttpStatus.BAD_REQUEST);
  33. }
  34.  
  35. private String toStr(CheckException e) {
  36. return e.getFiledName() + " : " + e.getFiledValue();
  37. }
  38.  
  39. /**
  40. * 把校验异常转化成字符串
  41. * @param e
  42. * @return
  43. */
  44. private String toStr(WebExchangeBindException e) {
  45. return e.getFieldErrors().stream()
  46. .map(error -> error.getField() + " : " + error.getDefaultMessage())
  47. .reduce("", (s1, s2) -> s1 + " \n " + s2);
  48. }
  49. }

CheckAdvice.java

  5.5 自定义校验方法

    自定义校验方法有两种方式,一种自定义一个参数校验注解,另外一种是自定义一个参数校验方法【PS: 本博文基于后者】

    5.5.1 自定义异常

  1. package cn.xiangxu.webflux_test.exception;
  2.  
  3. import lombok.Data;
  4.  
  5. /**
  6. * @author 王杨帅
  7. * @create 2018-08-02 17:01
  8. * @desc 检查异常
  9. **/
  10. @Data
  11. public class CheckException extends RuntimeException {
  12.  
  13. /**
  14. * 出错字段
  15. */
  16. private String filedName;
  17.  
  18. /**
  19. * 出错值
  20. */
  21. private String filedValue;
  22.  
  23. public CheckException(String message, String filedName, String filedValue) {
  24. super(message);
  25. this.filedName = filedName;
  26. this.filedValue = filedValue;
  27. }
  28.  
  29. public CheckException(String filedName, String filedValue) {
  30. this.filedName = filedName;
  31. this.filedValue = filedValue;
  32. }
  33. }

CheckException.java

    5.5.2 编写捕获自定义异常的切面

  1. package cn.xiangxu.webflux_test.exception.handler;
  2.  
  3. import cn.xiangxu.webflux_test.exception.CheckException;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
  6. import org.springframework.http.HttpStatus;
  7. import org.springframework.http.ResponseEntity;
  8. import org.springframework.web.bind.annotation.ControllerAdvice;
  9. import org.springframework.web.bind.annotation.ExceptionHandler;
  10. import org.springframework.web.bind.support.WebExchangeBindException;
  11.  
  12. import java.util.Optional;
  13.  
  14. /**
  15. * @author 王杨帅
  16. * @create 2018-08-02 16:31
  17. * @desc
  18. **/
  19. @ControllerAdvice
  20. @Slf4j
  21. public class CheckAdvice {
  22. @ExceptionHandler(WebExchangeBindException.class)
  23. public ResponseEntity handleWebExchangeBindException(WebExchangeBindException e) {
  24. log.error(e.getMessage());
  25.  
  26. return new ResponseEntity<String>(toStr(e), HttpStatus.BAD_REQUEST);
  27. }
  28.  
  29. @ExceptionHandler(CheckException.class)
  30. public ResponseEntity handleCheckException(CheckException e) {
  31. log.error(e.getMessage());
  32. return new ResponseEntity<String>(toStr(e), HttpStatus.BAD_REQUEST);
  33. }
  34.  
  35. private String toStr(CheckException e) {
  36. return e.getFiledName() + " : " + e.getFiledValue();
  37. }
  38.  
  39. /**
  40. * 把校验异常转化成字符串
  41. * @param e
  42. * @return
  43. */
  44. private String toStr(WebExchangeBindException e) {
  45. return e.getFieldErrors().stream()
  46. .map(error -> error.getField() + " : " + error.getDefaultMessage())
  47. .reduce("", (s1, s2) -> s1 + " \n " + s2);
  48. }
  49. }

CheckAdvice.java

    5 .5.3 自定义校验方法

  1. package cn.xiangxu.webflux_test.util;
  2.  
  3. import cn.xiangxu.webflux_test.exception.CheckException;
  4.  
  5. import java.util.Arrays;
  6. import java.util.stream.Stream;
  7.  
  8. /**
  9. * @author 王杨帅
  10. * @create 2018-08-02 17:00
  11. * @desc 检查工具类
  12. **/
  13. public class CheckUtil {
  14.  
  15. private static final String[] INVALID_NAMES = {"admin", "fury"};
  16.  
  17. /**
  18. * 校验名字:不成功时抛出自定义异常
  19. * @param value
  20. */
  21. public static void checkeName(String value) {
  22. Stream.of(INVALID_NAMES)
  23. .filter(name -> name.equalsIgnoreCase(value))
  24. .findAny()
  25. .ifPresent(
  26. name -> {
  27. throw new CheckException("name", value);
  28. }
  29. );
  30. }
  31.  
  32. }

CheckUtil.java

    5.5.4 使用自定义参数校验方法

  1. package cn.xiangxu.webflux_test.controller;
  2.  
  3. import cn.xiangxu.webflux_test.domain.domain_do.StudentDO;
  4. import cn.xiangxu.webflux_test.reposigory.StudentRepository;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.http.HttpStatus;
  8. import org.springframework.http.ResponseEntity;
  9. import org.springframework.validation.BindingResult;
  10. import org.springframework.web.bind.annotation.*;
  11. import reactor.core.publisher.Flux;
  12. import reactor.core.publisher.Mono;
  13.  
  14. import javax.validation.Valid;
  15.  
  16. import static cn.xiangxu.webflux_test.util.CheckUtil.checkeName;
  17.  
  18. /**
  19. * @author 王杨帅
  20. * @create 2018-08-02 15:44
  21. * @desc 学生控制层
  22. **/
  23. @RestController
  24. @RequestMapping(value = "/stu")
  25. @Slf4j
  26. public class StudentController {
  27.  
  28. @Autowired
  29. private StudentRepository studentRepository;
  30.  
  31. @GetMapping
  32. public Flux<StudentDO> findList() {
  33. return studentRepository.findAll();
  34. }
  35.  
  36. @PostMapping
  37. public Mono<StudentDO> create(
  38. @Valid @RequestBody StudentDO studentDO) {
  39. System.out.println(studentDO);
  40. checkeName(studentDO.getName());
  41. return studentRepository.save(studentDO);
  42. }
  43.  
  44. @PutMapping()
  45. public Mono<ResponseEntity<String>> update(
  46. @Valid @RequestBody StudentDO studentDO
  47.  
  48. ) {
  49. log.info("前端传过来的数据为:" + studentDO);
  50. checkeName(studentDO.getName());
  51. return studentRepository.findById(studentDO.getId())
  52. .flatMap(student -> studentRepository.save(studentDO))
  53. .map(student -> new ResponseEntity<String>("更新成功", HttpStatus.OK))
  54. .defaultIfEmpty(new ResponseEntity<String>("ID不合法", HttpStatus.BAD_REQUEST));
  55. }
  56.  
  57. @DeleteMapping(value = "/{id}")
  58. public Mono<ResponseEntity<Void>> delete(
  59. @PathVariable(value = "id") String id
  60. ) {
  61. log.info("从前端获取到的ID信息为:" + id);
  62. return studentRepository.findById(id)
  63. .flatMap(
  64. student -> {
  65. return studentRepository.deleteById(student.getId())
  66. .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK)));
  67. }
  68. )
  69. .defaultIfEmpty(new ResponseEntity<Void>(HttpStatus.NOT_FOUND));
  70. }
  71.  
  72. @GetMapping(value = "/{id}")
  73. public Mono<ResponseEntity<StudentDO>> findById(
  74. @PathVariable("id") String id
  75. ) {
  76. log.info("从前端获取到的参数信息为:" + id);
  77. return studentRepository.findById(id)
  78. .map(student -> new ResponseEntity<StudentDO>(student, HttpStatus.OK))
  79. .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
  80. }
  81.  
  82. }

StudentController.java

6 SpringBootWebflux 整合 MongoDB实现CRUD参考代码

  

WebFlux04 SpringBootWebFlux集成MongoDB之Windows版本、WebFlux实现CRUD、WebFlux实现JPA、参数校验的更多相关文章

  1. spring集成mongodb jar包版本问题

    在开发过程中,spring集成mongodb的jar包. 如果需要使用排序功能. spring-data-mongodb-1.4.1.RELEASE.jar 的版本为1.4.1,如果使用如下代码: Q ...

  2. Mongodb在Windows 7下的安装及配置

    第一步 下载MongoDB: 下载mongodb的windows版本,有32位和64位版本,根据操作系统情况下载,下载地址:http://www.mongodb.org/downloads 解压缩至指 ...

  3. Mongodb在Windows下安装及配置 【转】

    1.下载mongodb的windows版本,有32位和64位版本,根据系统情况下载,下载地址:http://www.mongodb.org/downloads 2.解压缩至E:/mongodb即可 3 ...

  4. Spring Boot 2 快速教程:WebFlux 集成 Mongodb(四)

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第104篇原创 文章工程:* JDK 1.8* M ...

  5. Spring Boot WebFlux 集成 Mongodb 数据源操作

    WebFlux 整合 Mongodb 前言 上一讲用 Map 数据结构内存式存储了数据.这样数据就不会持久化,本文我们用 MongoDB 来实现 WebFlux 对数据源的操作. 什么是 MongoD ...

  6. asp.net core集成MongoDB

    0.目录 整体架构目录:ASP.NET Core分布式项目实战-目录 一.前言及MongoDB的介绍 最近在整合自己的框架,顺便把MongoDBD的最简单CRUD重构一下作为组件化集成到asp.net ...

  7. mongoDB在windows下安装与配置方案

    首先在官网下载mongoDB的安装包: https://www.mongodb.org/downloads 百度云盘下载:http://pan.baidu.com/s/1slUSGYp (安装版 wi ...

  8. 【MongoDB】windows平台搭建Mongo数据库复制集(类似集群)(转)

    原文链接:[MongoDB]windows平台搭建Mongo数据库复制集(类似集群)(一) Replica  Sets(复制集)是在mongodDB1.6版本开始新增的功能,它可以实现故障自动切换和自 ...

  9. Mongodb在Windows上的配置

    1.打开mongodb的官网:https://www.mongodb.org/进行下载相应平台的安装包 2.我们选择最新版的3.2版本来下载,选择对应的操作系统版本来下载,这里选择windows Mo ...

随机推荐

  1. 安装使用lynis扫描Linux的安全漏洞

    Lynis是Linux平台上的一款安全漏洞扫描工具.它可以扫描系统的安全漏洞.收集系统信息.安装的软件信息.配置问题.没有设置密码的用户和防火墙等等. Lynis是流行可靠的安全扫描工具. 前不久,L ...

  2. python学习之准备

    快速入门:十分钟学会Pythonhttp://python.jobbole.com/43922/python框架http://www.elias.cn/Python/HomePage#toc14[Py ...

  3. storm-kafka源码走读之KafkaSpout

    from: http://blog.csdn.net/wzhg0508/article/details/40903919 (五)storm-kafka源码走读之KafkaSpout 原创 2014年1 ...

  4. 微博6月底升级后 报 10017/2/statuses/share.json或者10014/2/statuses/share.json错误

    一,背景 2017-06-26微博公告替换了一些接口,导致以前的: statuses/repost 转发一条微博 statuses/update 发布一条微博 statuses/upload 上传图片 ...

  5. Windows 系统定时自动重启

    1.创建新文本并输入 shutdown -r -t 0 保存成.bat文件 2.创建系统任务计划 2.1 在开始中打开[任务计划程序] 2.2 新建创建任务计划目录 2.3 在新目录下新建任务计划即可 ...

  6. 把color转成image的方法

    - (UIImage*)createImageWithColor:(UIColor*) color { CGRect rect=CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); ...

  7. maven编译问题:maven编译成功,eclipse文件未编译

    我们先来看一个正常的编译流程: 1.从svn上检出一个项目: 2.看该工程是否为maven项目,不是则先转为maven项目:右键单击项目,选择configure->Convert to Mave ...

  8. Volley的post使用

    直接看代码,注意在manifest中加入Internet权限 <uses-permission android:name="android.permission.INTERNET&qu ...

  9. php通过时间戳处理时间!

    1.获取当前时间方法date() 很简单,这就是获取时间的方法,格式为:date(format,format,timestamp),format为格式.timestamp为时间戳–可填参数. 2.获取 ...

  10. Linux: How to delete a disk or LUN reference from /dev

    In AIX, there is rmdev command to remove a disk/LUN from /dev directory i.e to make the disk/LUN una ...