catalogue
1. Application scenario of websocket Technology
2. Overview of websocket protocol
3. Difference between full duplex and simplex
4. Push technology and pull technology (understand)
2, SpringBoot uses WebSocket to implement chat room
1. Structure diagram of implementation
1. Create a project and import the coordinates of relevant jar packages
3. Realization of login function
4. Implementation of configuration class
1, websocket Technology
1. Application scenario of websocket Technology
Use java technology to quickly learn a simple online chat room system. The system has strong expansibility. According to business needs, it can make online customer service system, web version of wechat, QQ instant messaging system, etc., use more popular technology and adopt building block programming ideas.
The real-time push technology in the web field is also called Realtime technology. The purpose of this technology is to bypass the user and obtain real-time updates without refreshing the browser. It has a wide range of application prospects, such as online chat room, online customer service system, comment system, WebIM and so on.
2. Overview of websocket protocol
webSocket protocol is a new protocol of HTML5. He realized full duplex communication between browser and server. The initial handshake needs to be completed with the help of HTTP request.
websocket is an Internet technology that realizes the full duplex communication from server to client.
It is a protocol for full duplex communication over a single TCP connection. webSocket communication protocol was defined as standard RFC 6455 by IETF in 2011, and webSocket API was defined as standard by W3c.
3. Difference between full duplex and simplex
- Full duplex: a term for communication transmission. Communication allows data to be transmitted simultaneously in two directions. Its capability is equivalent to the combination of two simplex communication modes. Full duplex refers to the two-way transmission of signals simultaneously (instantaneously) (a - > b, B-A) refers to the simultaneous synchronization of a - > b and B - > a.
- Simplex and half duplex. The so-called half duplex means that only one action occurs in a time period. For example, only one carriage can pass through a narrow road at the same time. When there are two carriages at present, one needs to wait for the other to pass. This example vividly illustrates the principle of half duplex. Early walkie talkies and early hubs were based on half duplex products. With the continuous progress of technology, semi double trade unions gradually withdrew from the historical stage
4. Push technology and pull technology (understand)
- Push technology is a mechanism established on the client server, which is the technology that the server actively sends information to the client, just like broadcasting by a radio station.
- Compared with the traditional pull Pull technology, the main difference is that the push Push technology is the simultaneous interpreting of the information from the server to the client, while the pull PULL technology is the client's active request for information. The advantage of push technology lies in the initiative and timeliness of information.
- In short, compared with the server, the pull technology is to passively provide data to the client, and the push technology is to actively provide data to the client
5. Internet technology
Definition of Internet technology: Internet technology refers to an information technology developed and established on the basis of computer technology; Abbreviation: IT
This technology integrates the scattered resources on the Internet into an organic whole, realizes the comprehensive sharing and organic cooperation of resources, and enables people to use the overall ability of resources transparently and obtain information on demand.
6. Advantages of Wenbsocket
In the past, no matter using HTTP polling or using TCP long connection to make online chat system, it has natural defects. With the development of Html5, there is a new protocol Websocket protocol, which can realize full duplex communication between browser and server. It can do: browser and server only need one handshake, and then, A fast track is formed between the browser and the server. Data can be transmitted between the two. The characteristics of this new protocol are just suitable for this kind of online instant messaging.
Implementation of traditional Http protocol:
The http protocol can request multiple times, because the connection will be closed after each request. The next time you re request data, you need to open the connection again
Traditional Socket technology:
Long connection
Client - connect first - server
Benefits: it can realize two-way communication between client and server
Disadvantages: if everyone doesn't speak, it will cause a waste of resources
Other features include:
(1) Based on TCP protocol, the server-side implementation is relatively easy.
(2) It has good compatibility with HTTP protocol. The default ports are also 80 and 443, and the handshake phase adopts HTTP protocol, so it is not easy to shield the handshake and can pass through various HTTP proxy servers.
(3) The data format is light, the performance overhead is small, and the communication is efficient.
(4) You can send text or binary data.
(5) There is no homology restriction, and the client can communicate with any server.
(6) The protocol identifier is ws (wss if encrypted), and the server URL is the URL.
ws://example.com:80/some/path
2, SpringBoot uses WebSocket to implement chat room
1. Structure diagram of implementation
2. Message format
- Client -------- server
{"toName":"Zhang San","message":"Hello"} toName:To whom message:Message content sent
- Server ----- client
System message format: {"isSystem":true,"fromName":null,"message":["Li Si","Wang Wu"]} isSystem:Is it a system message fromName:Who sent it message: Message content sent Chat message format: {"isSystem":true,"formName:"Zhang San","message":"Hello"}
3. Function realization
1. Create a project and import the coordinates of relevant jar packages
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
2. Create public resources
Message class: used for the webSocket data sent by the browser to the server
package com.pojo; import lombok.Data; //Used to send data from the browser to the server @Data public class Message { private String toName; private String message; }
ResultMessage: used for the server to send the browser's Websocket data
package com.pojo; import lombok.Data; //Websocket data for the server to send the browser @Data public class ResultMessage { private boolean isSystem;//Is it a system message private String fromName; private Object message; //If it is a system message, it is an array }
MessageUtils: tool class used to encapsulate messages
The data needs to be converted into a format recognized by Websocket
package com.utils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.pojo.ResultMessage; //Tool class used to encapsulate messages public class MessageUtils { public static String getMesssge(boolean isSystemMessage,String fromName,Object message){ try { ResultMessage result = new ResultMessage(); result.setSystem(isSystemMessage); result.setMessage(message); if(fromName!=null){ result.setFromName(fromName); } ObjectMapper mapper=new ObjectMapper(); return mapper.writeValueAsString(result); } catch (Exception e) { e.printStackTrace(); } return null; } }
result: data used to log in and respond to the browser
package com.pojo; import lombok.Data; //Data used to respond to the browser after login @Data public class Result { private boolean flag; private String message; }
3. Realization of login function
- login.html: sending requests using asynchrony
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>login</title> <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script> </head> <body> <form id="loginForm"> <input type="text" placeholder="Please enter your name..." name="username"/> <input type="password" name="password"/> <input type="button" id="btn"/> </form> </body> <script> $(function () { $("#btn").click(function () { $.get("login",$("#loginForm").serialize(),function (res) { if (res.flag){ //Jump to main HTML page location.href="main.html"; }else { $("#err_msg").html(res.message); } },"json"); }); }) </script> </html>
- userController: login logic processing
package com.controller; import com.pojo.Result; import com.pojo.User; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; //userController: login logic processing @RestController public class UserController { @RequestMapping("/login") public Result login(User user, HttpSession session){ Result result = new Result(); if(user!=null&&"123".equals(user.getPassword())){ result.setFlag(true); //Save user to session object session.setAttribute("user",user.getUsername()); }else { result.setFlag(false); result.setMessage("Login failed"); } return result; } @RequestMapping("/getUsername") public String getUsername(HttpSession session){ String username = (String) session.getAttribute("user"); return username; } }
- main.html: the page of chat function
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script> </head> <body> <div> <div> <div> <!-- <div id="username"></span></div> User: Zhang San<span style="float: right;color: green">on-line--> <div id="username"></span></div> <div id="chatMes"> <!--And<font face=""Italics">Zhang San</font>chat--> </div> </div> <!--Chat area start--> <div id="pnlBody"> <div id="initBackground" style="background-color: white;width: 100%"> <div id="chatArea" style="display: none"> <div id="show"> <div id="hists"></div> <div id="msgs"> <!--Message display area--> <div class="msg guest"> <div class="msg-right"> <div>Hello</div> </div> </div> <div class="msg robot"> <div class="msg-left"> <div>Hello</div> </div> </div> </div> </div> <div> <div> <textarea id="context_text" wrap="hard" placeholder="Enter text here..."></textarea> <div id="atcomPnl"> <ul id="atcom"></ul> </div> </div> <div id="submit"> send out </div> </div> </div> </div> </div> <!--End of chat area--> <div> <div></div> <div> <div> <div id="hot-tab">Friends list</div> </div> <div> <ul id="userList"> </ul> </div> </div> <div> <div> <div>System broadcast</div> </div> <div> <ul id="broadcastList"> </ul> </div> </div> </div> </div> </div> </body> <script> var username; var toName; function showChat(name) { toName = name; //Now chat dialog $("#chatArea").css("display", "inline"); //Clear chat dialog $("#msgs").html(""); //Show who you are chatting with“ $("#chatMes").html(" chatting with < font face = \ "italics \" > "+ toname +" < font > "); //sessionStorage var chatData= sessionStorage.getItem(toName); if(chatData!=null){ //Render chat records to chat area $("#msgs").html(chatData); } } $(function () { $.ajax({ url: "getUsername", success: function (res) { username = res; //Display online information $("#username").html(" user: "+ res +" < span style ='float: right; color: Green '> online < / span > "); }, async: false //Asynchronous request }); //Create a webSocket object var ws = new WebSocket("ws://192.168.43.24:8080/chat"); //Click time for ws binding ws.onopen = function () { //What needs to be done after the connection is established? //Display online information $("#username").html("User:" + username + "<span style='float:right;color:#008000 '> online < / span > "); } //Triggered after receiving the message pushed by the server ws.onmessage = function (evt) { //Get messages pushed by the server var dataStr = evt.data; //Convert dataStr to Json object var res = JSON.parse(dataStr); console.log(res); console.log(res.message); //Determine whether it is a system message if (res.system) { var names = res.message; //System message //1. Friends list display var userlistStr = ""; var broadcastListStr = ""; for (var name of names) { if (name != username) { userlistStr += "<li class=\"rel-item\"><a onclick='showChat(\"" + name + "\")'>" + name + "</a></li>"; broadcastListStr += "<li class=\"rel-item\" style=\"color:#9d9d9d; Font family: Arial \ "> your friend" + name + "online < / Li >"; } } //Render friend list and system broadcast $("#userList").html(userlistStr); $("#broadcastList").html(broadcastListStr); //2. System broadcast display } else { //Not a system message //Display the messages pushed by the server // var str="<div class='\msg robot\'><div class=\"msg-left\" worker=\"\"><div class =\"msg-host photo\" style='background-image: url(img)'></div>" var str="<h5 style='text-align: left'>"+res.message+"</h5>"; if(toName==res.fromName){ $("#msgs").append(str); } var chatData = sessionStorage.getItem(res.fromName); if (chatData!=null){ str=chatData+str; } sessionStorage.setItem(res.fromName,str); } } ws.onclose = function () { //Display offline information $("#username").html(" user: "+ username +" < span style ='float: right; color: Red '> offline < / span > "); } $("#submit").click(function () { //Get input var data=$("#context_text").val(); //Clear the contents of the input area $("#context_text").val(""); var json={"toName":toName,"message":data}; //Display data in chat area var str="<h5 style='text-align: right'>"+data+"</h5>"; $("#msgs").append(str); //Send message to server var chatData = sessionStorage.getItem(toName); if (chatData!=null){ str=chatData+str; } sessionStorage.setItem(toName,str); ws.send(JSON.stringify(json)); }); }); </script> </html>
- Add a getUsername method in UserController to obtain the currently logged in user name from Session and respond back to the browser
@RequestMapping("/getUsername") public String getUsername(HttpSession session){ String username = (String) session.getAttribute("user"); return username; }
4. Implementation of configuration class
WebSocketConfig: inject a ServerEndpointExporter class object
package com.config; 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 //Inject ServerEndpointExporter bean object and automatically register @ ServerEndPoint public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
5. Build a server class
ChatEndpoint: realize the main functions of chat business
package com.ws; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.pojo.Message; import com.utils.MessageUtils; import org.springframework.stereotype.Component; import javax.servlet.http.HttpSession; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint(value = "/chat", configurator = GetHttpSessionConfigurator.class) @Component //Each client will have a reference to this object, and each object complements each other public class ChatEndpoint { //It is used to store the ChatEndpoint object corresponding to each client object private static Map<String, ChatEndpoint> onlineUsers = new ConcurrentHashMap<>(); //Declare Session capriccio, which can send messages to specified users private Session session; //Declare an HttpSession object. We previously stored the user name in the HttpSession object private HttpSession httpSession; //Called when the connection is established @OnOpen public void onOpen(Session session, EndpointConfig config) { //Assign the local session object to the member variable session this.session = session; //Get httpSession object HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName()); this.httpSession = httpSession; //Stores the current object in a container //Get user name from HttpSession object String username = (String) httpSession.getAttribute("user"); onlineUsers.put(username, this); //Send the user name of the current online user to all clients MessageUtils.getMesssge(true, null, getNames()); //1. Get message String message = MessageUtils.getMesssge(true, null, getNames()); //2. Call methods to push system messages broadcastAllUsers(message); } private Set<String> getNames() { return onlineUsers.keySet(); } private void broadcastAllUsers(String message) { //To push this message to all clients Set<String> names = onlineUsers.keySet(); for (String name : names) { ChatEndpoint chatEndpoint = onlineUsers.get(name); try { chatEndpoint.session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } //Called when data sent by the client is received @OnMessage public void onMessage(String message, Session session) { //Convert message to message object ObjectMapper mapper = new ObjectMapper(); try { Message mess = mapper.readValue(message, Message.class); //Get who to send the data to String toName=mess.getToName(); //Get message data String data=mess.getMessage(); //Get the currently logged in user String username= (String) httpSession.getAttribute("user"); //Gets the data of the message format pushed to the specified user String resultMessage=MessageUtils.getMesssge(false,username,data); //send data onlineUsers.get(toName).session.getBasicRemote().sendText(resultMessage); } catch (Exception e) { e.printStackTrace(); } } @OnClose public void onClose(Session session) { String username= (String) httpSession.getAttribute("user"); //Deletes the specified user from the container onlineUsers.remove(username); //Get the pushed amount message String messsge = MessageUtils.getMesssge(true, null, getNames()); broadcastAllUsers(messsge); } }
6,GetHttpSessionConfigurator
Store the httpSession object in the configuration object
package com.ws; import javax.servlet.http.HttpSession; import javax.websocket.HandshakeResponse; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpointConfig; public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator { @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response){ HttpSession httpSession = (HttpSession) request.getHttpSession(); //Store the httpSession object in the configuration object sec.getUserProperties().put(HttpSession.class.getName(),httpSession); } }