springboot 整合websocket 站内消息 (支持广播式和只给一人发送)单独信息发送 信息群发 统计连接数
线上客户端地址:http://www.niezhiliang.com:8086/index
线上服务端地址:http://www.niezhiliang.com:8086/admin
第一步:
使用org.springframework.web.socket.server.standard.ServerEndpointExporter.ServerEndpointExporter类。在Spring容器中添加一个该类的实例:
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
第二步:
JSR356定义了WebSocket的规范,Tomcat7中实现了该标准。JSR356 的 WebSocket 规范使用 javax.websocket.*的 API,可以将一个普通 Java 对象(POJO)使用 @ServerEndpoint 注释作为 WebSocket 服务器的端点。
package com.suyu.websocket.server; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @ServerEndpoint(value = "/socketServer/{userid}") @Component public class SocketServer { private Session session; private static Map<String,Session> sessionPool = new HashMap<String,Session>(); private static Map<String,String> sessionIds = new HashMap<String,String>(); /** * 用户连接时触发 * @param session * @param userid */ @OnOpen public void open(Session session,@PathParam(value="userid")String userid){ this.session = session; sessionPool.put(userid, session); sessionIds.put(session.getId(), userid); } /** * 收到信息时触发 * @param message */ @OnMessage public void onMessage(String message){ System.out.println("当前发送人sessionid为"+session.getId()+"发送内容为"+message); } /** * 连接关闭触发 */ @OnClose public void onClose(){ sessionPool.remove(sessionIds.get(session.getId())); sessionIds.remove(session.getId()); } /** * 发生错误时触发 * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { error.printStackTrace(); } /** *信息发送的方法 * @param message * @param userId */ public static void sendMessage(String message,String userId){ Session s = sessionPool.get(userId); if(s!=null){ try { s.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } /** * 获取当前连接数 * @return */ public static int getOnlineNum(){ return sessionPool.size(); } /** * 获取在线用户名以逗号隔开 * @return */ public static String getOnlineUsers(){ StringBuffer users = new StringBuffer(); for (String key : sessionIds.keySet()) { users.append(sessionIds.get(key)+","); } return users.toString(); } /** * 信息群发 * @param msg */ public static void sendAll(String msg) { for (String key : sessionIds.keySet()) { sendMessage(msg, sessionIds.get(key)); } } /** * 多个人发送给指定的几个用户 * @param msg * @param persons 用户s */ public static void SendMany(String msg,String [] persons) { for (String userid : persons) { sendMessage(msg, userid); } } }
第三步::编辑Controller
package com.suyu.websocket.controller; import com.suyu.websocket.server.SocketServer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; /** * websocket * 消息推送(个人和广播) */ @Controller public class WebSocketController { @Autowired private SocketServer socketServer; @RequestMapping(value = "/index") public String idnex() { return "index"; } @RequestMapping(value = "/admin") public String admin(Model model) { int num = socketServer.getOnlineNum(); String str = socketServer.getOnlineUsers(); model.addAttribute("num",num); model.addAttribute("users",str); return "admin"; } /** * 个人信息推送 * @return */ @RequestMapping("sendmsg") @ResponseBody public String sendmsg(String msg,String username){ //第一个参数 :msg 发送的信息内容 //第二个参数为用户长连接传的用户人数 String [] persons = username.split(","); SocketServer.SendMany(msg,persons); return "success"; } /** * 推送给所有在线用户 * @return */ @RequestMapping("sendAll") @ResponseBody public String sendAll(String msg){ SocketServer.sendAll(msg); return "success"; } /** * 获取当前在线用户 * @return */ @RequestMapping("webstatus") public String webstatus(){ //当前用户个数 int count = SocketServer.getOnlineNum(); //当年用户的username SocketServer.getOnlineUsers(); return "tongji"; } }
第四步:编写客户端页面,由于框架使用的是springboot,所以用了thymeleaf模板
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>客户端首页</title> <script th:src="@{../jquery.min.js}"></script> </head> <body> 请输入您的昵称<input type="text" id="username"/> <input type="button" value="连接" onclick="connect()"/> <br/> 请填写要发送的内容<input type="text" id="writeMsg"/> <input type="button" value="发送" onclick="sendMsg()"/> <script type="text/javascript"> var ws = null; var username = $("#username").val() function connect(){ if(username!=null){ if ('WebSocket' in window){ ws = new WebSocket("ws://localhost:8080/socketServer/"+$("#username").val()); } else if ('MozWebSocket' in window){ ws = new MozWebSocket("ws://localhost:8080/socketServer/"+$("#username").val()); } else{ alert("该浏览器不支持websocket"); } ws.onmessage = function(evt) { alert(evt.data); }; ws.onclose = function(evt) { alert("连接中断"); }; ws.onopen = function(evt) { alert("连接成功"); }; }else{ alert("请输入您的昵称"); } } function sendMsg() { ws.send($("#writeMsg").val()); } </script> </body> </html>
然后编写服务端发送信息的页面
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>统计</title> <script th:src="@{/jquery.min.js}"></script> </head> <body> 当前在线人数总计<div id="sum" th:text="${num}" ></div> <br/> 具体人员为:<div id="users" th:text="${users}"></div> <br/> 发送消息:请输入推送内容<input type="text" id="msg"/> <br/> 请输入发送人昵称<input type="text" id="username"/> <span>(如果发送多个用户,用户昵称之间用逗号隔开)</span> <br/> <input type="button" value="发送" onclick="sendMsg()"/> <br/> <input type="button" value="全部发送" onclick="sendAll()"/> <script type="text/javascript"> function sendMsg(){ var user = $("#username").val(); var msg = $("#msg").val(); if(msg!=null){ $.ajax({ method: 'get', url: '/sendmsg', data:{ username: user, msg:msg }, success:function(data) { console.log(data); } }) }else{ alert("请填写要发送的用户昵称或者发送内容"); } } function sendAll(){ var msg = $("#msg").val(); if(msg!=null){ $.ajax({ method: 'get', url: '/sendAll', data:{ msg:msg }, success:function(data) { console.log(data); } }) }else{ alert("请填写要发送的内容"); } } </script> </body> </html>
效果图
项目源码:https://github.com/niezhiliang/springbootwebsocket