javaweb與websocket實現線上聊天功能總結

來源:互聯網
上載者:User

標籤:bre   javascrip   create   path   資訊   html 4.01   rip   spring   substr   

技術從一開始ajax輪詢後來改成websocket 碰到的一些問題的處理:

websocket的pom依賴

<dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-websocket</artifactId>            <version>4.0.5.RELEASE</version>        </dependency>

首先是配置處理器

import javax.annotation.Resource;import org.springframework.stereotype.Component;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import org.springframework.web.socket.config.annotation.EnableWebSocket;import org.springframework.web.socket.config.annotation.WebSocketConfigurer;import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;/** * WebScoket配置處理器 * @author Goofy * @Date 2015年6月11日 下午1:15:09 */@Component@EnableWebSocketpublic class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {@ResourceMyWebSocketHandler handler;public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(handler, "/ws").addInterceptors(new HandShake());registry.addHandler(handler, "/ws/sockjs").addInterceptors(new HandShake()).withSockJS();}}

2.請求所經過的握手攔截器 主要用來將ServerHttpRequest裡的session的使用者資訊存放在attributes裡 到處理的handle中 會自動存入websocketsession的attribute裡

import java.util.Map;import javax.servlet.http.HttpSession;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.http.server.ServletServerHttpRequest;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.server.HandshakeInterceptor;/** * Socket建立串連(握手)和斷開 *  * @author Goofy * @Date 2015年6月11日 下午2:23:09 */public class HandShake implements HandshakeInterceptor {public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {System.out.println("Websocket:使用者[ID:" + ((ServletServerHttpRequest) request).getServletRequest().getSession(false).getAttribute("uid") + "]已經建立串連");if (request instanceof ServletServerHttpRequest) {ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;HttpSession session = servletRequest.getServletRequest().getSession(false);// 標記使用者Long uid = (Long) session.getAttribute("uid");if(uid!=null){attributes.put("uid", uid);}else{return false;}}return true;}public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {}}

Socket處理器 處理串連通訊 或錯誤 關閉等

import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import org.springframework.stereotype.Component;import org.springframework.web.socket.CloseStatus;import org.springframework.web.socket.TextMessage;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.WebSocketMessage;import org.springframework.web.socket.WebSocketSession;import org.xdemo.example.websocket.entity.Message;import com.google.gson.Gson;import com.google.gson.GsonBuilder;/** * Socket處理器 *  * @author Goofy * @Date 2015年6月11日 下午1:19:50 */@Componentpublic class MyWebSocketHandler implements WebSocketHandler {public static final Map<Long, WebSocketSession> userSocketSessionMap;static {userSocketSessionMap = new HashMap<Long, WebSocketSession>();}/** * 建立串連後 */public void afterConnectionEstablished(WebSocketSession session)throws Exception {Long uid = (Long) session.getAttributes().get("uid");if (userSocketSessionMap.get(uid) == null) {userSocketSessionMap.put(uid, session);}}/** * 訊息處理,在用戶端通過Websocket API發送的訊息會經過這裡,然後進行相應的處理 */public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {if(message.getPayloadLength()==0)return;Message msg=new Gson().fromJson(message.getPayload().toString(),Message.class);msg.setDate(new Date());sendMessageToUser(msg.getTo(), new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));}/** * 訊息傳輸錯誤處理 */public void handleTransportError(WebSocketSession session,Throwable exception) throws Exception {if (session.isOpen()) {session.close();}Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();// 移除Socket會話while (it.hasNext()) {Entry<Long, WebSocketSession> entry = it.next();if (entry.getValue().getId().equals(session.getId())) {userSocketSessionMap.remove(entry.getKey());System.out.println("Socket會話已經移除:使用者ID" + entry.getKey());break;}}}/** * 關閉串連後 */public void afterConnectionClosed(WebSocketSession session,CloseStatus closeStatus) throws Exception {System.out.println("Websocket:" + session.getId() + "已經關閉");Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();// 移除Socket會話while (it.hasNext()) {Entry<Long, WebSocketSession> entry = it.next();if (entry.getValue().getId().equals(session.getId())) {userSocketSessionMap.remove(entry.getKey());System.out.println("Socket會話已經移除:使用者ID" + entry.getKey());break;}}}public boolean supportsPartialMessages() {return false;}/** * 給所有線上使用者發送訊息 *  * @param message * @throws IOException */public void broadcast(final TextMessage message) throws IOException {Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();// 多線程群發while (it.hasNext()) {final Entry<Long, WebSocketSession> entry = it.next();if (entry.getValue().isOpen()) {// entry.getValue().sendMessage(message);new Thread(new Runnable() {public void run() {try {if (entry.getValue().isOpen()) {entry.getValue().sendMessage(message);}} catch (IOException e) {e.printStackTrace();}}}).start();}}}/** * 給某個使用者發送訊息 *  * @param userName * @param message * @throws IOException */public void sendMessageToUser(Long uid, TextMessage message)throws IOException {WebSocketSession session = userSocketSessionMap.get(uid);if (session != null && session.isOpen()) {session.sendMessage(message);}}}

  頁面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getServerName() + ":"+ request.getServerPort() + path + "/";String basePath2 = request.getScheme() + "://"+ request.getServerName() + ":" + request.getServerPort()+ path + "/";%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title></title><script type="text/javascript" src="<%=basePath2%>resources/jquery.js"></script><style>textarea {height: 300px;width: 100%;resize: none;outline: none;}input[type=button] {float: right;margin: 5px;width: 50px;height: 35px;border: none;color: white;font-weight: bold;outline: none;}.clear {background: red;}.send {background: green;}.clear:active {background: yellow;}.send:active {background: yellow;}.msg {width: 100%;height: 25px;outline: none;}#content {border: 1px solid gray;width: 100%;height: 400px;overflow-y: scroll;}.from {background-color: green;width: 80%;border-radius: 10px;height: 30px;line-height: 30px;margin: 5px;float: left;color: white;padding: 5px;font-size: 22px;}.to {background-color: gray;width: 80%;border-radius: 10px;height: 30px;line-height: 30px;margin: 5px;float: right;color: white;padding: 5px;font-size: 22px;}.name {color: gray;font-size: 12px;}.tmsg_text {color: white;background-color: rgb(47, 47, 47);font-size: 18px;border-radius: 5px;padding: 2px;}.fmsg_text {color: white;background-color: rgb(66, 138, 140);font-size: 18px;border-radius: 5px;padding: 2px;}.sfmsg_text {color: white;background-color: rgb(148, 16, 16);font-size: 18px;border-radius: 5px;padding: 2px;}.tmsg {clear: both;float: right;width: 80%;text-align: right;}.fmsg {clear: both;float: left;width: 80%;}</style><script>var path = ‘<%=basePath%>‘;var uid=${uid eq null?-1:uid};if(uid==-1){location.href="<%=basePath2%>";}var from=uid;var fromName=‘${name}‘;var to=uid==1?2:1;var websocket;if (‘WebSocket‘ in window) {websocket = new WebSocket("ws://" + path + "/ws?uid="+uid);} else if (‘MozWebSocket‘ in window) {websocket = new MozWebSocket("ws://" + path + "/ws"+uid);} else {websocket = new SockJS("http://" + path + "/ws/sockjs"+uid);}websocket.onopen = function(event) {console.log("WebSocket:已串連");console.log(event);};websocket.onmessage = function(event) {var data=JSON.parse(event.data);console.log("WebSocket:收到一條訊息",data);var textCss=data.from==-1?"sfmsg_text":"fmsg_text";$("#content").append("<div class=‘fmsg‘><label class=‘name‘>"+data.fromName+" "+data.date+"</label><div class=‘"+textCss+"‘>"+data.text+"</div></div>");scrollToBottom();};websocket.onerror = function(event) {console.log("WebSocket:發生錯誤 ");console.log(event);};websocket.onclose = function(event) {console.log("WebSocket:已關閉");console.log(event);}function sendMsg(){var v=$("#msg").val();if(v==""){return;}else{var data={};data["from"]=from;data["fromName"]=fromName;data["to"]=to;data["text"]=v;websocket.send(JSON.stringify(data));$("#content").append("<div class=‘tmsg‘><label class=‘name‘>我 "+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</label><div class=‘tmsg_text‘>"+data.text+"</div></div>");scrollToBottom();$("#msg").val("");}}function scrollToBottom(){var div = document.getElementById(‘content‘);div.scrollTop = div.scrollHeight;}Date.prototype.Format = function (fmt) { //author: meizz     var o = {        "M+": this.getMonth() + 1, //月份         "d+": this.getDate(), //日         "h+": this.getHours(), //小時         "m+": this.getMinutes(), //分         "s+": this.getSeconds(), //秒         "q+": Math.floor((this.getMonth() + 3) / 3), //季度         "S": this.getMilliseconds() //毫秒     };    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));    for (var k in o)    if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));    return fmt;}function send(event){var code; if(window.event){ code = window.event.keyCode; // IE }else{ code = e.which; // Firefox }if(code==13){ sendMsg();            }}function clearAll(){$("#content").empty();}</script></head><body>歡迎:${sessionScope.name }<div id="content"></div><input type="text" placeholder="請輸入要發送的資訊" id="msg" class="msg" onkeydown="send(event)"><input type="button" value="發送" class="send" onclick="sendMsg()" ><input type="button" value="清空" class="clear" onclick="clearAll()"></body></html>

  

  碰到的一些問題 以及處理的想法

1.之前在攔截器的請求裡面得不到session   使用從頁面傳進來的get方式得到參數uid(後來也沒改什麼 調試的時候發現可以得到session)

2.客服防止多處登陸的處理:

每次登陸擷取loginusermap 如果沒有該使用者 新增有就更新 然後替換map到session中
登陸攔截器校正登陸的使用者的sessionid和map裡的是否一致 不一致說明被擠 重新跳轉
loginUserMap.put(user.getFid(), sessionId);
request.getSession().getServletContext().setAttribute("loginUserMap", loginUserMap);

3.

按鈕嵌在右側的工具列 點擊固定只彈出一個聊天網頁
var op;
op = window.open("${webRoot}customerChat.json","newWin1");
op.focus();

4.

相容ios(看了要求標頭裡的sec-websocket-extensions不一致  就想的餿主意改頭  結果可用)
if(request.getHeaders().get("sec-websocket-extensions").contains("x-webkit-deflate-frame")){
List<String> list = new ArrayList<String>();
list.add("permessage-deflate");
request.getHeaders().remove("sec-websocket-extensions");
request.getHeaders().put("sec-websocket-extensions",list);
}

 

相容nginx
upstream tjxm.com{ 
server 127.0.0.1:8080;
}
server {
listen 80;
server_name localhost; 
location / {
proxy_pass http://tjxm.com/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

 

 

哈哈 第一次寫部落格  有點菜雞 websokcet部分也是從網上找的demo  

javaweb與websocket實現線上聊天功能總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.