WebSocket簡單聊天
剛學習了WebSocket ,寫了一個簡單的聊天功能,在這裡記錄一下;想學習的也可以參考。
WebSocket協議是基於TCP的一種新的網路協議。它實現了瀏覽器與伺服器全雙工(full-duplex)通訊——允許伺服器主動傳送資訊給客戶端。
首先給出程式碼,執行一下看看效果:
(介面有些醜,忽略這些細節,之後再進行美化;)
index.jsp 這是登入頁面,獲取聊天時的暱稱;
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登入</title>
</head>
<style>
.container{
width: 400px;
height : 600px;
background: navajowhite;
margin: 0 auto;
text-align: center;
}
.pic{
margin: 0 auto;
width:100px;
height: 100px;
border-radius: 50px;
background:gray;
}
#name{
width: 200px;
height: 50px;
margin-top: 200 px;
}
button{
text-decoration: none;
background: darkcyan;
width: 200px;
height: 50px;
}
</style>
<script type="text/javascript" src="jquery/jquery-2.2.4.min.js" ></script>
<body>
<header>聊天</header>
<div class="container">
<form action="/UserServlet" method="post" id="login">
<div class="pic">
</div>
<div class="login">
<div class="name">
<input type="text" name="nick" id="name"/>
</div>
<div>
<!-- <a href="javascript:goChat()">登入</a>-->
<button class="but" onclick="goChat()">登入</button>
</div>
</div>
</form>
</div>
</body>
<script type="text/javascript">
function goChat(){
$("#login").submit();
}
</script>
</html>
chatroom.jsp 這是聊天的頁面,能看到所有使用者傳送的訊息:
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2017/10/11 0011
Time: 18:43
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<style type="text/css">
.container{
width: 400px;
height: 600px;
background: navajowhite;
margin: 0 auto;
text-align: center;
}
.message{
width:400px;
height: 400px;
position: absolute;
top:100px;
background: indianred;
}
li{
margin: 0;
background: khaki;
width: 300px;
height: 20px;
list-style:none;
}
.msg{
position: absolute;
width:400px;
height: 50px;
top:550px;
background: indianred;
}
input[name = "msg"]{
width: 200px;
height: 40px;
}
button{
width: 90px;
height: 47px;
}
</style>
<script type="text/javascript" src="jquery/jquery-2.2.4.min.js" ></script>
<body>
<div class="container">
<div class="message">
<ul class="list">
</ul>
</div>
<% String nick = (String)request.getAttribute("nick");%>
<div class="msg">
<input type="text" name="msg" id="msg" value="" /><button class="send" value="">傳送</button>
</div>
</div>
</body>
<script type="text/javascript">
var ws = null;
if(WebSocket){
ws = new WebSocket("ws://localhost:8080/chat");
}else{
alert("瀏覽器不支援");
}
ws.onopen = function(){
ws.send("使用者<%=nick%>加入聊天室");
}
ws.onmessage = function(event){
showMessage(event.data);
}
function showMessage(msg){
var message = $(".list");
var html = message.html();
html += "<li>"+msg+"</li>";
message.html(html);
message.scrollTop(message[0].scrollHeight);
}
$(".send").click(function () {
var msg = $(this).siblings("input").val();
ws.send("<%=nick%>說:"+msg);
$(this).siblings("input").val("");
})
</script>
</html>
UserServlet 用於轉發使用者名稱,之後可以用框架實現:
package com.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/UserServlet")
public class UserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String nick = request.getParameter("nick");
request.setAttribute("nick",nick);
request.getRequestDispatcher("/chatroom.jsp").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
ChatServer 聊天的伺服器 用於接收發送訊息
package com.websocket;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/chat")
public class ChatServer {
private Session session;
// private static Map<String,ChatServer> map = new HashMap(String,ChatServer);
private static CopyOnWriteArraySet<ChatServer> servers = new CopyOnWriteArraySet<ChatServer>();
@OnOpen
public void onOpen(Session session){
this.session = session;
servers.add(this);
System.out.println("建立連線"+session.getId());
}
@OnMessage
public void onMessage(String msg){
// try {
// this.session.getBasicRemote().sendText(msg);
// } catch (IOException e) {
// e.printStackTrace();
// }
System.out.println("接受資訊:"+msg);
//向所有的使用者傳送訊息
try{
for (ChatServer server:servers){
server.session.getBasicRemote().sendText(msg);
}
}catch (IOException e){
e.printStackTrace();
}
}
@OnError
public void onError(Throwable error){
System.out.println("錯誤:");
error.printStackTrace();
}
@OnClose
public void onClose(){
servers.remove(this);
}
}
簡單說明一下執行的過程:
在登入介面,輸入使用者名稱,登入, 會通過表單提交的UserServlet,UserServlet再轉發到chatroom.jsp
在載入的時候,建立了一個websocket物件
ws = new WebSocket(“ws://localhost:8080/chat”);
就是這句, 這裡我有一個疑惑,在IDEA中要直接寫ChatServer的路徑, 在Eclipse 要加上專案名;這個問題糾結了好久,還是沒有答案;
找到ChatServer,如果連線成功了 ,就會執行 onopen方法 ,控制檯輸出對應的資料,
同樣,jsp中的 ws.onopen的方法也會執行; ws.send(“使用者<%=nick%>加入聊天室”); 這句就是向服務端傳送了訊息, 再服務端通過 onMessage 接收資料,控制檯輸出; 這樣就可以簡單的傳送訊息;
不過這樣只能是自己看到訊息 ,需要對每一個線上的使用者都發送訊息
private static CopyOnWriteArraySet servers = new CopyOnWriteArraySet(); 用來儲存每個使用者的 websocket ;
servers.add(this); 使用者連線時,向set中新增一個websocket
try{
for (ChatServer server:servers){
server.session.getBasicRemote().sendText(msg);
}
}catch (IOException e){
e.printStackTrace();
}
通過遍歷servers中的websocket,向每一使用者傳送訊息,
這樣, 簡單的聊天 就實現了;