本文为实战SpringCloud响应式微服务系列教程第十章,本章给出响应式RESTful服务完整代码示例。建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末。

在前面章节中我们讲了如何使用 Spring Initializer初始化响应式web应用,本节中就不再做过多介绍(请回顾第九章内容)。

在学习本章内容之前需要了解mongodb以及redis,mongodb以及redis可查阅相关资料进行全面了解,并在本地环境搭建mongodb和redis。

  1. server:
  2. port: 9801
  3. spring:
  4. application:
  5. name: advert
  6. data:
  7. mongodb:
  8. uri: mongodb://localhost:27017/db_advert
  9. http:
  10. encoding:
  11. force: true
  12. charset: UTF-8
  13. enabled: true
  14. redis:
  15. host: 127.0.0.1
  16. password: 123456
  17. logback:
  18. level: info

 

以上配置代码是我们目前学习的响应式RESTful服务的全部配置,配置比较简单,spring.data.mongodb.uri: mongodb://localhost:27017/db_advertspring.data.redis是我们服务的核心配置,我们知道传统的数据库是不支持响应式数据读取的,所以这里使用mongodb和redis代替。

springboot 本身提供了cassandra/couchbase/mongodb/redis这几个NoSQL数据库的响应式驱动:

阻塞式的spring-boot-starter-data-mongodb 改为响应式的mongodb依赖spring-boot-starter-data-mongodb-reactive:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
  4. </dependency>

 

  1. /**
  2. * 广告投放
  3. */
  4. @Document(collection="advert")//集合名
  5. @Data
  6. @Builder
  7. @NoArgsConstructor
  8. @AllArgsConstructor
  9. public class Advert implements Serializable {
  10. private static final long serialVersionUID = -8985545025018238754L;
  11. /**
  12. * 主键
  13. */
  14. @Id
  15. private String id;
  16. /**
  17. * 内容
  18. */
  19. private String content;
  20. /**
  21. * 发布人
  22. */
  23. private Long userId;
  24. /**
  25. * 创建时间
  26. */
  27. private Date creatData;
  28. /**
  29. * 图片地址
  30. */
  31. private String imgUrl;
  32. /**
  33. * 视频地址
  34. */
  35. private String videoUrl;
  36. /**
  37. * 广告类型(视频图片)
  38. */
  39. private String advertType;
  40. /**
  41. * 今日投放地区
  42. */
  43. private String launchArea;
  44. /**
  45. * 投放时长(小时为单位)
  46. */
  47. private int durationTime;
  48. /**
  49. * 广告类型
  50. */
  51. private int classify;
  52. /**
  53. * 计费方式
  54. */
  55. private int billingMode;
  56. /**
  57. * 展示位置(首页轮播,其他轮播,首页其他位置,其他)
  58. */
  59. private int displayPosition;
  60. /**
  61. * 广告主题
  62. */
  63. private String advertTitle;
  64. /**
  65. * 是否需要自定义展示页面
  66. */
  67. private int isCustom;
  68. /**
  69. * 索引关键词
  70. */
  71. private String keyWords;
  72. }

 

其中@document把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档,标注在实体类上,类似于hibernate的entity注解。其他注解均为lombok的注解。

  1. import com.shmc.advert.model.po.Advert;
  2. import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
  3. import org.springframework.data.mongodb.repository.Tailable;
  4. import org.springframework.stereotype.Repository;
  5. import reactor.core.publisher.Flux;
  6. @Repository
  7. public interface AdvertRepository extends ReactiveMongoRepository<Advert,Long> {
  8. @Tailable
  9. Flux<Advert> findBy();
  10. }

 

其中@Repository是org.springframework.stereotype.Repository的注解,这个大家应该都很熟悉了不做解释。

从以上代码中我们可以清楚看到AdvertRepository 继承了ReactiveMongoRepository,ReactiveMongoRepository正是我们依赖的maven响应式mongodb-reactive中的类,其中@Tailable注解,该注解类似于Linux中的tail ,可以将DB的变化以响应式流的方式获取到并推送给前端。

除了可以继承ReactiveMongoRepository之外我们还可以通过注入MongoTemplate来操作mongodb,但是MongoTemplate做不到实时监控和主动推送。如:

  1. @Autowired
  2. MongoTemplate mongoTemplate;

 

Service接口:

  1. import com.shmc.advert.model.po.Advert;
  2. import reactor.core.publisher.Flux;
  3. import reactor.core.publisher.Mono;
  4. public interface AdvertService {
  5. Mono<Advert> saveAdvert(Advert advert);
  6. Mono<Advert> findById(String id);
  7. Flux<Advert> findAll();
  8. Flux<Advert> findByAll();
  9. }

 

Service实现类:

  1. @Service
  2. public class AdvertServiceImpl implements AdvertService {
  3. @Autowired
  4. MongoTemplate mongoTemplate;
  5. @Autowired
  6. private AdvertRepository advertRepository;
  7. @Override
  8. public Mono<Advert> saveAdvert(Advert advert){
  9. advert.setId(new IdWorker().nextId());
  10. advert.setCreatData(new Date());
  11. mongoTemplate.insert(advert);
  12. return Mono.just(advert);
  13. }
  14. @Override
  15. public Mono<Advert> findById(String id){
  16. Query query = new Query(Criteria.where("id").is(id));
  17. return Mono.just(mongoTemplate.findOne(query,Advert.class));
  18. }
  19. @Override
  20. public Flux<Advert> findAll(){
  21. return advertRepository.findAll();
  22. }
  23. @Override
  24. public Flux<Advert> findByAll(){
  25. return advertRepository.findBy();
  26. }
  27. }
  1. import com.shmc.advert.model.po.Advert;
  2. import com.shmc.advert.service.AdvertService;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.http.MediaType;
  5. import org.springframework.web.bind.annotation.*;
  6. import reactor.core.publisher.Flux;
  7. import reactor.core.publisher.Mono;
  8. import java.time.Duration;
  9. @RestController
  10. @RequestMapping("/advert")
  11. public class AdvertController {
  12. @Autowired
  13. private AdvertService advertService;
  14. @PostMapping("/saveAdvert")
  15. public Mono<Advert> saveAdvert(@RequestBody Advert advert){
  16. return advertService.saveAdvert(advert);
  17. }
  18. @GetMapping("/findById/{id}")
  19. public Mono<Advert> findById(@PathVariable String id){
  20. return advertService.findById(id);
  21. }
  22. /**
  23. * 以stream+json流的方式推送到客户端
  24. * @return
  25. */
  26. @GetMapping(value = "/findAllPreSec", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
  27. public Flux<Advert> findAllPreSec() {
  28. return advertService.findAll().delayElements(Duration.ofSeconds(1));
  29. }
  30. /**
  31. * 数据变更
  32. * @return
  33. */
  34. @GetMapping(value = "/findByAll", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
  35. public Flux<Advert> findByAll(){
  36. return advertService.findByAll();
  37. }
  38. }

 

至此基于RESTful的响应式服务我们全部完成了,启动程序访问“/advert/findAllPreSec”接口和”/advert/findByAll“接口就可以看到响应式的数据推送了。

findAllPreSec这个方法。使用了delayElements使得每隔一秒钟获取一条数据发送给客户端,以“异步响应式流”的方式逐条推送。

这里指定了MediaType是APPLICATION_STREAM_JSON,即application/stream+json格式。

在浏览器中就可以看到每隔一秒出现一条记录。运行程序,访问findByAll接口,然后测试调用save接口添加advert数据,或者直接通过MongoDB Compass客户端添加Stu数据,就会看到在页面中实时看到新添加的数据了。

下一章会吧代码上传到gitee,各位看官如有需要请自行下载。

实战SpringCloud响应式微服务系列教程(第一章)

实战SpringCloud响应式微服务系列教程(第二章)

实战SpringCloud响应式微服务系列教程(第三章)

实战SpringCloud响应式微服务系列教程(第四章)

实战SpringCloud响应式微服务系列教程(第五章)

实战SpringCloud响应式微服务系列教程(第六章)

实战SpringCloud响应式微服务系列教程(第七章)

实战SpringCloud响应式微服务系列教程(第八章)

实战SpringCloud响应式微服务系列教程(第九章)

版权声明:本文为javazhiyin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/javazhiyin/p/11797349.html