注:源代码来自享学课堂,略有修改,学习之后所做笔记,方便回顾,也给大家一个参考
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();
}
}
}
}
结果:
页面上的金额数字不断发生变化