实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,通用型 2核4GB
简介: 实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例

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

1.搭建响应式RESTful服务。

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

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

2.application.yml文件配置

server:
  port: 9801
spring:
  application:
    name: advert
  data:
    mongodb:
      uri: mongodb://localhost:27017/db_advert
  http:
    encoding:
      force: true
      charset: UTF-8
      enabled: true
  redis:
    host: 127.0.0.1
    password: 123456
logback:
  level: info

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

3.集成响应式的MongoDB

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

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

reactive:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>

(1)编写实体类:

/**
 * 广告投放
*/
@Document(collection="advert")//集合名
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Advert implements Serializable {
    private static final long serialVersionUID = -8985545025018238754L;
    /**
     * 主键
     */
    @Id
    private String id;
    /**
     * 内容
     */
    private String content;
    /**
     * 发布人
     */
    private Long userId;
    /**
     * 创建时间
     */
    private Date creatData;
    /**
     * 图片地址
     */
    private String imgUrl;
    /**
     * 视频地址
     */
    private String videoUrl;
    /**
     * 广告类型(视频图片)
     */
    private String advertType;
    /**
     * 今日投放地区
     */
    private String launchArea;
    /**
     * 投放时长(小时为单位)
     */
    private int durationTime;
    /**
     * 广告类型
     */
    private int classify;
    /**
     * 计费方式
     */
    private int billingMode;
    /**
     * 展示位置(首页轮播,其他轮播,首页其他位置,其他)
     */
    private int displayPosition;
    /**
     * 广告主题
     */
    private String advertTitle;
    /**
     * 是否需要自定义展示页面
     */
    private int isCustom;
    /**
     * 索引关键词
     */
    private String keyWords;
}

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

(2)编写repository接口

import com.shmc.advert.model.po.Advert;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.data.mongodb.repository.Tailable;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
@Repository
public interface AdvertRepository extends ReactiveMongoRepository<Advert,Long> {
    @Tailable
    Flux<Advert> findBy();
}
 
其中@Repository是org.springframework.stereotype.Repository的注解,这个大家应该都很熟悉了不做解释。
从以上代码中我们可以清楚看到AdvertRepository 继承了ReactiveMongoRepository,ReactiveMongoRepository正是我们依赖的maven响应式mongodb-reactive中的类,其中@Tailable注解,该注解类似于Linux中的tail ,可以将DB的变化以响应式流的方式获取到并推送给前端。
除了可以继承ReactiveMongoRepository之外我们还可以通过注入MongoTemplate来操作mongodb,但是MongoTemplate做不到实时监控和主动推送。如:
@Autowired
MongoTemplate mongoTemplate;

 

(3)编写Service接口以及实现类

Service接口:
import com.shmc.advert.model.po.Advert;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface AdvertService {
    Mono<Advert> saveAdvert(Advert advert);
    Mono<Advert> findById(String id);
    Flux<Advert> findAll();
    Flux<Advert> findByAll();
}
 
Service实现类:
@Service
public class AdvertServiceImpl implements AdvertService {
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    private AdvertRepository advertRepository;
    @Override
    public Mono<Advert> saveAdvert(Advert advert){
        advert.setId(new IdWorker().nextId());
        advert.setCreatData(new Date());
        mongoTemplate.insert(advert);
        return Mono.just(advert);
    }
    @Override
    public Mono<Advert> findById(String id){
        Query query = new Query(Criteria.where("id").is(id));
        return Mono.just(mongoTemplate.findOne(query,Advert.class));
    }
    @Override
    public Flux<Advert> findAll(){
        return advertRepository.findAll();
    }
    @Override
    public Flux<Advert> findByAll(){
        return advertRepository.findBy();
    }
}

(4)编写Controller

import com.shmc.advert.model.po.Advert;
import com.shmc.advert.service.AdvertService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
@RestController
@RequestMapping("/advert")
public class AdvertController {
    @Autowired
    private AdvertService advertService;
    @PostMapping("/saveAdvert")
    public Mono<Advert> saveAdvert(@RequestBody Advert advert){
        return advertService.saveAdvert(advert);
    }
    @GetMapping("/findById/{id}")
    public Mono<Advert> findById(@PathVariable String id){
        return advertService.findById(id);
    }
    /**
     * 以stream+json流的方式推送到客户端
     * @return
     */
    @GetMapping(value = "/findAllPreSec", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
    public Flux<Advert> findAllPreSec() {
        return advertService.findAll().delayElements(Duration.ofSeconds(1));
    }
    /**
     * 数据变更
     * @return
     */
    @GetMapping(value = "/findByAll", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
    public Flux<Advert> findByAll(){
        return advertService.findByAll();
    }
}

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

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

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

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

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

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1天前
|
JSON 前端开发 API
Django API开发实战:前后端分离、Restful风格与DRF序列化器详解
Django API开发实战:前后端分离、Restful风格与DRF序列化器详解
|
1天前
|
JSON Java 程序员
马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day1最快 最全(2)
马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day1最快 最全(2)
7 3
|
1天前
|
缓存 负载均衡 算法
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day3 全网最全(2)
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day3 全网最全(2)
7 1
|
1天前
|
程序员 测试技术 Docker
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day3 全网最全(1)
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day3 全网最全(1)
10 1
|
1天前
|
SQL Java 程序员
马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day1最快 最全(1)
马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day1最快 最全(1)
6 1
|
3天前
|
存储 搜索推荐 Java
微服务SpringCloud ES分布式全文搜索引擎简介 下载安装及简单操作入门
微服务SpringCloud ES分布式全文搜索引擎简介 下载安装及简单操作入门
13 2
|
1天前
|
Java Nacos 微服务
Spring Cloud微服务在Windows本地开发时禁用Nacos注册中心注册
Spring Cloud微服务在Windows本地开发时禁用Nacos注册中心注册
5 0
|
1天前
|
关系型数据库 MySQL Shell
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day2 全网最快最全(下)
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day2 全网最快最全(下)
5 0
|
1天前
|
Java 程序员 Docker
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day2 全网最快最全(上)
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day2 全网最快最全(上)
5 0
|
1天前
|
安全 Java 测试技术
开发Java RESTful Web服务的技巧
开发Java RESTful Web服务的技巧