序文
参加この世界からwebfluxのspring5メッセージはまた、企業の何人かの友人がwebfuxを使用しているが、それらのほとんどが使用するように制御サーバ間の通信経路の一部として使用されているが、本当のように彼を扱う見つけ、いくつかの時間のためにされていますWebサービスとフロントエンドAPIと木材に提供します。私は早くbigpipe確率を接触させたが、いないかのjavaの地域に住むことに応答して単一のデータストリームは、それが似ているようですか?だから私たちは議論を共有するwebfluxとフロントエンド統合を研究しました...
WebFlux
WebFluxモジュール名は、反応器内のフラックスフラックスのクラス名に由来するばねwebflux、です。春は非同期を構築するために使用することができ、新たな非目詰まり官能性反応性Webフレームワーク、非ブロッキング、イベント駆動型のサービスがあるwebflux、パフォーマンスの面で柔軟性が非常に良いです。
実際の効果のショー
最初の場所:
プッシュSSEのAPIは、サーバーへの一方向の接続を作成するために使用される、サーバーから(HTML5)ページが更新されたことができ、サーバはこの接続を介してデータの任意の数を送信することが可能です。サーバの応答のMIMEタイプはtext /イベント・ストリームでなければならない、とブラウザのJavaScript API形式の出力を解決することができます。SSEは、短いポーリング、ポーリングとHTTPストリーミング長さをサポートし、自動的に切断された再接続を決定することができます。
Javaコード:
@RestController
@RequestMapping("/sse")
public class SseController {
private int count_down_sec=3*60*60;
@GetMapping(value="/countDown",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<Object>> countDown() {
return Flux.interval(Duration.ofSeconds(1))
.map(seq -> Tuples.of(seq, getCountDownSec()))
.map(data -> ServerSentEvent.<Object>builder()
.event("countDown")
.id(Long.toString(data.getT1()))
.data(data.getT2().toString())
.build());
}
private String getCountDownSec() {
if (count_down_sec>0) {
int h = count_down_sec/(60*60);
int m = (count_down_sec%(60*60))/60;
int s = (count_down_sec%(60*60))%60;
count_down_sec--;
return "活动倒计时:"+h+" 小时 "+m+" 分钟 "+s+" 秒";
}
return "活动倒计时:0 小时 0 分钟 0 秒";
}
}
HTMLコード:
//js代码
<script>
//记录加载次数
var time=1;
if (typeof (EventSource) !== "undefined") {
var source = new EventSource("/sse/countDown");
console.log(source);
source.addEventListener("countDown", function(e) {
document.getElementById("result").innerHTML = e.data;
}, false);//使用false表示在冒泡阶段处理事件,而不是捕获阶段。
} else {
document.getElementById("result").innerHTML = "抱歉,你的浏览器不支持 server-sent 事件...";
}
</script>
//html代码
<div id="result"></div><br/>
SSEでwebfluxは、新しいものではありません以上を導入していない、前に登場しています。
第二は、フラックスwebfluxインタフェースの3の情報であります
Javaコード(主にモンゴ用)
エンティティ:
@Data
@EqualsAndHashCode(callSuper=false)
public class Commodity extends ParentEntity implements Serializable{
private static final long serialVersionUID = 6659341305838439447L;
/**
* 店铺ID
*/
private Long shopId;
/**
* 商品名
*/
@NotNull(message = "商品名不能为空")
@Pattern(regexp = "^.{0,50}$",message = "商品名必须是小于50位字符串")
private String name;
/**
* 商品详情
*/
@Pattern(regexp = "^.{0,500}$",message = "商品详情必须是小于500位字符串")
private String details;
/**
* 商品图片地址
*/
private String imageUrl;
/**
* 商品图片地址
*/
private Integer type;
/**
* 商品单价
*/
@Min(value = 0)
private BigDecimal price;
/**
* 商品库存
*/
@Min(value = 0)
private Integer pcs;
}
親クラスのエンティティ:
public class ParentEntity {
/**
* 商品ID
*/
public Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
DAO:
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import com.flying.cattle.wf.entity.Commodity;
public interface CommodityRepository extends ReactiveMongoRepository<Commodity, Long>{
}
サービス:
import com.flying.cattle.wf.aid.IService;
import com.flying.cattle.wf.entity.Commodity;
public interface CommodityService extends IService<Commodity>{
}
SERVICEの親クラス:
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* <p>
* 顶级 Service
* </p>
*
* @author BianPeng
* @since 2019/6/17
*/
public interface IService<T> {
/**
* <p>
* 插入一条记录(选择字段,策略插入)
* </p>
*
* @param entity 实体对象
*/
Mono<T> insert(T entity);
/**
* <p>
* 根据 ID 删除
* </p>
* @param id 主键ID
*/
Mono<Void> deleteById(Long id);
/**
* <p>
* 根据 ID 删除
* </p>
* @param id 主键ID
*/
Mono<Void> delete(T entity);
/**
* <p>
* 根据 ID 选择修改
* </p>
* @param entity 实体对象
*/
Mono<T> updateById(T entity);
/**
* <p>
* 根据 ID 查询
* </p>
* @param id 主键ID
*/
Mono<T> findById(Long id);
/**
* <p>
* 查询所有
* </p>
*/
Flux<T> findAll();
}
SERVICE-IMPL
import org.springframework.stereotype.Service;
import com.flying.cattle.wf.aid.ServiceImpl;
import com.flying.cattle.wf.dao.CommodityRepository;
import com.flying.cattle.wf.entity.Commodity;
import com.flying.cattle.wf.service.CommodityService;
@Service
public class CommodityServiceImpl extends ServiceImpl<CommodityRepository, Commodity> implements CommodityService {
}
SERVICE-IMPL親クラス:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* <p>
* IService 实现类( 泛型:M 是 mapper 对象,T 是实体 , PK 是主键泛型 )
* </p>
*
* @author BianPeng
* @since 2019/6/17
*/
public class ServiceImpl<M extends ReactiveMongoRepository<T,Long>, T> implements IService<T> {
@Autowired
protected M baseDao;
@Override
public Mono<T> insert(T entity) {
return baseDao.save(entity);
}
@Override
public Mono<Void> deleteById(Long id) {
// TODO Auto-generated method stub
return baseDao.deleteById(id);
}
@Override
public Mono<Void> delete(T entity) {
// TODO Auto-generated method stub
return baseDao.delete(entity);
}
@Override
public Mono<T> updateById(T entity) {
// TODO Auto-generated method stub
return baseDao.save(entity);
}
@Override
public Mono<T> findById(Long id) {
// TODO Auto-generated method stub
return baseDao.findById(id);
}
@Override
public Flux<T> findAll() {
// TODO Auto-generated method stub
return baseDao.findAll();
}
}
コントローラ:
import java.math.BigDecimal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.flying.cattle.wf.aid.AbstractController;
import com.flying.cattle.wf.entity.Commodity;
import com.flying.cattle.wf.service.CommodityService;
import com.flying.cattle.wf.utils.ValidationResult;
import com.flying.cattle.wf.utils.ValidationUtils;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/commodity")
public class CommodityController extends AbstractController<CommodityService, Commodity> {
Logger logger = LoggerFactory.getLogger(this.getClass());
@GetMapping("/add")
public Mono<Commodity> add() throws Exception {
Commodity obj = new Commodity();
Long id=super.getAutoIncrementId(obj);
obj.setId(id);
obj.setShopId(1l);
obj.setName("第" + id + "个商品");
obj.setDetails("流式商品展示");
obj.setImageUrl("/aa/aa.png");
obj.setPcs(1);
obj.setPrice(new BigDecimal(998));
obj.setType(1);
ValidationResult vr = ValidationUtils.validateEntity(obj);
if (!vr.isHasErrors()) {
return baseService.insert(obj);
} else {
throw new Exception(vr.getFirstErrors());
}
}
}
CONTROLLERの親クラス:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import com.flying.cattle.wf.entity.ParentEntity;
import com.flying.cattle.wf.service.impl.RedisGenerateId;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* <p>自动生成工具:mybatis-dsc-generator</p>
*
* <p>说明: 资金归集API接口层</P>
* @version: V1.0
* @author: BianPeng
*
*/
public class AbstractController<S extends IService<T>,T extends ParentEntity>{
@Autowired
private RedisGenerateId redisGenerateId;
@Autowired
protected S baseService;
@GetMapping("/getId")
public Long getAutoIncrementId(T entity){
return redisGenerateId.generate(entity.getClass().getName());
}
@PostMapping("/save")
public Mono<T> save(T entity) {
entity.setId(getAutoIncrementId(entity));
return baseService.insert(entity);
}
@PostMapping("/deleteById")
public Mono<String> deleteById(Long id) {
// TODO Auto-generated method stub
return baseService.deleteById(id)
.then(Mono.just("ok"))
.defaultIfEmpty("not found");
}
@PostMapping("/delete")
public Mono<String> delete(T entity) {
// TODO Auto-generated method stub
return baseService.delete(entity)
.then(Mono.just("ok"))
.defaultIfEmpty("not found");
}
@PostMapping("/updateById")
public Mono<T> updateById(T entity) {
// TODO Auto-generated method stub
return baseService.updateById(entity);
}
@GetMapping("/getById/{id}")
public Mono<T> findById(@PathVariable("id") Long id) {
// TODO Auto-generated method stub
return baseService.findById(id);
}
@GetMapping(value="/findAll",produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<T> findAll() {
// TODO Auto-generated method stub
return baseService.findAll();
}
}
HTMLコード:
<html>
<head>
<meta charset="UTF-8">
<title>商品展示</title>
<script src="/js/jquery-2.1.1.min.js"></script>
<script>
//记录加载次数
var time=1;
if (typeof (EventSource) !== "undefined") {
var source = new EventSource("/sse/countDown");
console.log(source);
source.addEventListener("countDown", function(e) {
document.getElementById("result").innerHTML = e.data;
}, false);//使用false表示在冒泡阶段处理事件,而不是捕获阶段。
} else {
document.getElementById("result").innerHTML = "抱歉,你的浏览器不支持 server-sent 事件...";
}
/************************以上是SSE的JS************************/
$(function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/commodity/findAll');
xhr.send(null);//发送请求
xhr.onreadystatechange = function() {
//2是空响应,3是响应一部分,4是响应完成
if (xhr.readyState > 2) {
//这儿可以使用response与responseText,因为我接口返回的就是String数据,所以选择responseText
var newData = xhr.response.substr(xhr.seenBytes);
newData = newData.replace(/\n/g, "#");
newData = newData.substring(0, newData.length - 1);
var data = newData.split("#");
//显示加载次数,和大小
$("#dataModule").append("第"+time+"次数据响应"+data.length+"条 ");
$("#note").append("<div style='clear: both;'>第"+time+"次数据响应"+data.length+"条</div><div id='note"+time+"' style='width: 100%;'></div>");
var html="";
for (var i = 0; i < data.length; i++) {
var obj = JSON.parse(data[i])
html=html + "<div style='margin-left: 10px;margin-top: 10px; width: 80px;height: 80px;background-color: gray;float: left;'>"+obj.name+"</div>";
}
$("#note"+time).html(html);
time++;
xhr.seenBytes = xhr.response.length;
}
}
})
</script>
</head>
<body>
<div id="result"></div><br/>
<div id="dataModule"></div><br/>
<div id="note" style="width: 100%;" >
</div>
</body>
</html>
その画像を表示し始めているデータのうち、このようなフロントエンドのコードは、データが表示データのみを受信した後、界面反応が完了したので、データを待たずに、すぐにどのように多くのフロントエンドの表示データを反映しています。、340697945のみんなの交流をお互いから学ぶ:今webflux使用は実際にはあまり普及していない、私は自分のニーズを掘っていた多くのことは、興味のある友人は、グループを追加することができます。
問題が発生しました:
serviceImplデータの変更は、コードを実行されていません。
@Override
public Mono<Boolean> deleteById(Long id) {
// TODO Auto-generated method stub
baseDao.deleteById(id);
return Mono.create(entityMonoSink -> entityMonoSink.success());
}
制御コードは、(除去が、ソースコード内のメソッドである場合)に実行されていません
@PostMapping("/deleteById")
public Mono<Boolean> deleteById(Long id) {
// TODO Auto-generated method stub
baseService.deleteById(id)
return Mono.create(entityMonoSink -> entityMonoSink.success());
}
私が実行され、見つかった場合はデータを削除しますが、エラーはありません。最後に限り、コントローラは(例えばbaseDao.deleteById(ID)またはbaseDao.save(エンティティ)など)ReactiveMongoRepository方法の結果で直接返さなかったとして、データの変更が成功していない、なぜ知らないことがわかった....