Java后端主动向前端推送消息
后端向前端推送消息就需要长连接,⾸先想到的就是websocket。这⾥推荐⼀个⽐websocket更轻量级的长连接推送实现⽅式:SpringBoot之SseEmitter
contrller:
//@CrossOrigin // 跨域(看具体情况)
@RestController
@RequestMapping("/sse")
public class TestNotify {
/**
* ⽤于创建连接(将⽤户注册到server中)
*/
@GetMapping("/connect/{userId}")
public SseEmitter connect(@PathVariable String userId){
t(userId);
}
@GetMapping("/push/{message}")
public ResponseEntity<String>push(@PathVariable(name ="message") String message){
SseEmitterServer.batchSendMessage(message);
return ResponseEntity.ok("送消息给所有⼈");
}
}
server:
/**
* 主动向前端推送信息
* @Date 2021/4/21
*/
public class SseEmitterServer {
private static final Logger logger = Logger(SseEmitterServer.class);
/**
* 当前连接数
*/
private static AtomicInteger count =new AtomicInteger(0);
/**
* 使⽤map对象,便于根据userId来获取对应的SseEmitter,或者放redis⾥⾯
*/
private static Map<String, SseEmitter> sseEmitterMap =new ConcurrentHashMap<>();
/**
* 创建⽤户连接并返回 SseEmitter
* @param employeeCode ⽤户ID
* @return SseEmitter
*/
public static SseEmitter connect(String employeeCode){
// 设置超时时间,0表⽰不过期。默认30秒,超过时间未完成会抛出异常:AsyncRequestTimeoutException
SseEmitter sseEmitter =new SseEmitter(0L);
// 注册回调
sseEmitterMap.put(employeeCode, sseEmitter);
// 数量+1
logger.info("创建新的sse连接,当前⽤户:{}", employeeCode);
return sseEmitter;
}
/**
* 给指定⽤户发送信息
* @param employeeCode
* @param jsonMsg
*/
public static void sendMessage(String employeeCode, String jsonMsg){
try{
SseEmitter emitter = (employeeCode);
if(emitter == null){
logger.warn("sse⽤户[{}]不在注册表,消息推送失败", employeeCode);
return;
}
emitter.send(jsonMsg, MediaType.APPLICATION_JSON);
}catch(IOException e){
<("sse⽤户[{}]推送异常:{}", employeeCode, e.getMessage());
removeUser(employeeCode);
}
}
/**
* 发消息
* @param jsonMsg
* @param employeeCodes
*/
public static void batchSendMessage(String jsonMsg, List<String> employeeCodes){
employeeCodes.forEach(employeeCode ->sendMessage(jsonMsg, employeeCode)); }
/**
* 发所有⼈
* @param jsonMsg
*/
public static void batchSendMessage(String jsonMsg){
sseEmitterMap.forEach((k, v)->{
try{
v.send(jsonMsg, MediaType.APPLICATION_JSON);
}catch(IOException e){
<("⽤户[{}]推送异常:{}", k, e.getMessage());
removeUser(k);
}
});
}
/**
* 移除⽤户连接
*/
public static void removeUser(String employeeCode){
SseEmitter emitter = (employeeCode);
if(emitter != null){
emitterplete();
}
// 数量-1
logger.info("移除sse⽤户:{}", employeeCode);
}
/**
* 获取当前连接信息
*/
public static List<String>getIds(){
return new ArrayList<>(sseEmitterMap.keySet());
}
/**
* 获取当前连接数量
*/
*/
public static int getUserCount(){
return count.intValue();
}
private static Runnable completionCallBack(String employeeCode){
return()->{
logger.info("结束sse⽤户连接:{}", employeeCode);
removeUser(employeeCode);
};
}
private static Runnable timeoutCallBack(String employeeCode){
return()->{
logger.info("连接sse⽤户超时:{}", employeeCode);
removeUser(employeeCode);
};
}
private static Consumer<Throwable>errorCallBack(String employeeCode){ return throwable ->{
logger.info("sse⽤户连接异常:{}", employeeCode);
removeUser(employeeCode);
};
}
}
html(直接复制保存为html即可使⽤):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SseEmitter</title>
</head>
<body>
<button onclick="closeSse()">关闭连接</button>
<div id="message"></div>
</body>
<script>
let source =null;
// ⽤时间戳模拟登录⽤户
const userId =new Date().getTime();
console.log(userId);
if(!!window.EventSource){
// 建⽴连接
source =new EventSource('localhost:8090/sse/connect/'+ userId);
/**
* 连接⼀旦建⽴,就会触发open事件
* 另⼀种写法:pen = function (event) {}
*/
source.addEventListener('open',function(e){
setMessageInnerHTML("建⽴连接。。。");
},false);
/**
* 客户端收到服务器发来的数据
* 另⼀种写法:ssage = function (event) {}
*/
source.addEventListener('message',function(e){
setMessageInnerHTML(e.data);
});
/**
/**
前端websocket怎么用* 如果发⽣通信错误(⽐如连接中断),就会触发error事件
* 或者:
* 另⼀种写法:r = function (event) {}
*/
source.addEventListener('error',function(e){
adyState === EventSource.CLOSED){
setMessageInnerHTML("连接关闭");
}else{
console.log(e);
}
},false);
}else{
setMessageInnerHTML("你的浏览器不⽀持SSE");
}
// 监听窗⼝关闭事件,主动去关闭sse连接,如果服务端设置永不过期,浏览器关闭后⼿动清理服务端数据 beforeunload=function(){
closeSse();
};
// 关闭Sse连接
function closeSse(){
source.close();
const httpRequest =new XMLHttpRequest();
httpRequest.open('GET','localhost:8090/sse/close/'+ userId,true);
httpRequest.send();
console.log("close");
}
// 将消息显⽰在⽹页上
function setMessageInnerHTML(innerHTML){
}
</script>
</html>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论