SSE 的使用方法可以参考:https://blog.csdn.net/xiewz1112/article/details/80591898
EventSource 对象的 API 文档地址:https://developer.mozilla.org/en-US/docs/Web/API/EventSource
SSE 的使用示例(主要代码来自《Java EE 开发的颠覆者 Spring Boot 实战》一书的 4.5.3 部分)
1. 页面sse.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SSE Demo</title>
</head>
<body>
<div id="msgFromPush"></div>
<script type="text/javascript" src="<%=request.getContextPath()%>/assets/js/jquery-2.2.4.min.js"></script>
<script type="text/javascript">
if (window.EventSource) {
console.log("该浏览器支持SSE");
var source = new EventSource("ssePush");
var s = "";
source.addEventListener("open", function(e) {
console.log("连接打开");
}, false);
source.addEventListener("message", function(e) {
console.log("message: data=" + e.data + ", lastEventId=" + e.lastEventId);
s += e.data + "<br>";
$("#msgFromPush").html(s);
if (e.data == "-1") {
source.close();
}
});
source.addEventListener("error", function(e) {
if (e.readyState == EventSource.CLOSED) {
console.log("连接关闭");
} else {
console.log(e.readyState);
}
}, false);
} else {
console.log("该浏览器不支持SSE");
}
</script>
</body>
</html>
2. SseData.java
package com.wisely.highlight_springmvc4.entity;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
public class SseData {
private static final String CR = "\n";
private String data = "";// 表示数据内容。属性来自于MessageEvent
private String event = "message";// 自定义的事件类型,默认是message事件。
private String id;// 数据标识符用id字段表示,相当于每一条数据的编号。属性来自于MessageEvent
private long retry;// 指定浏览器重新发起连接的时间间隔。单位:ms
private List<String> comments = Lists.newArrayList();
public static class SseDataBuilder {
private SseData sseData;
private SseDataBuilder() {
this.sseData = new SseData();
}
public static SseDataBuilder builder() {
return new SseDataBuilder();
}
public SseData build() {
return this.sseData;
}
public SseDataBuilder setData(String data) {
Preconditions.checkNotNull(data);
this.sseData.setData(data);
return this;
}
public SseDataBuilder setEvent(String event) {
Preconditions.checkNotNull(event);
this.sseData.setEvent(event);
return this;
}
public SseDataBuilder setId(String id) {
Preconditions.checkNotNull(id);
this.sseData.setId(id);
return this;
}
public SseDataBuilder setRetry(long retry) {
Preconditions.checkArgument(retry > 0L, "retry must be greater than 0");
this.sseData.setRetry(retry);
return this;
}
public SseDataBuilder setComments(String... comments) {
Preconditions.checkArgument(comments != null && comments.length > 0, "comments must not be empty");
this.sseData.setComments(Arrays.asList(comments));
return this;
}
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public long getRetry() {
return retry;
}
public void setRetry(long retry) {
this.retry = retry;
}
public List<String> getComments() {
return comments;
}
public void setComments(List<String> comments) {
this.comments = comments;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
if (CollectionUtils.isNotEmpty(comments)) {
for (String comment : comments) {
if (comment != null) {
builder.append(':').append(comment).append(CR);
}
}
}
builder.append("event:").append(StringUtils.defaultString(event, "message")).append(CR);
if (id != null) {
builder.append("id:").append(id).append(CR);
}
if (retry > 0L) {
builder.append("retry:").append(retry).append(CR);
}
builder.append("data:").append(Strings.nullToEmpty(data)).append(CR).append(CR);
return builder.toString();
}
}
3. SseController.java
package com.wisely.highlight_springmvc4.ch4_5;
import java.util.Date;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.wisely.highlight_springmvc4.entity.SseData.SseDataBuilder;
@Controller
public class SseController {
@RequestMapping(value="/ssePush", produces="text/event-stream")
@ResponseBody
public String push() {
try {
// 休眠2秒模拟处理过程
Thread.sleep(2000L);
} catch (Exception e) {
// not handler
}
int num = RandomUtils.nextInt(1, 11);
if (num % 10 == 0) {// 结束
return SseDataBuilder.builder()
.setComments("over")
.setData("-1")
.build()
.toString();
} else {
return SseDataBuilder.builder()
.setComments("comment " + num)
.setId(String.valueOf(num))
.setRetry(2000L)
.setData("ssePush value[" + num + "] to browser at " + FastDateFormat.getInstance("HH:mm:ss").format(new Date()))
.build().toString();
}
}
}
4. 浏览器 Console 控制台效果
5. 项目日志