作者:
瑾年
微信公眾號: Java知音
1.搭建響應(yīng)式RESTful服務(wù)愧膀。
在前面章節(jié)中我們講了如何使用 Spring Initializer初始化響應(yīng)式web應(yīng)用沽讹,本節(jié)中就不再做過多介紹
在學(xué)習(xí)本章內(nèi)容之前需要了解mongodb以及redis,mongodb以及redis可查閱相關(guān)資料進(jìn)行全面了解唉擂,并在本地環(huán)境搭建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
以上配置代碼是我們目前學(xué)習(xí)的響應(yīng)式RESTful服務(wù)的全部配置艳吠,配置比較簡單,spring.data.mongodb.uri: mongodb://localhost:27017/db_advert
和spring.data.redis
是我們服務(wù)的核心配置局骤,我們知道傳統(tǒng)的數(shù)據(jù)庫是不支持響應(yīng)式數(shù)據(jù)讀取的攀圈,所以這里使用mongodb和redis代替。
3.集成響應(yīng)式的MongoDB
springboot 本身提供了cassandra/couchbase/mongodb/redis這幾個NoSQL數(shù)據(jù)庫的響應(yīng)式驅(qū)動:
阻塞式的spring-boot-starter-data-mongodb 改為響應(yīng)式的mongodb依賴spring-boot-starter-data-mongodb-reactive:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
(1)編寫實(shí)體類:
/**
* 廣告投放
*/
@Document(collection="advert")//集合名
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Advert implements Serializable {
private static final long serialVersionUID = -8985545025018238754L;
/**
* 主鍵
*/
@Id
private String id;
/**
* 內(nèi)容
*/
private String content;
/**
* 發(fā)布人
*/
private Long userId;
/**
* 創(chuàng)建時間
*/
private Date creatData;
/**
* 圖片地址
*/
private String imgUrl;
/**
* 視頻地址
*/
private String videoUrl;
/**
* 廣告類型(視頻圖片)
*/
private String advertType;
/**
* 今日投放地區(qū)
*/
private String launchArea;
/**
* 投放時長(小時為單位)
*/
private int durationTime;
/**
* 廣告類型
*/
private int classify;
/**
* 計費(fèi)方式
*/
private int billingMode;
/**
* 展示位置(首頁輪播峦甩,其他輪播赘来,首頁其他位置,其他)
*/
private int displayPosition;
/**
* 廣告主題
*/
private String advertTitle;
/**
* 是否需要自定義展示頁面
*/
private int isCustom;
/**
* 索引關(guān)鍵詞
*/
private String keyWords;
}
其中@document把一個java類聲明為mongodb的文檔,可以通過collection參數(shù)指定這個類對應(yīng)的文檔,標(biāo)注在實(shí)體類上,類似于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的注解嗦篱,這個大家應(yīng)該都很熟悉了不做解釋。
從以上代碼中我們可以清楚看到AdvertRepository 繼承了ReactiveMongoRepository幌缝,ReactiveMongoRepository正是我們依賴的maven響應(yīng)式mongodb-reactive中的類灸促,其中@Tailable注解,該注解類似于Linux中的tail 狮腿,可以將DB的變化以響應(yīng)式流的方式獲取到并推送給前端腿宰。
除了可以繼承ReactiveMongoRepository之外我們還可以通過注入MongoTemplate來操作mongodb,但是MongoTemplate做不到實(shí)時監(jiān)控和主動推送缘厢。如:
@Autowired
MongoTemplate mongoTemplate;
(3)編寫Service接口以及實(shí)現(xiàn)類
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實(shí)現(xiàn)類:
@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));
}
/**
* 數(shù)據(jù)變更
* @return
*/
@GetMapping(value = "/findByAll", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<Advert> findByAll(){
return advertService.findByAll();
}
}
至此基于RESTful的響應(yīng)式服務(wù)我們?nèi)客瓿闪顺远龋瑔映绦蛟L問“/advert/findAllPreSec"接口和”/advert/findByAll“接口就可以看到響應(yīng)式的數(shù)據(jù)推送了。
findAllPreSec這個方法贴硫。使用了delayElements使得每隔一秒鐘獲取一條數(shù)據(jù)發(fā)送給客戶端椿每,以“異步響應(yīng)式流”的方式逐條推送。
這里指定了MediaType是APPLICATION_STREAM_JSON英遭,即application/stream+json格式间护。
在瀏覽器中就可以看到每隔一秒出現(xiàn)一條記錄。運(yùn)行程序挖诸,訪問findByAll接口汁尺,然后測試調(diào)用save接口添加advert數(shù)據(jù),或者直接通過MongoDB Compass客戶端添加Stu數(shù)據(jù)多律,就會看到在頁面中實(shí)時看到新添加的數(shù)據(jù)了痴突。
下一章會吧代碼上傳到gitee,各位看官如有需要請自行下載狼荞。