这是SpringMVC提供的一种技术,可以实现服务端向客户端实时推送数据.用法非常简单,只需要在Controller提供一个接口,创建并返回SseEmitter对象,发送数据可以在另一个接口调用其send方法发送数据.这个SseEmitter对象和DeferredResult有异曲同工之妙,只是SseEmitter可以在一次请求中返回多条数据,而DeferredResult只能返回一条.关于DeferredResult的用法请求参考我的另一篇博客:
https://www.cnblogs.com/jun1019/p/10807055.html
1 import org.slf4j.Logger;
2 import org.slf4j.LoggerFactory;
3 import org.springframework.web.bind.annotation.RequestMapping;
4 import org.springframework.web.bind.annotation.RestController;
5 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
7 import java.io.IOException;
8 import java.util.Map;
9 import java.util.concurrent.ConcurrentHashMap;
11 /**
12 * 服务器端实时推送技术之 SseEmitter 的用法测试
13 * <p>
14 * 测试步骤:
15 * 1.请求http://localhost:8888/sse/start?clientId=111接口,浏览器会阻塞,等待服务器返回结果;
16 * 2.请求http://localhost:8888/sse/send?clientId=111接口,可以请求多次,并观察第1步的浏览器返回结果;
17 * 3.请求http://localhost:8888/sse/end?clientId=111接口结束某个请求,第1步的浏览器将结束阻塞;
18 * 其中clientId代表请求的唯一标志;
19 *
20 * @author syj
21 */
22 @RestController
23 @RequestMapping("/sse")
24 public class SseEmitterController {
25 private static final Logger logger = LoggerFactory.getLogger(SseEmitterController.class);
27 // 用于保存每个请求对应的 SseEmitter
28 private Map<String, Result> sseEmitterMap = new ConcurrentHashMap<>();
30 /**
31 * 返回SseEmitter对象
32 *
33 * @param clientId
34 * @return
35 */
36 @RequestMapping("/start")
37 public SseEmitter testSseEmitter(String clientId) {
38 // 默认30秒超时,设置为0L则永不超时
39 SseEmitter sseEmitter = new SseEmitter(0L);
40 sseEmitterMap.put(clientId, new Result(clientId, System.currentTimeMillis(), sseEmitter));
41 return sseEmitter;
42 }
44 /**
45 * 向SseEmitter对象发送数据
46 *
47 * @param clientId
48 * @return
49 */
50 @RequestMapping("/send")
51 public String setSseEmitter(String clientId) {
52 try {
53 Result result = sseEmitterMap.get(clientId);
54 if (result != null && result.sseEmitter != null) {
55 long timestamp = System.currentTimeMillis();
56 result.sseEmitter.send(timestamp);
57 }
58 } catch (IOException e) {
59 logger.error("IOException!", e);
60 return "error";
61 }
63 return "Succeed!";
64 }
66 /**
67 * 将SseEmitter对象设置成完成
68 *
69 * @param clientId
70 * @return
71 */
72 @RequestMapping("/end")
73 public String completeSseEmitter(String clientId) {
74 Result result = sseEmitterMap.get(clientId);
75 if (result != null) {
76 sseEmitterMap.remove(clientId);
77 result.sseEmitter.complete();
78 }
79 return "Succeed!";
80 }
82 private class Result {
83 public String clientId;
84 public long timestamp;
85 public SseEmitter sseEmitter;
87 public Result(String clientId, long timestamp, SseEmitter sseEmitter) {
88 this.clientId = clientId;
89 this.timestamp = timestamp;
90 this.sseEmitter = sseEmitter;
91 }
92 }
这个技术有什么用呢? 就看你的想象力了, 比如可以用于和进度有关的操作: 安装进度, 部署进度, 任务执行进度等等.