服务器端实时推送技术之SseEmitter的用法
这是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; 6 7 import java.io.IOException; 8 import java.util.Map; 9 import java.util.concurrent.ConcurrentHashMap; 10 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); 26 27 // 用于保存每个请求对应的 SseEmitter 28 private Map<String, Result> sseEmitterMap = new ConcurrentHashMap<>(); 29 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 } 43 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 } 62 63 return "Succeed!"; 64 } 65 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 } 81 82 private class Result { 83 public String clientId; 84 public long timestamp; 85 public SseEmitter sseEmitter; 86 87 public Result(String clientId, long timestamp, SseEmitter sseEmitter) { 88 this.clientId = clientId; 89 this.timestamp = timestamp; 90 this.sseEmitter = sseEmitter; 91 } 92 } 93 }
这个技术有什么用呢? 就看你的想象力了, 比如可以用于和进度有关的操作: 安装进度, 部署进度, 任务执行进度等等.