【Java后端向前端推送消息】
1、WebSocketConfig配置类
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.config.annotation.EnableWebSocket;import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration @EnableWebSocket publicclassWebSocketConfig{ @Bean public ServerEndpointExporter serverEndpointExporter(){returnnewServerEndpointExporter();}}2、WebSocket消息发送接收
import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import org.springframework.util.ObjectUtils;import javax.websocket.*;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import java.util.Map;import java.util.Set;import java.util.concurrent.ConcurrentHashMap; @Slf4j @Component @ServerEndpoint(value ="/web/{id}")publicclassWebSocketProcess{/* * 持有每个webSocket对象,以key-value存储到线程安全ConcurrentHashMap, */privatestatic ConcurrentHashMap<Long, WebSocketProcess> concurrentHashMap =newConcurrentHashMap<>(12);/** * 会话对象 **/private Session session;/* * 客户端创建连接时触发 * */ @OnOpen publicvoidonOpen(Session session, @PathParam("id") long id){//每新建立一个连接,就把当前客户id为key,this为value存储到map中this.session = session; concurrentHashMap.put(id,this); log.info("Open a websocket. id={}", id);}/** * 客户端连接关闭时触发 **/ @OnClose publicvoidonClose(Session session, @PathParam("id") long id){//客户端连接关闭时,移除map中存储的键值对 concurrentHashMap.remove(id); log.info("close a websocket, concurrentHashMap remove sessionId= {}", id);}/** * 接收到客户端消息时触发 */ @OnMessage publicvoidonMessage(String message, @PathParam("id") String id){ log.info("receive a message from client id={},msg={}", id, message);}/** * 连接发生异常时候触发 */ @OnError publicvoidonError(Session session, Throwable error){ log.error("Error while websocket. ", error);}/** * 发送消息到指定客户端 * * @param id * @param message */publicvoidsendMessage(long id, String message) throws Exception {//根据id,从map中获取存储的webSocket对象 WebSocketProcess webSocketProcess = concurrentHashMap.get(id);if(!ObjectUtils.isEmpty(webSocketProcess)){//当客户端是Open状态时,才能发送消息if(webSocketProcess.session.isOpen()){ webSocketProcess.session.getBasicRemote().sendText(message);}else{ log.error("websocket session={} is closed ", id);}}else{ log.error("websocket session={} is not exit ", id);}}/** * 发送消息到所有客户端 */publicvoidsendAllMessage(String msg) throws Exception { log.info("online client count={}", concurrentHashMap.size()); Set<Map.Entry<Long, WebSocketProcess>> entries = concurrentHashMap.entrySet();for(Map.Entry<Long, WebSocketProcess> entry : entries){ Long cid = entry.getKey(); WebSocketProcess webSocketProcess = entry.getValue(); boolean sessionOpen = webSocketProcess.session.isOpen();if(sessionOpen){ webSocketProcess.session.getBasicRemote().sendText(msg);}else{ log.info("cid={} is closed,ignore send text", cid);}}}}3、消息推送Controller
import com.xyl.web.controller.common.WebSocketProcess;import com.xyl.web.controller.common.WebSocketServer;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/testws")publicclassWebSocketController{/** * 注入WebSocketProcess **/ @Autowired private WebSocketProcess webSocketProcess;/** * 向指定客户端发消息 * * @param id */ @PostMapping(value ="sendMsgToClientById")publicvoidsendMsgToClientById(@RequestParam long id, @RequestParam String text){try{ webSocketProcess.sendMessage(id, text);}catch(Exception e){ e.printStackTrace();}}/** * 发消息到所有客户端 * * @param text */ @PostMapping(value ="sendMsgToAllClient")publicvoidsendMsgToAllClient(@RequestParam String text){try{ webSocketProcess.sendAllMessage(text);}catch(Exception e){ e.printStackTrace();}}/** * 定时向客户端推送消息 * @throws Exception */ @Scheduled(cron ="0/5 * * * * ?")privatevoidconfigureTasks() throws Exception { webSocketProcess.sendAllMessage("向前端推送消息内容");}}4、测试HTML
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>websocket测试</title><script src="http://code.jquery.com/jquery-2.1.1.min.js"></script></head><body><div id="content"></div></body><script type="text/javascript">$(function(){var ws;//检测浏览器是否支持webSocketif("WebSocket"in window){$("#content").html("您的浏览器支持webSocket!");//模拟产生clientIDlet clientID = Math.ceil(Math.random()*100);//创建 WebSocket 对象,注意请求路径!!!! ws =newWebSocket("ws://127.0.0.1:9095/web/"+clientID);//与服务端建立连接时触发 ws.onopen=function(){$("#content").append("<p>与服务端建立连接建立成功!您的客户端ID="+clientID+"</p>");//模拟发送数据到服务器 ws.send("你好服务端!我是客户端 "+clientID);}//接收到服务端消息时触发 ws.onmessage=function(evt){let received_msg = evt.data;$("#content").append("<p>接收到服务端消息:"+received_msg+"</p>");};//服务端关闭连接时触发 ws.onclose=function(){ console.error("连接已经关闭.....")};}else{$("#content").html("您的浏览器不支持webSocket!");}})</script></html>