Java和WebSocket開發網頁即時聊天室java
11、項目說明及簡介
1. 項目簡介
WebSocket是HTML5一種新的協議,它實現了瀏覽器與服務器全雙工通訊,這裏就將使用WebSocket來開發網頁聊天室,前端框架會使用AmazeUI,後臺使用Java,編輯器使用UMEditor。jquery
2. 涉及知識點
網頁前端(HTML5 + CSS3 + JS)和 JavaEE。git
3. 軟件環境
Tomcat8web
JavaEE7json
JDK7後端
Eclipse-JavaEE 或 MyEclipse
支持HTML5的瀏覽器
4. 相關框架
jQuery—1.X
妹子UI(AmazeUI-2.5.2)
百度富文本編輯器(UMeditor1_2_2)
5. 效果預覽
6.Git地址
http://git.oschina.net/loopcc/WebSocketChat
22、新建空項目
打開Eclipse JavaEE,新建一個名爲Chat的Dynamic Web Project,而後導入處理JSON格式字符串所須要的包,
1
2
3
4
5
6
|
commons-beanutils-1.8.0.jar
commons-collections-3.2.1.jar
commons-lang-2.5.jar
commons-logging-1.1.1.jar
ezmorph-1.0.6.jar
json-lib-2.4-jdk15.jar
|
把這幾個包放在/WEB-INF/lib目錄下,最後把項目發佈到Tomcat8服務器上,到此空項目就搭建完成了。
Eclipse的默認項目根目錄叫WebContent, MyEclipse默認項目根目錄叫WebRoot,
在本篇文檔中,咱們接下來用WebRoot做爲項目根目錄。
33、編寫前端頁面
這裏使用了AmazeUI框架,它是一個跨屏自適應的前端框架
消息輸入框使用了UMEditor,它是一個富文本在線編輯器,能讓咱們的消息內容多姿多彩。
在WebContent目錄下新建一個名爲index.jsp的頁面,
首先從AmazeUI官網下載壓縮包,而後解壓把assets文件夾拷貝到WebRoot目錄下,這樣咱們就能使用AmazeUI了。
再從UEditer官網下載Mini版的JSP版本壓縮包,解壓後把整個目錄拷貝到WebRoot目錄下,
接下來就能夠編寫前端代碼了,代碼以下(可按照本身的審美去編寫):
<%@ 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> <meta charset="UTF-8"> <title>Landing Page | Amaze UI Example</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="format-detection" content="telephone=no"> <meta name="renderer" content="webkit"> <meta http-equiv="Cache-Control" content="no-siteapp"/> <script src="assets/js/jquery.min.js"></script> <!-- 妹子UI相關資源 --> <link rel="alternate icon" type="image/png" href="assets/i/favicon.png"> <link rel="stylesheet" href="assets/css/amazeui.min.css"/> <script src="assets/js/amazeui.min.js"></script> <!-- UM相關資源 --> <link href="assets/umeditor/themes/default/css/umeditor.css" type="text/css" rel="stylesheet"> <script type="text/javascript" charset="utf-8" src="assets/umeditor/umeditor.config.js"></script> <script type="text/javascript" charset="utf-8" src="assets/umeditor/umeditor.min.js"></script> <script type="text/javascript" src="assets/umeditor/lang/zh-cn/zh-cn.js"></script> </head> <body> <header class="am-topbar am-topbar-fixed-top"> <div class="am-container"> <h1 class="am-topbar-brand"> <a href="#">聊天室</a> </h1> <div class="am-collapse am-topbar-collapse" id="collapse-head"> <ul class="am-nav am-nav-pills am-topbar-nav"> <li class="am-active"><a href="#">首頁</a></li> <li><a href="#">項目</a></li> </ul> <div class="am-topbar-right"> <button class="am-btn am-btn-secondary am-topbar-btn am-btn-sm"><span class="am-icon-pencil"></span> 註冊</button> </div> <div class="am-topbar-right"> <button class="am-btn am-btn-primary am-topbar-btn am-btn-sm"><span class="am-icon-user"></span> 登陸</button> </div> </div> </div> </header> <div id="main"> <!-- 聊天內容展現區域 --> <div id="ChatBox" class="am-g am-g-fixed" > <div class="am-u-lg-12" style="height:400px;border:1px solid #999;overflow-y:scroll;"> <ul id="chatContent" class="am-comments-list am-comments-list-flip"> <li class="am-comment am-comment-success" style="margin-right:20%;"> <a href=""> <img class="am-comment-avatar" src="assets/images/other.jpg" alt=""/> </a> <div class="am-comment-main" > <header class="am-comment-hd"> <div class="am-comment-meta"> <a href="#link-to-user" class="am-comment-author">某人</a> <time datetime="" title="">2014-7-12 15:30</time> </div> </header> <div class="am-comment-bd">此處是消息內容</div> </div> </li> <li class="am-comment am-comment-flip am-comment-warning" style="margin-left:20%;"> <a href=""> <img class="am-comment-avatar" src="assets/images/xia.jpg" alt=""/> </a> <div class="am-comment-main" > <header class="am-comment-hd"> <div class="am-comment-meta"> <a href="#link-to-user" class="am-comment-author">某人</a> <time datetime="" title="">2014-7-12 15:30</time> </div> </header> <div class="am-comment-bd">此處是消息內容</div> </div> </li> </ul> </div> </div> <!-- 聊天內容發送區域 --> <div id="EditBox" class="am-g am-g-fixed"> <!--style給定寬度能夠影響編輯器的最終寬度--> <script type="text/plain" id="myEditor" style="width:100%;height:140px;"></script> <button id="send" type="button" class="am-btn am-btn-primary am-btn-block">發送</button> </div></div><script type="text/javascript">$(function(){ //窗口大小變化時,調整顯示效果 $("#ChatBox div:eq(0)").height($(this).height()-290); $(window).resize(function(){ $("#ChatBox div:eq(0)").height($(this).height()-290); }); //實例化編輯器 var um = UM.getEditor('myEditor',{ initialContent:"請輸入聊天信息...", autoHeightEnabled:false, toolbar:[ 'source | undo redo | bold italic underline strikethrough | superscript subscript | forecolor backcolor | removeformat |', 'insertorderedlist insertunorderedlist | selectall cleardoc paragraph | fontfamily fontsize' , '| justifyleft justifycenter justifyright justifyjustify |', 'link unlink | emotion image video | map' ] });}); </script> </body> </html>
編寫完成以後啓動Tomcat服務器,而後訪問index.jsp ,會看到設計好的頁面效果。
上面的實例代碼裏有兩條示例消息,一條別人的消息,一條本身的消息。
44、消息流轉
聊天室的核心就是把一我的的消息廣播給全部人,咱們這裏使用WebSocket技術讓全部人的瀏覽器都與服務器連在一塊兒,當一我的發送消息到服務器後,服務器把消息轉發給全部人,包括本身,
這樣每一個人的瀏覽器就都能看到這條消息。
出現一條新消息時必備的3個屬性:【發言人暱稱】,【消息內容】和【發送時間】。
爲了區別消息是否爲本身,咱們還須要在消息中加入一項屬性:【是否本身】。
其中【發送時間】和【是否本身】能夠由服務器進行處理,那麼發言人只須要告訴服務器【暱稱】與【消息內容】便可:
//瀏覽器發給服務器的數據:
{
nickname:"風清揚",
content:"HelloWorld"
}
//瀏覽器接收的數據:
{
nickname:"風清揚",
content:"HelloWorld",
date:"2016.04.01 14:05:22",
isSelf:true
}
55、JS添加新消息
頁面樣式已經設計好,而真正聊天的時候確定須要不斷展現新的消息,爲了方便控制,咱們使用JavaScript統一消息的建立過程。
頁面中表明消息的li元素只保留一份,把它做爲消息的模板,默認隱藏,每當新消息到來,咱們就複製一份模板,修改其中的屬性,追加到列表中去展現,給幾個元素加上獨有的標記:
【暱稱】:ff="nickname" 【內容】:ff="content" 【時間】:ff="msgdate"
<li id="msgtmp" class="am-comment" style="display:none;"> <a href=""> <img class="am-comment-avatar" src="assets/images/other.jpg" alt=""/> </a> <div class="am-comment-main" > <header class="am-comment-hd"> <div class="am-comment-meta"> <a ff="nickname" href="#link-to-user" class="am-comment-author">某人</a> <time ff="msgdate" datetime="" title="">2014-7-12 15:30</time> </div> </header> <div ff="content" class="am-comment-bd">此處是消息內容</div> </div> </li>
使用JS克隆一份模板,設置克隆體裏面的數據,最終追加到列表中:
//向聊天窗口加入一條消息
function addMessage(msg){
var box = $("#msgtmp").clone(); //複製一份模板,取名爲box
box.show(); //設置box狀態爲顯示
box.appendTo("#chatContent"); //把box追加到聊天面板中
box.find('[ff="nickname"]').html(msg.nickname); //在box中設置暱稱
box.find('[ff="msgdate"]').html(msg.date); //在box中設置時間
box.find('[ff="content"]').html(msg.content); //在box中設置內容
box.addClass(msg.isSelf? 'am-comment-flip':''); //右側顯示
box.addClass(msg.isSelf? 'am-comment-warning':'am-comment-success');//顏色
box.css((msg.isSelf? 'margin-left':'margin-right'),"20%");//外邊距
$("#ChatBox div:eq(0)").scrollTop(999999); //滾動條移動至最底部
}
66、編寫後臺代碼
新建一個com.zhenzhigu.chat的包,在包中建立一個名爲ChatServer的類,從JavaEE 7開始就統一了WebSocket的API,所以不管是什麼服務器,用Java寫的代碼都是同樣的,代碼以下:
package com.zhenzhigu.chat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Vector; 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 net.sf.json.JSONObject; @ServerEndpoint("/websocket") public class ChatServer { private static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static Vector<Session> room = new Vector<Session>(); /** * 用戶接入 * @param session 可選 */ @OnOpen public void onOpen(Session session){ room.addElement(session); } /** * 接收到來自用戶的消息 * @param message * @param session */ @OnMessage public void onMessage(String message,Session session){ //把用戶發來的消息解析爲JSON對象 JSONObject obj = JSONObject.fromObject(message); //向JSON對象中添加發送時間 obj.put("date", df.format(new Date())); //遍歷聊天室中的全部會話 for(Session se : room){ //設置消息是否爲本身的 obj.put("isSelf", se.equals(session)); //發送消息給遠程用戶 se.getAsyncRemote().sendText(obj.toString()); } } /** * 用戶斷開 * @param session */ @OnClose public void onClose(Session session){ room.remove(session); } /** * 用戶鏈接異常 * @param t */ @OnError public void onError(Throwable t){ } }
77、前端後端交互
後臺寫完了,前臺要用WebSocket鏈接後臺,須要新建一個WebSocket對象,而後就能夠和服務器端進行交互,從瀏覽器發送消息給服務器端,同時要驗證輸入框的內容是否爲空,而後接受服務端發送的消息,把它們動態地添加到聊天內容框中。
記得寫到文檔就緒函數中
//本身的暱稱
var nickname = "風清揚"+Math.random();
//創建一條與服務器之間的鏈接
var socket = new WebSocket("ws://${pageContext.request.getServerName()}:${pageContext.request.getServerPort()}${pageContext.request.contextPath}/websocket");
//接收服務器的消息
socket.onmessage=function(ev){
var obj = eval( '('+ev.data+')' );
addMessage(obj)
}
//發送按鈕被點擊時
$("#send").click(function(){
if (!um.hasContents()) { // 判斷消息輸入框是否爲空
// 消息輸入框獲取焦點
um.focus();
// 添加抖動效果
$('.edui-container').addClass('am-animation-shake');
setTimeout("$('.edui-container').removeClass('am-animation-shake')", 1000);
} else {
//獲取輸入框的內容
var txt = um.getContent();
//構建一個標準格式的JSON對象
var obj = JSON.stringify({
nickname:nickname,
content:txt
});
// 發送消息
socket.send(obj);
// 清空消息輸入框
um.setContent('');
// 消息輸入框獲取焦點
um.focus();
}
});
到這步,簡單的網頁聊天室就完成了,你能夠多開幾個窗口或在局域網中邀請小夥伴們來一塊兒測試。
88、思考
本次項目只是簡單的實現羣體聊天功能,還有不少功能能夠增長,例如頭像上傳、一對一聊天等,請考慮如何完善咱們的聊天室。