注:源代碼來自享學課堂,略有修改,學習之後所做筆記,方便回顧,也給大家一個參考
SSE和DeferredResult不同之處在於:
DeferredResult需要頁面重複發送多個請求,來刷新頁面,原理是使用Servlet3的異步任務,有個缺點,下次發送請求的時候,還是會有個時間空格,消息會有一點延遲;SSE是頁面只發送一次請求到服務器,然後服務器自動多次返回結果,服務器發送的數據是一個流數據,不斷髮送,不讓客戶端關閉連接。
SSE更適合金融實時數據。
頁面處理
function showPrice(index,data){
$("#c"+index).html("當前價格:"+data);
var s = $("#s"+index).html();
$("#s"+index).html(s+data+" ");
}
if(!!window.EventSource){//判斷瀏覽器支持度
//拿到sse的對象
var source = new EventSource('needPrice');
//接收到服務器的消息
source.onmessage=function (e) {
var dataObj=e.data;
var arr = dataObj.split(',');
$.each(arr, function (i, item) {
showPrice(i,item);
});
$("#hint").html("");
};
source.onopen=function (e) {
console.log("Connecting server!");
};
source.οnerrοr=function () {
console.log("error");
};
}else{
$("#hint").html("您的瀏覽器不支持SSE!");
}
接口邏輯處理
/*不完美的用法*/
@RequestMapping(value="/needPrice",produces = "text/event-stream;charset=UTF-8")
@ResponseBody
public String push(){
Random r = new Random();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
StringBuilder stringBuilder = new StringBuilder("");
stringBuilder.append("retry:1\n")
.append("data:")
.append((r.nextInt(100)+50)+",")
.append((r.nextInt(80)+45)+",")
.append((r.nextInt(60)+40)+",")
.append((r.nextInt(40)+35))
.append("\n\n");
logger.info("當前股票信息:"+stringBuilder.toString());
return stringBuilder.toString();
}
還可以子服務器自定義一個counter,多少次之後會關閉長鏈接
@RequestMapping(value="needPrice")
@ResponseBody
public void push(HttpServletResponse response){
response.setContentType("text/event-stream");
response.setCharacterEncoding("utf-8");
Random r = new Random();
int sendCount = 0;/*服務器數據發送完*/
try {
PrintWriter pw = response.getWriter();
while(true){
if(pw.checkError()){
System.out.println("客戶端斷開連接");
return;
}
Thread.sleep(1000);
//字符串拼接,使用\n\n代表當前數據包結束,頁面可以處理了
StringBuilder sb = new StringBuilder("");
sb//.append("retry:2000\n")
.append("data:")
.append((r.nextInt(1000)+50)+",")
.append((r.nextInt(800)+100)+",")
.append((r.nextInt(2000)+150)+",")
.append((r.nextInt(1500)+100)+",")
.append("\n\n");
pw.write(sb.toString());
pw.flush();
sendCount++;
if(sendCount>=100){
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
使用spring提供的方法,模擬支付,使用spring提供的SseEmitter
頁面調用支付接口之後,頁面“訂單提交中”->“支付完成”
@Controller
public class SseController {
private static Logger logger = LoggerFactory.getLogger(SseController.class);
private static Map<String,SseEmitter> sseEmitters
= new ConcurrentHashMap<>();
private ExecutorService executorService
= Executors.newFixedThreadPool(2);
@RequestMapping("/weChatPay")
public String stock(){
return "weChatPay";
}
@RequestMapping(value="/payMoney")
@ResponseBody
public SseEmitter pay(String weCharId){
SseEmitter emitter = new SseEmitter();
sseEmitters.put(weCharId,emitter);
executorService.submit(new Pay(weCharId) );
return emitter;
}
private static class Pay implements Runnable{
private String weCharId;
public Pay(String weCharId) {
this.weCharId = weCharId;
}
@Override
public void run() {
SseEmitter sseEmitter = sseEmitters.get(weCharId);
try {
logger.info("聯繫支付服務,準備扣款");
Thread.sleep(500);
sseEmitter.send("支付完成");
logger.info("準備通知自動售貨機");
Thread.sleep(1500);//售貨機的動作
sseEmitter.send("已通知自動售貨機C9出貨,請勿走開!");
sseEmitter.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
結果:
頁面上的金額數字不斷髮生變化