Article directory:
2.1 relevant annotations and API methods in websocket development
2.2 front end technology support for WebSocket
3. Implementation source code of multi person chat room
3.1 add related dependencies to POM file
2.2 configure the view parser in the core configuration file
2.3 add relevant static resource files
2.4 write control layer controller
2.5 write a configuration class to enable SpringBoot's support for WebSocket
1. What is WebSocket?
WebSocket protocol is a network protocol defined by HTML5 and implemented based on TCP protocol. Through this protocol, the server can actively send information to the client;
WebSocket protocol was born in 2008 and became the W3C international standard in 2011;
We already have HTTP protocol. Why is there a websocket protocol?
http protocol is a short connection, because after the request, the connection will be closed. The next time you re request data, you need to open the link again;
WebSocket protocol is a long connection, which only needs one request to initialize the connection, and then all requests and responses communicate through this TCP connection;
Therefore, the HTTP protocol communication can only be that the client sends a request to the server, and the server returns the response result. The HTTP protocol can not make the server actively push information to the client, but websocket can realize the full duplex communication between the server and the client;
What is full duplex
Information can only be transmitted in one direction as simplex; If information can be transmitted in both directions but cannot be transmitted in both directions at the same time, it is called half duplex, and if information can be transmitted in both directions at the same time, it is called full duplex;
Basic implementation principle
WebSocket protocol is implemented based on TCP protocol. After the client and server only need to make a handshake, a fast channel between the client and server is formed. After that, multiple two-way transmission of data frames can be carried out between the client and the server;
The purpose of this implementation is that when the client and the server communicate frequently, the server can avoid frequently creating HTTP connections, save resources, and improve work efficiency and resource utilization;
Implementation of traditional Web push
How does the server push messages to the browser before there is no WebSocket protocol?
At this time, the usual implementation method is to periodically poll the page through Ajax, such as sending an HTTP request to the server every 1 second, asking the server whether there is a new message, and the server returns the result;
The disadvantages of this form are obvious. The browser needs to constantly send HTTP requests to the server, and HTTP requests contain long headers and relatively few effective information. Repeated invalid requests occupy a lot of bandwidth and CPU resources, resulting in a great waste. Therefore, WebSocket should be born;
WebSocket protocol defined in HTML5 can better save server resources and bandwidth, and can communicate in real time;
WebSocket protocol is essentially a TCP based protocol, so it has nothing to do with HTTP protocol;
Characteristics of WebSocket
Full duplex communication, client and server can communicate equally in both directions;
Based on TCP protocol, the implementation of server-side is relatively easy;
The data format is light, the performance overhead is small, and the communication is efficient;
You can send text or binary data;
Communication has stronger real-time performance;
The protocol identifier is WS. For example, the server address is ws://www.abc.com com/some/path
The address of HTTP protocol is: http://......
websocket business scenario
WebSocket chat room;
Real time stock price display and other applications;
Instant messaging, games, visual large screen display and other fields;
Enterprise internal management communication and other functions, the main communication protocol is websocket;
Implementation of web chat and customer service system;
System reminder, user online and offline reminder, client synchronization, real-time data update, multi screen synchronization, user online status, message notification, scanning QR code login / QR code payment, bullet screen, various information reminders, online seat selection, real-time monitoring of large screen, etc;
2. WebSocket API in Java
In Java EE 7, the Java language begins to support websocket protocol. Java EE 7 defines a set of Websocket API specifications, that is, a series of interfaces, which are not implemented and are located in the package javax Websocket includes client-side API and server-side API. The Java API of websocket is only a specification. The specific implementation needs to be provided by web container (for example, tomcat implements Java websocket api), Java EE server or framework;
javax.websocket | This package contains all the WebSocket APIs common to both the client and server side. |
javax.websocket.server | This package contains all the WebSocket APIs used only by server side applications. |
1. Tomcat: the implementation of websocket in java, which requires tomcat 7.0.47 + or above to support Java EE7;
2. Spring websocket requires spring 4 x. So spring boot can also be used;
2.1 relevant annotations and API methods in websocket development
@ServerEndpoint("/websocket/{uid}")
Declare that this is a websocket service;
You need to specify the address to access the service. You can specify parameters in the address, which needs to be occupied through {};
@OnOpen
Usage: public void onOpen(Session session, @PathParam("uid") String uid) throws IOException {}
This method will be executed after the connection is established, and the session object will be passed in, that is, the long connection channel established between the client and the server, and the parameters declared in the url will be obtained through @ PathParam;
@OnClose
Usage: public void onClose() {}
The method is executed after the connection is closed;
@OnMessage
Usage: public void onmessage (string message, session) throws IOException {}
The method is used to receive the message sent by the client;
Message: message data sent;
Session: session object (also a long connection channel);
Send a message to the client;
Usage: session getBasicRemote(). sendText("hello,websocket.");
Send messages through session;
2.2 front end technology support for WebSocket
Websocket is an html5 specification, which is supported by mainstream browsers; (not supported by some older browsers)
jQuery, vueJS, React {JS, angularjs, etc. can support websocket objects;
The bottom layer is a js object of websocket supported by javascript. The connection of websocket can be established through this object: ws://localhost:8080/websocket/12345
3. Implementation source code of multi person chat room
3.1 add related dependencies to POM file
<dependencies> <!-- SpringBoot frame web Project start dependence --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringBoot frame websocket Start dependence --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <!-- SpringBoot Frame infill Tomcat yes jsp Resolution dependency of --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <!-- lombok rely on --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> </dependencies> <build> <!-- SpringBoot Framework compilation and packaging plug-in --> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <!-- src/main/webapp Lower jsp Page compilation to META-INF/resources Can't access until --> <resources> <resource> <directory>src/main/webapp</directory> <targetPath>META-INF/resources</targetPath> <includes> <include>*.*</include> </includes> </resource> </resources> </build>
2.2 configure the view parser in the core configuration file
#Configure view parser spring.mvc.view.prefix=/ spring.mvc.view.suffix=.jsp
2.3 add relevant static resource files
2.4 write control layer controller
There is only one request, / chat, which will jump to our index JSP page.
package com.szh.springboot.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import java.util.concurrent.atomic.AtomicInteger; /** * */ @Controller public class ChatController { //Declare atomic variable classes to ensure the atomicity and visibility of operations between the server and the client private AtomicInteger atomicInteger=new AtomicInteger(); @RequestMapping("/chat") public String chat(Model model) { model.addAttribute("username","user" + atomicInteger.getAndIncrement()); return "index"; } }
2.5 write a configuration class to enable SpringBoot's support for WebSocket
package com.szh.springboot.config; 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; /** * */ @EnableWebSocket //Enable SpringBoot support for WebSocket @Configuration //Declare that this class is a configuration class public class ChatConfig { /** * Configure the bean of ServerEndpointExporter * The Bean will automatically register the Websocket endpoint declared with the @ ServerEndpoint annotation * @return */ @Bean public ServerEndpointExporter serverEndpoint() { return new ServerEndpointExporter(); } }
2.6 write a tool class
This tool class encapsulates a large number of static methods for external calls.
package com.szh.springboot.endpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.websocket.RemoteEndpoint; import javax.websocket.Session; import java.io.IOException; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * A tool class for the realization of chat room function */ public class ChatUtils { //Define log object private static final Logger logger= LoggerFactory.getLogger(ChatUtils.class); //Define a map set to ensure data sharing and security. Here, use ConcurrentHashMap //The user name is key and the session information is value public static final Map<String, Session> CLIENTS=new ConcurrentHashMap<>(); /** * Send messages using connections * @param session User's session * @param message Message content sent */ public static void sendMessage(Session session,String message) { if (session == null) { return; } final RemoteEndpoint.Basic basic=session.getBasicRemote(); if (basic == null) { return; } try { basic.sendText(message); } catch (IOException e) { e.printStackTrace(); logger.error("sendMessage IOException",e); } } /** * Send a message to everyone * @param message */ public static void sendMessageAll(String message) { CLIENTS.forEach((sessionId,session) -> sendMessage(session,message)); } /** * Get all online users */ public static String getOnlineInfo() { Set<String> userNames=CLIENTS.keySet(); if (userNames.size() == 0) { return "No one is currently online......"; } return userNames.toString() + "on-line"; } }
2.7 core classes of websocket
package com.szh.springboot.endpoint; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; /** * @ServerEndpoint Specify the address of the WebSocket protocol in the annotation * @OnOpen,@OnMessage,@OnClose,@OnError The annotation corresponds to the listening event in WebSocket */ @Slf4j //Generate some log code @Component @ServerEndpoint("/websocket/{username}") public class ChatServerEndpoint { /** * Triggered when the connection is established */ @OnOpen public void onOpen(@PathParam("username") String username, Session session) { log.info("user{}Sign in",username); String message= "user[" + username + "]Entered the chat room!"; //Send this user's login message to others ChatUtils.sendMessageAll(message); //Add your own information to the map collection ChatUtils.CLIENTS.put(username,session); //Get the current number of people online and send it to yourself for viewing String onlineInfo=ChatUtils.getOnlineInfo(); ChatUtils.sendMessage(session,onlineInfo); } /** * Triggered when the client receives data from the server */ @OnMessage public void onMessage(@PathParam("username") String username,String message) { log.info("Send message:{}, {}",username,message); //Broadcast and synchronize messages to other clients ChatUtils.sendMessageAll("[" + username + "]: " + message); } /** * Triggered when the connection is closed */ @OnClose public void onClose(@PathParam("username") String username,Session session) { //Remove the user from the current map collection ChatUtils.CLIENTS.remove(username); //Notify others of the user's offline message ChatUtils.sendMessageAll("[" + username + "]Offline!"); try { //Close the Seesion session under WebSocket session.close(); log.info("{} Offline......",username); } catch (IOException e) { e.printStackTrace(); log.error("onClose error",e); } } /** * Triggered when an error occurs in chat communication */ @OnError public void onError(Session session,Throwable throwable) { try { //Close the Seesion session under WebSocket session.close(); } catch (IOException e) { e.printStackTrace(); log.error("onError Exception",e); } log.info("Throwable msg " + throwable.getMessage()); } }
2.8 finally is our jsp page
To put it simply, when we initiate the corresponding request in the controller, we will jump to this page. After the page is loaded (that is, the code before the < script > tag is executed), and then go to the script content. The following is ajax + jQuery. First, we get the request address of websocket, and then trigger onopen, onmessage onclose and onerror. In fact, it is not difficult to understand.
<%@ page contentType="text/html;charset=utf-8" language="java" %> <html> <head> <title>SpringBoot + WebSocket + JSP</title> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css"> <script src="${pageContext.request.contextPath}/js/jquery.min.js"></script> <script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script> </head> <body style="margin: 45px"> <h4>Zhang Qiling online chat room</h4> <div class="form-group"> <label for="content"></label> <textarea id="content" readonly="readonly" cols="80" rows="15"></textarea> </div> <div class="form-group" style="margin-top: 8px"> <textarea id="message" cols="80" rows="5" placeholder="Please enter a message"></textarea> <div style="margin-top: 10px"> <button id="toSend" class="btn btn-info">send out</button> <button id="toExit" class="btn btn-danger">off-line</button> <input id="username" value="${username}" style="display: none"> </div> </div> <script type="text/javascript"> $(function () { var ws; //If the browser supports WebSocket if ("WebSocket" in window) { var baseUrl='ws://localhost:8080/websocket/'; var username=$('#username').val(); ws=new WebSocket(baseUrl + username); //After the connection is established, the event is triggered ws.onopen=function () { console.log("establish websocket connect......"); }; //Receive the message from the background server and trigger the event ws.onmessage=function (event) { $('#content').append(event.data + '\n\n'); console.log("Received the message sent by the server......" + event.data + '\n'); }; //An event is triggered when the connection is closed ws.onclose=function () { $('#content').append('[' + username + '] offline'); console.log("close websocket connect......"); }; //An event is triggered when an error occurs ws.onerror=function (event) { console.log("websocket An error occurred......" + event + '\n'); }; } else { //If the browser does not support WebSocket alert("Sorry, your browser doesn't support it WebSocket!!!"); } //The behavior triggered by the send button. The client sends a message to the server $('#toSend').click(function () { sendMsg(); }); //Support the Enter key to send messages $(document).keyup(function (event) { if (event.keyCode == 13) { sendMsg(); } }); //Function to send message function sendMsg() { ws.send($('#message').val()); $('#message').val(""); } //Offline button triggered behavior $('#toExit').click(function () { if (ws) { ws.close(); } }) }) </script> </body> </html>
2.9 test results
I have three users here, one user0, one user1 and one user2.
Visit the request address three times in the browser to open the chat room of three users.
Then we close the window of user2 or click the offline button.
When user2 is offline, you can see his offline message in the chat window of user0 and user1.
Finally, click the offline buttons of user1 and user0 in turn. Because Slf4j was used in our previous code, we return to IDEA to view the log information printed on the console.