To achieve the goal of this article, it is necessary to directly realize the function of chatting, and, on the basis of the chat function, and then realize the function of the cache chat record. The first step: the principle of chat implementation first, we need to clarify our needs. Usually, the chat on the Web page is the form of the chat room, so, this example also has a chat space concept, as long as in this space, you can chat together. Secondly, everyone can speak and be seen by others, so everyone will send their own content to the backstage, backstage to each person. On the client side, the socket can be easily implemented, and on the web, it was previously done by polling, but after the advent of websocket, it was possible to implement this function through a long connection, like a socket client, through WebSocket. The second step: the server base code through the above analysis of the principle can be known, the need to send to the background of the data is very simple, that is, user information, chat information, and space information, because it is a simple example, so the 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 + ' \ ' + '}'; }}
Through this bean to receive the message sent by the Web, and then forward on the server, the next is the logic of forwarding, but first need to introduce a spring websocket a annotation. The annotation of the controller layer of spring MVC is requestmapping everybody knows, similarly, WebSocket also has the same function annotation, is messagemapping, its value is the access address. Now let's see how the controller layer is implemented:
/** * WebSocket Chat corresponding receive method and forwarding method * * @param userchat information about user chat * /@MessageMapping ("/userchat") Public void Userchat (Userchatcommand userchat) { //Find address to send String dest = "/userchat/chat" + Userchat.getcoordinationid (); Send user's chat record this.template.convertAndSend (dest, userchat); }
Why is it so simple? Oh, can be so simple to implement the background code, all is the credit of spring. First of all, we agreed to send the rules of the address, that is, chat followed by the previous sent to the ID, and then through the "template" to forward, the "template" is a spring implementation of a Send template class: Simpmessagingtemplate, When we define a controller, we can inject it in the constructor method:
@Controllerpublic class Coordinationcontroller { ... Used to forward data (SendTo) private simpmessagingtemplate template; <pre name= "code" class= "java" > @Autowired public coordinationcontroller (Simpmessagingtemplate t) { template = t; } .....}
Now the user sent over the chat message forwarded to a contractual space, as long as the web side of the user subscribed to the address of this space, then you will receive the JSON forwarded over. Now let's look at what the web side needs to do. The third step: the Web-side code in an article has already introduced the connection WebSocket, so here does not repeat the said. First we create a page, write a textarea (id=chat_content) in the page to use as a chat record to display the place, write a input (id=chat_input) as a chat box, write a button as a Send button, although a bit humble, The beautification of the page is left behind when the feature is implemented. Now it's time to use the stompclient used in the previous article to connect to the background and define the stompclient as a global variable to make it easier for us to use it everywhere. According to logic, we first write a method of sending a message, so that we can first test whether the background is correct. We write a function called Sendname (which is random when writing code), and bind to the Send button onclick event. What we're going to do is probably the following steps: 1. Get input2. The data needed to assemble a string3. Send to the background the first step is simple, using jquery for a second, the second step can be done using the Json.stringify () method, The third step is to use the Stompclient send method, the Send method has three parameters, the first is to send the address, the second parameter is the header information, the third parameter is the message body, so sendname the overall code 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 ': Enco Deuricomponent (Inputvalue), ' Coordinationid ': Coordinationid});}
Among them, name and Coordinationid are the corresponding user information, can be obtained through Ajax or JSP, there is not much to say. Explain why the address is "/app/userchat": in the first article configured WebSocket information, one of which is applicationdestinationprefixes, configured "/app", from the name can be seen, is the WebSocket program address prefix, that is, in fact, this "/app" is to distinguish between ordinary address and websocket address, so long as the WebSocket address, you need to add "/app" in front of the controller address is "/ Userchat ", so the final form of the address is"/app/userchat ". Now run the program, in the background next breakpoint, we can see that the chat message has been sent to the background. But the web side does not show anything, this is because we have not subscribed to the corresponding address, so the background forwarding message is not to receive at all. Back to the previous function connected to the background: Stompclient.connect (",", "function (frame) {}), you can notice that the last is a method body, it is a callback method, when the connection is successful will call this method, So we subscribe to backstage messages in this method body. Stompclient's subscription method is called subscribe, there are two parameters, the first parameter is the address of the subscription, and the second parameter is the callback function when the message is received. Next try to subscribe to chat information: according to the previous convention, you can get the address of the subscription is '/coordination/coordination ' + Coordinationid, so we subscribe to this address can be, when the subscription is successful, as long as the background has forwarded messages, The second method is called, and the message body passed from the background is used as a parameter. So the method of subscribing is as follows:
User Chat Subscription stompclient.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 of displaying the chat information is no longer explained, as follows:
Display chat information function showchat (message) { var response = document.getElementById (' chat_content '); Response.value + = decodeURIComponent (message.name) + ': ' + decodeuricomponent (message.chatcontent) + ' \ n ';}
Because before the processing of Chinese problems, so the data sent to the background is transcoded, from the background after the return, you also need to turn the code back. Here, chat function has done, run the program, will find, really can chat! A chat program, that's that simple. But this does not satisfy, the function of the future can play our imagination to add, for example: I think, chat program, at least also to cache some chat records, not then come in the user do not know what the user is talking about, the user experience will be very bad, then look at the chat record cache is how to achieve it. Fourth step: The chat record cache implementation because it is a small program, it does not use the database to record the cache, which is not only cumbersome, but also inefficient. I simply used a map to implement the cache. First, we define a map in the controller, which guarantees that only one cached copy is available when the program is running. The key of the map is the ID of each space, and the value is the cache information.
Private Map<integer, object[]> Coordinationcache = new Hashmap<integer, object[]> ();
Here I have an object array, because I write the program, in addition to the cache of chat information, there is a lot of things to cache, just the cache of the chat information is placed in a position in this array. For the sake of simplicity, you can directly store Userchatcommand objects sent over the web to the cache, and our server resources are limited, since I put the map into memory to implement the cache, I do not think of this, my idea is to implement a fixed-size queue, When the maximum queue size is reached, the most advanced elements are popped up, and then the elements to be entered are inserted, keeping the latest chat history. But there seems to be no such queue (I didn't see it in the JDK anyway), so I implemented a queue of my own, which is very simple, the class is called Limitqueue, uses generics, inherits from the queue, and defines two member variables in a class:
private int limit;private queue<e> Queue;
The Limit team column is capped, and the queue is the one that is actually used. Create a construction method that is formed by these two parameters, and implement all the methods of the queue, all of which are done by the queue object, such as:
@Override public int size () { return queue.size (); } @Override Public Boolean isEmpty () { return queue.isempty (); }
Among them, there is a way to do the processing:
@Override Public Boolean offer (E e) { if (queue.size () >= limit) { queue.poll (); } Return Queue.offer (e); }
When the element is added, it is determined whether the upper limit is reached, then the queue is reached first, and then the queue is entered. In this way, a fixed-size queue is implemented and always keeps up-to-date records. Then, when the Web side sends the chat message to the backstage, it can record the message in this queue and save it in the map, so the following method of receiving the chat after the change is as follows:
/** * websocket Chat The corresponding Receive method and forwarding method * * @param userchat information about user chats */@MessageMapping ("/userchat") public void Userchat (Userch Atcommand userchat) {//Find the address to be sent String dest = "/userchat/chat" + Userchat.getcoordinationid (); Send user's chat record this.template.convertAndSend (dest, userchat); Get the cache and store the user's latest chat record 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<userchatcommand>) cache[1]). Offer (Userchat); }
Already have the cache, as long as the page to remove the cache can display the chat record, can be through Ajax or JSP methods, however, WebSocket also has a method can be implemented, because spring WebSocket provides a annotation called subscribemapping, this annotation tag method is called at the time of the subscription, that is, basically only the method of execution once, it is very suitable for us to initialize the chat record. So, under the code that subscribes to the chat information, you can add a method to initialize the chat record. Let's start by writing the web-side 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 address of this subscription is init, or add Coordinationid to distinguish the space, the data sent is an array of chat records, the loop is displayed in the dialog box. With the web-side code constraints, the background code is basically out, as long as the use of subscribemapping, and then assemble the data is completed, the background code is as follows:
/** * Initialize, initialize the chat record * * @param the ID of the Coordinationid co-space * /@SubscribeMapping ("/init/{ Coordinationid} ") Public map<string,object> Init (@DestinationVariable (" Coordinationid ") int Coordinationid) { System.out.println ("------------New user entry, space initialization---------"); map<string, object> document = new hashmap<string, object> (); Document.put ("Chat", Coordinationcache.get (Coordinationid) [1]); return document; }
In this way, the cache chat record is also implemented.
Conclusion This is my graduation design, my graduation design is an online collaborative preparation system, for multi-person online simultaneous and real-time operation of documents and presentations, which contains the small chat function, so use it to explain the use of spring websocket. I put the code on GitHub, interested friends can go to see the code, next, I will consider my graduation design of the source of the introduction, there are a lot of shortcomings, but also hope that you correct. GitHub Address: Https://github.com/xjyaikj/OnlinePreparation