Server push chat rooms based on Tomcat 7, Java, and websocket

Source: Internet
Author: User
Preface HTML5 websocket implements two-way communication between the server and the browser. Two-way communication simplifies the development of Server Message push. The most common is instant messaging and applications with high requirements on real-time information. In the past, most Server Message pushing technologies were "polling" and "persistent connection". These two technologies will produce considerable overhead for the server, and the real-time performance is not very high. Websocket technology only produces a small amount of overhead, and has a high real-time performance. The following describes how to use websocket technology to develop chat rooms. In this instance, the Tomcat 7 server is used, and each server has different implementations for websocket. Therefore, this instance can only be run on the Tomcat server, however, at present, spring has released websocket APIs that are compatible with the implementation of various servers. You can refer to the relevant materials for more information. I will not introduce them here, but it is for chat rooms: in this example, messages are pushed in real time, and online/offline notifications of chat users are also implemented. The following describes how to implement it. The backend processing of Tomcat to implement websocket mainly relies on Org. apache. catalina. websocket. messageinbound class, which is in {tomcat_home}/lib/Catalina. jar, so you need to import Catalina. jar and tomcat-coyote.jar are introduced, the following code is exposed to the client connection address servlet:
Package COM. ibcio; import javax. servlet. annotation. webservlet; import javax. servlet. HTTP. httpservletrequest; import Org. apache. catalina. websocket. streaminbound; @ webservlet (urlpatterns = {"/message"}) // to receive browser WS: // Protocol requests, you must implement the public class websocketmessageservlet extends Org. apache. catalina. websocket. websocketservlet {Private Static final long serialversionuid = 1l; public static int online_user_count = 1; Public String getuser (httpservletrequest request) {return (string) request. getsession (). getattribute ("user");} // different from the common servlet, createwebsocketinbound must be implemented. Here, the custom websocket connection object @ override protected streaminbound createwebsocketinbound (string subprotocol, httpservletrequest request) {return New websocketmessageinbound (this. getuser (request ));}}

This servlet is somewhat different from a common servlet. It inherits the websocketservlet class and needs to override the createwebsocketinbound method. In this class, the user attribute in the session is set when the user enters index. jsp, And the nickname of the current user is recorded. The following is the self-implemented websocket connection object class websocketmessageinbound code:

Package COM. ibcio; import Java. io. ioexception; import Java. NIO. bytebuffer; import Java. NIO. charbuffer; import net. SF. JSON. jsonobject; import Org. apache. catalina. websocket. messageinbound; import Org. apache. catalina. websocket. wsoutbound; public class websocketmessageinbound extends messageinbound {// name of the currently connected user private final string user; Public websocketmessageinbound (string user) {This. user = user;} Public String getuser () {return this. user;} // The event triggered when a connection is established @ overrideprotected void onopen (wsoutbound outbound) {// The Connection event is triggered, and jsonobject result = new jsonobject () is added to the connection pool (); result. element ("type", "user_join"); result. element ("user", this. user); // push the online message websocketmessageinboundpool to all online users. sendmessage (result. tostring (); Result = new jsonobject (); result. element ("type", "get_online_user"); result. element ("list", websocketmessageinboundpool. getonlineuser (); // Add the current connection object websocketmessageinboundpool to the connection pool. addmessageinbound (this); // send the list of current online users to the current connection websocketmessageinboundpool. sendmessagetouser (this. user, result. tostring () ;}@ overrideprotected void onclose (INT status) {// triggers the Close event and removes the websocketmessageinboundpool connection in the connection pool. removemessageinbound (this); jsonobject result = new jsonobject (); result. element ("type", "user_leave"); result. element ("user", this. user); // send the websocketmessageinboundpool message to the online user. sendmessage (result. tostring () ;}@ overrideprotected void onbinarymessage (bytebuffer message) throws ioexception {Throw new unsupportedoperationexception ("binary message not supported. ");} // The Event @ overrideprotected void ontextmessage (charbuffer message) throws ioexception triggered when the client sends a message to the server {// send the message websocketmessageinboundpool to all online users. sendmessage (message. tostring ());}}

The onopen, onclose, and ontextmessage methods are implemented in the code to process online, offline, and sent messages respectively. There is a websocketmessageinboundpool class in this class. This class is used to manage the connections of online users. The following is the code of this class:

Package COM. ibcio; import Java. io. ioexception; import Java. NIO. charbuffer; import Java. util. hashmap; import Java. util. map; import Java. util. set; public class websocketmessageinboundpool {// Save the connected map container Private Static final map <string, websocketmessageinbound> connections = new hashmap <string, websocketmessageinbound> (); // Add the public static void addmessageinbound (websocketmessageinbound inbound) to the connection pool {// Add the connection sys TEM. out. println ("User:" + inbound. getuser () + "join .. "); connections. put (inbound. getuser (), inbound);} // obtain all online users public static set <string> getonlineuser () {return connections. keyset ();} public static void removemessageinbound (websocketmessageinbound inbound) {// remove the connection system. out. println ("User:" + inbound. getuser () + "exit .. "); connections. remove (inbound. getuser ();} public static void sendmessagetous Er (string user, string message) {try {// send data to a specific user system. out. println ("send message to user:" + User + ", message content:" + message); websocketmessageinbound inbound = connections. get (User); If (inbound! = NULL) {inbound. getwsoutbound (). writetextmessage (charbuffer. wrap (Message) ;}} catch (ioexception e) {e. printstacktrace () ;}/// send the public static void sendmessage (string message) {try {set <string> keyset = connections. keyset (); For (string key: keyset) {websocketmessageinbound inbound = connections. get (key); If (inbound! = NULL) {system. out. println ("send message to user:" + key + ", message content:" + message); inbound. getwsoutbound (). writetextmessage (charbuffer. wrap (Message) ;}} catch (ioexception e) {e. printstacktrace ();}}}
Front-end display

The above code is the background code of the chat room. It consists of three objects: servlet, connection object, and connection pool. The following is the front-end code, the front-end code mainly connects to the server to display the user list and Information List. The front-end code uses the ext framework. If you are not familiar with ext, you can get a preliminary understanding of Ext, the following is the index. JSP code:

<% @ Page Language = "Java" pageencoding = "UTF-8" Import = "com. ibcio. websocketmessageservlet "%> <% string user = (string) session. getattribute ("user"); If (user = NULL) {// generate nickname user = "visitor" + websocketmessageservlet for the user. online_user_count; websocketmessageservlet. online_user_count ++; Session. setattribute ("user", user);} pagecontext. setattribute ("user", user); %> <HTML> 

The page display is mainly controlled in websocket. js. below is the websocket. JSD code:

// Displays the user's chat information Ext. define ('messageiner iner ', {extend: 'ext. view. view', trackover: True, multiselect: false, itemcls: 'l-im-message', itemselector: 'div. l-im-message', overitemcls: 'l-im-message-over', selecteditemcls: 'l-im-message-selected', style: {overflow: 'auto ', backgroundcolor: '# fff'}, TPL: [' <Div class = "L-im-message-Warn"> during conversations, do not trust remittances, winning information, or unfamiliar phone numbers. Comply with relevant laws and regulations. </Div> ',' <TPL for = ". "> ',' <Div class =" L-im-message "> ', '<Div class = "L-im-message-header-{source}" >{from} {timestamp} </div> ', '<Div class = "L-im-message-Body" >{content} </div>', '</div>', '</TPL>'], messages: [], initcomponent: function () {var me = This; me. messagemodel = ext. define ('leetop. im. messagemodel ', {extend: 'ext. data. model ', fields: ['from', 'timestamp', 'content', 'source']}); me. store = ext. create ('ext. data. store', {model: 'leetop. im. messagemodel ', data: me. messages}); me. callparent () ;}, // display the information pushed by the server to the page. Receive: function (Message) {var me = This; message ['timestamp'] = ext. date. format (new date (Message ['timestamp']), 'H: I: s'); If (message. from = user) {message. source = 'self ';} else {message. source = 'remote';} Me. store. add (Message); If (Me. el. dom) {me. el. dom. scrolltop = me. el. dom. scrollheight ;}}});

This code mainly implements the container for displaying messages. The following code is executed after the page is loaded:

Ext. onready (function () {// create user input box var input = ext. create ('ext. form. field. htmleditor ', {region: 'south', height: 120, enablefont: false, enablesourceedit: false, enablealignments: false, listeners: {initialize: function () {Ext. eventmanager. on (Me. input. getdoc (), {keyup: function (e) {If (E. ctrlkey === true & E. keycode = 13) {e. preventdefault (); E. stoppropagation (); send () ;}}}) ;}}); // create a message display container var outp Ut = ext. create ('messagecontainer ', {region: 'center'}); var dialog = ext. create ('ext. panel. panel ', {region: 'center', layout: 'border', items: [input, output], buttons: [{text: 'put', Handler: send}]}); var websocket; // initial websocketfunction initwebsocket () {If (window. websocket) {websocket = new websocket (encodeuri ('ws: // localhost: 8080/websocket/message'); websocket. onopen = function () {// connection successful win. Settitle (Title + '(connected)');} websocket. onerror = function () {// Connection Failed win. settitle (Title + '(connection error)');} websocket. onclose = function () {// Connection closed win. settitle (Title + '(disconnected)');} // message receiving websocket. onmessage = function (Message) {var message = JSON. parse (message. data); // receives the message if (message. type = 'message') {output. receive (Message);} else if (message. type = 'get _ online_user ') {// obtain the online user list var root = onlin Euser. getrootnode (); Ext. each (message. list, function (User) {var node = root. createnode ({ID: User, text: User, iconcls: 'user', leaf: true}); root. appendchild (node) ;}) ;}else if (message. type = 'user _ join') {// var root = onlineuser. getrootnode (); var user = message. user; var node = root. createnode ({ID: User, text: User, iconcls: 'user', leaf: true}); root. appendchild (node);} else if (message. type = = 'User _ leave ') {// user offline var root = onlineuser. getrootnode (); var user = message. user; var node = root. findchild ('id', user); root. removechild (node) ;}}}; // online user tree var onlineuser = ext. create ('ext. tree. panel ', {Title: 'Online user', rootvisible: false, Region: 'east', width: 150, lines: false, usearrows: True, autoscroll: True, split: true, iconcls: 'user-online', store: ext. create ('ext. data. treestore', {root: {Text: 'Online user', expanded: True, children: []}); var Title = 'Welcome: '+ user; // display window var win = ext. create ('ext. window. window ', {Title: Title +' (not connected) ', layout: 'border', iconcls: 'user-win', minwidth: 650, minheight: 460, width: 650, animatetarget: 'websocket _ call', height: 460, items: [dialog, onlineuser], border: false, listeners: {render: function () {initwebsocket () ;}}); win. show (); // send message funct Ion send () {var message ={}; if (websocket! = NULL) {If (input. getvalue () {Ext. apply (message, {from: User, content: input. getvalue (), timestamp: new date (). gettime (), type: 'message'}); websocket. send (JSON. stringify (Message); // output. receive (Message); input. setvalue ('') ;}} else {Ext. MSG. alert ('hprompt ',' you are offline and cannot send messages! ');}}});

The code above is the code that automatically connects to the server after the page is loaded and creates a display interface.

Pay attention to the following two points. jar and tomcat-coyote.jar Delete, such as the project lib directory in D: \ workspace \ websocket \ webroot \ WEB-INF \ Lib, and the deployment of the application lib directory is in D: \ tools \ apache-Tomcat-7.0.32 \ webapps \ websocket \ WEB-INF \ Lib, delete the lib directory of the deployment directory can be connected to two jar, otherwise the package cocould not initialize class COM. ibcio. websocketmessageservlet error. Remember. If you still cannot establish a connection, please download the latest Tomcat and forget that the tomcatcreatewebsocketinbound version does not have the request parameter. The current Code has this parameter, both 7.0.3xx and later versions contain this parameter. Summary It is very convenient to use websocket development server push. This is a simple application. In fact, you can also use WebRTC to implement video chat and voice chat. The browser-side video chat function has been implemented in my leetop project. You can go to www.ibcio.com and have a detailed introduction in my other article: Ghost
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.