java websocket实现点对点即时聊天

来源:互联网 发布:mac游戏排名 编辑:程序博客网 时间:2024/05/17 02:47

算是一个入门的demo,使用的是springMVC。

必要环境:JDK1.7以上,tomcat7.0以上。以下是干货:

1、websocket的jar直接从tomcat运行库里面添加到build path里面。

2、前台聊天页面,通过ws://localhost:8080/newProject/websocketTest与后台建立连接

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>My JSP 'index.jsp' starting page</title><script type="text/javascript" src="js/jquery-1.8.2.js"></script></head><body>${username}<br/>在线人数:<div id="onlineCount">0</div><br />发送对象:<input id="username" type="text" width="50px"/>内容:<input id="text" type="text" /><button onclick="send()">发送消息</button><hr /><button onclick="closeWebSocket()">关闭WebSocket连接</button><hr /><div id="message"></div></body><script type="text/javascript">var websocket = null;//判断当前浏览器是否支持WebSocketif ('WebSocket' in window) {websocket = new WebSocket("ws://localhost:8080/newProject/websocketTest");} else {alert('当前浏览器 Not support websocket')}//连接发生错误的回调方法websocket.onerror = function() {setMessageInnerHTML("WebSocket连接发生错误");};//连接成功建立的回调方法websocket.onopen = function() {setMessageInnerHTML("WebSocket连接成功");}//接收到消息的回调方法websocket.onmessage = function(event) {debuggervar messageJson=eval("("+event.data+")");if(messageJson.messageType=="message"){setMessageInnerHTML(messageJson.data);}if(messageJson.messageType=="onlineCount"){document.getElementById('onlineCount').innerHTML=messageJson.data;}}//连接关闭的回调方法websocket.onclose = function() {setMessageInnerHTML("WebSocket连接关闭");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function() {closeWebSocket();}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//关闭WebSocket连接function closeWebSocket() {websocket.close();}//发送消息function send() {var message = document.getElementById('text').value;var username = document.getElementById('username').value;websocket.send(username+"@"+message);document.getElementById('message').innerHTML += message + '<br/>';}</script></html>
3、登录页面,简单的创建一个session会话模拟用户登录用作点对点聊天的唯一标识。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme() + "://"+ request.getServerName() + ":" + request.getServerPort()+ path + "/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><base href="<%=basePath%>"><title>My JSP 'login.jsp' starting page</title></head><body><center><form action="chatWebsocket/login.do" method="post"><table><tr><td>username:</td><td><input type="text" id="username" name="username"/></td></tr><tr><td colspan="2"> <input type="submit" value="登录"/></td></tr></table></form></center></body></html>
4、controller类,模拟登录创建会话,并向socket工具类里面传送登录用户的唯一标识。

package com.test.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import com.test.socket.WebSocketTest;@Controller@RequestMapping("chatWebsocket")public class ChartWebsocketController {@RequestMapping("login")public void login(String username,HttpServletRequest request,HttpServletResponse response) throws Exception{HttpSession session=request.getSession();session.setAttribute("username", username);WebSocketTest.setHttpSession(session);request.getRequestDispatcher("/socketChart.jsp").forward(request, response);}@RequestMapping("loginOut")public void loginOut(HttpServletRequest request,HttpServletResponse response) throws Exception{HttpSession session=request.getSession();session.removeAttribute("username");request.getRequestDispatcher("/socketChart.jsp").forward(request, response);}}


5、socket消息处理类,负责消息的接收与转发,作用类似于TCP的服务端,@ServerEndpoint("/websocketTest")的作用是声明websocket的连接路径。

package com.test.socket;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import javax.servlet.http.HttpSession;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;import com.google.gson.Gson;/** * @ServerEndpoint */@ServerEndpoint("/websocketTest")public class WebSocketTest {private static int onlineCount = 0;//存放所有登录用户的Map集合,键:每个用户的唯一标识(用户名)private static Map<String,WebSocketTest> webSocketMap = new HashMap<String,WebSocketTest>();//session作为用户简历连接的唯一会话,可以用来区别每个用户private Session session;//httpsession用以在建立连接的时候获取登录用户的唯一标识(登录名),获取到之后以键值对的方式存在Map对象里面private static HttpSession httpSession;public static void setHttpSession(HttpSession httpSession){WebSocketTest.httpSession=httpSession;}/** * 连接建立成功调用的方法 * @param session * 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */@OnOpenpublic void onOpen(Session session) {Gson gson=new Gson();this.session = session;webSocketMap.put((String) httpSession.getAttribute("username"), this);addOnlineCount(); // MessageDto md=new MessageDto();md.setMessageType("onlineCount");md.setData(onlineCount+"");sendOnlineCount(gson.toJson(md));System.out.println(getOnlineCount());}/** * 向所有在线用户发送在线人数 * @param message */public void sendOnlineCount(String message){for (Entry<String,WebSocketTest> entry  : webSocketMap.entrySet()) {try {entry.getValue().sendMessage(message);} catch (IOException e) {continue;}}}/** * 连接关闭调用的方法 */@OnClosepublic void onClose() {for (Entry<String,WebSocketTest> entry  : webSocketMap.entrySet()) {if(entry.getValue().session==this.session){webSocketMap.remove(entry.getKey());break;}}//webSocketMap.remove(httpSession.getAttribute("username"));subOnlineCount(); // System.out.println(getOnlineCount());}/** * 服务器接收到客户端消息时调用的方法,(通过“@”截取接收用户的用户名) *  * @param message *            客户端发送过来的消息 * @param session *            数据源客户端的session */@OnMessagepublic void onMessage(String message, Session session) {Gson gson=new Gson();System.out.println("收到客户端的消息:" + message);StringBuffer messageStr=new StringBuffer(message);if(messageStr.indexOf("@")!=-1){String targetname=messageStr.substring(0, messageStr.indexOf("@"));String sourcename="";for (Entry<String,WebSocketTest> entry  : webSocketMap.entrySet()) {//根据接收用户名遍历出接收对象if(targetname.equals(entry.getKey())){try {for (Entry<String,WebSocketTest> entry1  : webSocketMap.entrySet()) {//session在这里作为客户端向服务器发送信息的会话,用来遍历出信息来源if(entry1.getValue().session==session){sourcename=entry1.getKey();}}MessageDto md=new MessageDto();md.setMessageType("message");md.setData(sourcename+":"+message.substring(messageStr.indexOf("@")+1));entry.getValue().sendMessage(gson.toJson(md));} catch (IOException e) {e.printStackTrace();continue;}}}}}/** * 发生错误时调用 *  * @param session * @param error */@OnErrorpublic void onError(Session session, Throwable error) {error.printStackTrace();}/** * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 *  * @param message * @throws IOException */public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);// this.session.getAsyncRemote().sendText(message);}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketTest.onlineCount++;}public static synchronized void subOnlineCount() {WebSocketTest.onlineCount--;}}




原创粉丝点击