Spring WebSocket tutorial (2)

Source: Internet
Author: User

Spring WebSocket tutorial (2)
To achieve this goal, we need to directly implement the chat function, and then implement the function of caching certain chat records based on the chat function. Step 1: First of all, we need to clarify our requirements. Generally, the chat on the Web page is in the form of a chat room, so this example also has the concept of a chat space, as long as you can chat in this space. Secondly, everyone can speak and be seen by others. Therefore, everyone will send what they want to say to the background and forward it to everyone in the background. In the client, it can be easily implemented using Socket. In the web end, it was previously implemented through polling. However, after the emergence of WebSocket, WebSocket can be used like a Socket Client, this function is implemented through persistent connections. Step 2: the Basic server code can be found through the above principle analysis. The data to be sent to the backend is very simple, that is, user information, chat information, and space information, as it is a simple example, bean design is relatively simple:

public class UserChatCommand {    private String name;    private String chatContent;    private String coordinationId;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getChatContent() {        return chatContent;    }    public void setChatContent(String chatContent) {        this.chatContent = chatContent;    }    public String getCoordinationId() {        return coordinationId;    }    public void setCoordinationId(String coordinationId) {        this.coordinationId = coordinationId;    }    @Override    public String toString() {        return "UserChatCommand{" +                "name='" + name + '\'' +                ", chatContent='" + chatContent + '\'' +                ", coordinationId='" + coordinationId + '\'' +                '}';    }}
The bean is used to receive the message sent by the web Client, and then forward the message on the server. The next step is the forwarding logic. But first, we need to introduce an annotation of Spring WebSocket. The annotation at the controller layer of spring mvc is RequestMapping. As we all know, WebSocket has the same function of annotation, that is, MessageMapping, and its value is the access address. Now let's take a look at how the controller layer is implemented:
/*** WebSocket chat receiver method and forwarding method ** @ param userChat information about user chat */@ MessageMapping ("/userChat") public void userChat (UserChatCommand userChat) {// find the address to be sent String dest = "/userChat/chat" + userChat. getCoordinationId (); // send the user's chat record this. template. convertAndSend (dest, userChat );}
Why is it so simple? It's all Spring's credit to implement the background code in such a simple way. First, we agree on the Sending address rule, that is, the chat is followed by the id sent previously, and then forwarded through this "template, this "template" is a sending template class implemented by Spring: SimpMessagingTemplate. When we define the controller, we can inject it in the constructor:
@ Controllerpublic class CoordinationController {...... // used to forward data (sendTo) private SimpMessagingTemplate template;
    @Autowired    public CoordinationController(SimpMessagingTemplate t) {        template = t;    }    .....}
Now the chat information sent by the user has been forwarded to an agreed space. As long as the web user subscribes to the address of the space, the forwarded json will be received. Now let's take a look at what the web end needs to do. Step 3: The Web client code has already introduced WebSocket connection in the previous article, so I will not repeat it here. First, create a page, write a textarea (id = chat_content) in the page to display the chat record, and write an input (id = chat_input) as the chat box, write a button as a sending button. Although it is simple, you can leave the page beautification function after implementation. Now we need to use the stompClient used in the previous article to connect to the backend, and define this stompClient as a global variable so that we can use it anywhere. According to the logic, we should first write a message sending method, so that we can first test whether the background is correct. We write a function called sendName (which is garbled during code writing) and bind it to The onclick event of the send button. We have to do the following steps: 1. obtain the data required by input2. assemble a string3. the first step is very simple to send to the background. Use jquery for one second. The second step can be JSON. after the stringify () method is completed, the stompClient send method is used in step 3. The send method has three parameters: the first is the Sending address, and the second is the header information, the third parameter is the message body, so the overall code of sendName is as follows:
// Send chat information function sendName () {var input = $ ('# chat_input'); var inputValue = input. val (); input. val (""); stompClient. send ("/app/userChat", {}, JSON. stringify ({'name': encodeURIComponent (name), 'chatcontent': encodeURIComponent (inputValue), 'coordinationid': coordinationId }));}
Here, name and coordinationId are the corresponding user information, which can be obtained through ajax or jsp. To explain why the address is "/app/userChat": In the first article, configure the WebSocket information, one of which is ApplicationDestinationPrefixes and the other is "/app ", it can be seen from the name that it is the prefix of the WebSocket program address, that is to say, in fact, this "/app" is used to distinguish the common address from the WebSocket address, so as long as it is a WebSocket address, add "/app" to the front, and the controller address in the background is "/userChat". Therefore, the final address is "/app/userChat ". Now run the program and next breakpoint in the background. We can see that the chat information has been sent to the background. However, the web end does not display anything. This is because we have not subscribed to the corresponding address, so the messages forwarded in the background are not received at all. Return to the function used to connect to the backend: stompClient. connect ('','', function (frame) {}), you can note that the last is a method body, which is a callback method, this method is called when the connection is successful, so we subscribe to background messages in this method body. The stompClient subscription method is subscribe. There are two parameters. The first parameter is the subscription address, and the second parameter is the callback function when the message is received. Next, we will try to subscribe to the chat information: according to the previous conventions, we can get the subscription address '/coordination' + coordinationId, so we can subscribe to this address, after the subscription is successful, the second method is called as long as there is a message forwarded in the background, and the message body transmitted in the background is used as the parameter. The subscription method is as follows:
// Subscribe ('/userChat/chat' + coordinationId, function (chat) {showChat (JSON. parse (chat. body ));});
Convert the message body to json, and then write a method to display the chat information. The method to display the chat information is not explained as follows:
// Function showChat (message) {var response = document. getElementById ('chat _ content'); response. value + = decodeURIComponent (message. name) + ':' + decodeURIComponent (message. chatContent) + '\ n ';}
The data sent to the backend is transcoded because the Chinese characters are previously processed. After the data is sent back from the backend, the encoding needs to be transferred back. Now, the chat function has been completed. Run the program and you will find that you can chat! A chat program is that simple. However, this does not satisfy the requirements. We can use our imagination to add functions in the future. For example, I think chat programs should at least cache Some Chat records, if the incoming users do not know what the previous users are talking about, the user experience will be very poor. Next, let's look at how the chat record cache is implemented. Step 4: The Chat record cache is implemented because it is a small program and the database is not used to record the cache. This is not only troublesome but also inefficient. I simply used a Map to implement caching. First, we define a Map in the controller to ensure that there is only one cached copy when the program is running. The Map key is the id of each space and the value is the cache information.
private Map
  
    coordinationCache = new HashMap
   
    ();
   
  
Here, I am storing an Object array because in the program I write, in addition to the chat information cache, there are still many things to cache, only the chat information is cached in a location in this array. For the sake of simplicity, you can directly store the UserChatCommand object sent from the web end to the cache, while our server resources are limited. Since I use Map to put it in the memory for caching, I would not have imagined this. My idea is to implement a fixed-size queue. When the queue size limit is reached, the most advanced elements will pop up and insert the elements to be entered, in this way, the latest chat records are retained. But it seems that there is no such Queue (I didn't see it in jdk anyway), So I implemented such a queue myself. The implementation is very simple. The class name is LimitQueue and the generic type is used, inherited from Queue. Two member variables are defined in the class:
private int limit;private Queue
  
    queue;
  
Limit indicates the upper limit of the queue, and queue is the queue actually used. Create a constructor composed of these two parameters and implement all Queue methods. All methods are completed by the queue object, for example:
    @Override    public int size() {        return queue.size();    }    @Override    public boolean isEmpty() {        return queue.isEmpty();    }
Here, there is a method that needs to be processed:
    @Override    public boolean offer(E e) {        if (queue.size() >= limit) {            queue.poll();        }        return queue.offer(e);    }
When an element is added, determine whether the upper limit is reached. If the upper limit is reached, the first-out queue is added and the second-entry queue is added. In this way, a queue of a fixed size is implemented and the latest records are always kept. Then, when the web Client sends a chat message to the background, it can record the message in this queue and save it in Map. Therefore, the modified chat receiving method is as follows:
/*** WebSocket chat receiver method and forwarding method ** @ param userChat information about user chat */@ MessageMapping ("/userChat") public void userChat (UserChatCommand userChat) {// find the address to be sent String dest = "/userChat/chat" + userChat. getCoordinationId (); // send the user's chat record this. template. convertAndSend (dest, userChat); // obtain the cache and store the latest chat records in the cache. Object [] cache = coordinationCache. get (Integer. parseInt (userChat. getCoordinationId (); try {userChat. setName (URLDecoder. decode (userChat. getName (), "UTF-8"); userChat. setChatContent (URLDecoder. decode (userChat. getChatContent (), "UTF-8");} catch (UnsupportedEncodingException e) {e. printStackTrace ();} (LimitQueue
  
   
) Cache [1]). offer (userChat );}
  
If the cache is available, you can retrieve the cache on the page to display chat records. You can use ajax or jsp methods. However, WebSocket can also be implemented, spring WebSocket provides an annotation called SubscribeMapping. This annotation flag method is called during subscription. That is to say, the method is executed only once, it is suitable for us to initialize chat records. Therefore, you can add a method to initialize chat records under the Code for subscribing to chat information. First, write the web code:
// Initialize stompClient. subscribe ('/app/init/' + coordinationId, function (initData) {console. log (initData); var body = JSON. parse (initData. body); var chat = body. chat; chat. forEach (function (item) {showChat (item );});});
The subscription address is init or coordinationId to differentiate space. The sent data is an array of chat records and is displayed cyclically in the dialog box. With the web-side code constraints, the background code is also basically ready. You only need to use SubscribeMapping and then assemble the data. The background code is as follows:
/*** Initialize the chat record ** @ param coordinationId: id of the collaborative space */@ SubscribeMapping ("/init/{coordinationId}") public Map
  
   
Init (@ DestinationVariable ("coordinationId") int coordinationId) {System. out. println ("------------ new user enters, space initialization ---------"); Map
   
    
Document = new HashMap
    
     
(); Document. put ("chat", coordinationCache. get (coordinationId) [1]); return document ;}
    
   
  
In this way, cache chat records are also implemented.
Conclusion: This is my graduation project. My graduation project is an online collaborative course preparation system. It is used to operate documents and presentations simultaneously and in real time by multiple people online. It includes the chat function, so use it to explain the use of Spring WebSocket. I put the code on github. If you are interested, you can check the code. Next, I will consider introducing the source code of my graduation project, which has many shortcomings, I also hope you can correct it. Github address: https://github.com/xjyaikj/OnlinePreparation

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.