参考资料-后端:https://developer.ibm.com/zh/articles/j-lo-WebSocket/
参考资料-前端:https://www.runoob.com/html/html5-websocket.html
在线测试-地址:http://www.websocket-test.com/
1. 简介
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
经典对比图示:
效果图:
2. 服务端实现
2.1 依赖 jar
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
|
2.2 配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration public class WebSocketConfig {
@Bean public ServerEndpointExporter createSEE() { return new ServerEndpointExporter(); } }
|
2.3 服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| import org.springframework.context.annotation.Scope; 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.concurrent.ConcurrentHashMap;
@Component @Scope(scopeName = "prototype") @ServerEndpoint("/chatserver/{nickname}") public class ChatServer {
private String nickname;
private Session session; public static ConcurrentHashMap<String, ChatServer> clients;
static { clients = new ConcurrentHashMap<>(); }
@OnOpen public void open(@PathParam("nickname") String name, Session session) throws IOException { if (clients.containsKey(name)) { session.getBasicRemote().sendText("亲,昵称与存在,请重新命名"); } else { clients.put(name, this); nickname = name; this.session = session; sendAlMsg("欢迎-" + name + "- 加入聊天室,鲜花走起来!", true); } }
@OnMessage public void message(String msg) { System.err.println(nickname + "----->" + msg); sendAlMsg(msg, false); }
@OnError public void error(Throwable error) { error.printStackTrace(); }
@OnClose public void close(Session session) throws IOException { clients.remove(nickname); sendAlMsg(nickname + "-离开了聊天室,他错失了100万", true); session.close(); }
private void sendAlMsg(String msg, boolean isself) { for (String s : clients.keySet()) { if (!isself) { if (s.equals(nickname)) { continue; } } try { clients.get(s).session.getBasicRemote().sendText(msg); } catch (IOException e) { e.printStackTrace(); } } } }
|
3. 前端实现
核心:
- ws =
new WebSocket("ws://ip:port/chatserver/" + name)
; 创建 webSocket 连接
- style=”
scroll-snap-type-y: unset;
“ 界面滚动样式
- ws.onopen / ws.onmessage / ws.send / ws.close 相关事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>WebSocket 聊天室实战 Jerry</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <script type="application/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/1.10.0/jquery.js"></script>
<style type="text/css"> div { text-align: center; } .inputmsg { padding: 5px; border-radius: 10px; width: 60%; } .dvleft { float: left; text-align: left; margin-left: 10px; width: 100%; } .dvright { float: right; width: 100%; text-align: right; margin-right: 10px; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col"> <input class="inputmsg" id="nickname" style="width: 30%;" /> <button class="btn btn-primary" id="btnjoin">加入聊天室</button> <button class="btn btn-primary" id="btnexit" disabled>退出聊天室</button> </div> </div> <div class="row" id="dvchat" style="scroll-snap-type-y: unset;margin-top: 10px;border: 1px solid red;height: 600px;">
<p class="dvleft">哈哈哈哈</p> <p class="dvright">哦的</p> </div> <div class="row" style="position: absolute;bottom: 10px; width: 100%;"> <div class="col-sm-offset-1 col-sm-10"> <input class="inputmsg" id="chatmsg" /> <button class="btn btn-primary" id="btnsend">发送消息</button> </div> </div> </div> <script type="application/javascript"> var ws; $(function() { $("#btnjoin").click(function() { var n = $("#nickname").val(); if (n) { ws = new WebSocket("ws://localhost:8085/chatserver/" + n); ws.onopen = function() { $("#btnjoin").attr("disabled", ""); $("#btnexit").removeAttr("disabled"); } ws.onmessage = function(evt) { receiveMsg(evt); }; ws.onclose = function() { alert("连接已关闭..."); window.close(); };
} else { alert("亲,请输入昵称"); } }) $("#btnsend").click(function() { sendMsg(); }); $("#btnexit").click(function() { ws.close(); }) })
function sendMsg() { var m = $("#chatmsg").val(); if (m) { ws.send(m); $("#dvchat").append("<p class=\"dvright\">" + m + "</p>"); $("#chatmsg").val(""); } else { alert("请输入聊天消息"); } }; function receiveMsg(evt) { var rmsg = evt.data; $("#dvchat").append("<p class=\"dvleft\">" + rmsg + "</p>"); } </script> </body> </html>
|
4. 在线测试
在线测试-地址:http://www.websocket-test.com/
接口地址:ws://192.168.31.244:8085/chatserver/jerry
1 2 3 4 5
| @ServerEndpoint("/chatserver/{nickname}") public class ChatServer { ... }
|