实战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,各位看官如有需要请自行下载。
系列章节目录
推荐阅读
-
实战SpringCloud响应式微服务系列教程(第六章)
-
实战SpringCloud响应式微服务系列教程(第九章)使用Spring WebFlux构建响应式RESTful服务
-
实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例
-
实战SpringCloud响应式微服务系列教程(第一章)
-
实战SpringCloud响应式微服务系列教程(第四章)
-
实战SpringCloud响应式微服务系列教程(第七章)
-
实战SpringCloud响应式微服务系列教程(第八章)构建响应式RESTful服务
-
实战SpringCloud响应式微服务系列教程(第六章)
-
实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例
-
实战SpringCloud响应式微服务系列教程(第四章)