您好,登錄后才能下訂單哦!
websocket 是一種長連接方式,可以幫助我們通過瀏覽器和服務端進行長連接,用于可以即時通訊,推送消息等
Java 中 WebSocket 使用比較簡單, java 給我們提供了響應的 api 用于處理建立連接,收消息,關閉連接等
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
? xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
? <modelVersion>4.0.0</modelVersion>
? <groupId>com.qianfeng</groupId>
? <artifactId>testwebsocket</artifactId>
??<packaging>war</packaging>
? <version>1.0-SNAPSHOT</version>
? <name>testwebsocket Maven Webapp</name>
? <url>http://maven.apache.org</url>
? <dependencies>
??? <dependency>
????? <groupId>junit</groupId>
????? <artifactId>junit</artifactId>
????? <version>3.8.1</version>
????? <scope>test</scope>
??? </dependency>
<!--servlet3.1規(guī)范-->
??? <dependency>
????? <groupId>javax.servlet</groupId>
????? <artifactId>javax.servlet-api</artifactId>
????? <version>3.1.0</version>
??? </dependency>
???? <dependency>
????? <groupId>javax.servlet.jsp</groupId>
????? <artifactId>jsp-api</artifactId>
????? <version>2.2</version>
??? </dependency>
??? <!-- https://mvnrepository.com/artifact/javax.websocket/javax.websocket-api
???? websocket 依賴
???? -->
??? <dependency>
????? <groupId>javax.websocket</groupId>
????? <artifactId>javax.websocket-api</artifactId>
????? <version>1.1</version>
????? <scope>provided</scope>
??? </dependency>
??? <!--用于處理json 數(shù)據(jù)的-->
??? <dependency>
????? <groupId>net.sf.json-lib</groupId>
????? <artifactId>json-lib</artifactId>
????? <version>2.4</version>
??? </dependency>
? </dependencies>
? <build>
??? <finalName>testwebsocket</finalName>
? </build>
</project>
注意 maven 工程的 xml 文件的版本應該是3.0+
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
???????? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
???????? xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
???????? http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
???????? version="3.1">
</web-app>
package com.qianfeng.servlet;
//
//??????????????????????????? _ooOoo_?
//?????????????????????????? o8888888o?
//?????????????????????????? 88" . "88?
//?????????????????????????? (| -_- |)?
//??????????????????????????? O\ = /O?
// ???????????????????????____/`---'\____?
//????????????????????? .?? ' \\| |// `.?
//?????????????????????? / \\||| : |||// \?
//???????????????????? / _||||| -:- |||||- \?
//?????????????????????? | | \\\ - /// | |?
//???????????????????? | \_| ''\---/'' | |?
//????????????????????? \ .-\__ `-` ___/-. /?
//?????????????????? ___`. .' /--.--\ `. . __?
//??????????????? ."" '< `.___\_<|>_/___.' >'"".?
//?????????????? | | : `- \`.;`\ _ /`;.`/ - ` : | |?
//???????????????? \ \ `-. \_ __\ /__ _/ .-` / /?
//???????? ======`-.____`-.___\_____/___.-`____.-'======?
//??????????????????????????? `=---='?
//?
//???????? .............................................?
//????????????????? 佛祖鎮(zhèn)樓????????????????? BUG辟易?
//????????? 佛曰:?
//????????????????? 寫字樓里寫字間,寫字間里程序員;?
//????????????????? 程序人員寫程序,又拿程序換酒錢。?
//????????????????? 酒醒只在網(wǎng)上坐,酒醉還來網(wǎng)下眠;?
//????????????????? 酒醉酒醒日復日,網(wǎng)上網(wǎng)下年復年。?
//????????????????? 但愿老死電腦間,不愿鞠躬老板前;?
//????????????????? 奔馳寶馬貴者趣,公交自行程序員。?
//????????????????? 別人笑我忒瘋癲,我笑自己命太賤;?
//?
import net.sf.json.JSONObject;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
?* Created by jackiechan on 2018/2/5/下午2:08
?*
?* WebSocket 的處理類
?* 狀態(tài) 注解:
?*? 連接? OnOpen
?*? 收到消息 OnMessage
?*? 關閉連接 OnClose
?*? 錯誤 OnError
?*? 這是一個多例對象,每一次連接都會創(chuàng)建一個對象
?*/
@ServerEndpoint("/websocket/{name}")
public class WebSocket {
??? private String name;
??? private Session session;
??? private static Map<String,Session>? allClients=new ConcurrentHashMap();//用于記錄所有的用戶和連接之間的關系
??? public WebSocket() {
??????? System.out.println("構(gòu)造方法執(zhí)行了");
??? }
??? /**
???? * 當打開連接的時候,代表有人連接我們了
???? * @param name ?此處的 name 代表類注解上面的訪問路徑后的name, 我們此處做測試,根據(jù)用戶傳過來的名字做區(qū)分, 也可以通過 ip 等區(qū)分
???? * @param session 當前連接的 session
???? * @throws Exception
???? */
??? @OnOpen//此注解的作用是聲明當前方法是當建立連接的時候調(diào)用
??? public void onOpen(@PathParam("name") String name, Session session) throws? Exception{
??????? this.name=name;
??????? this.session = session;
??????? allClients.put(name, session);//將當前連接放入到 map中
??? }
??? /**
???? * 收到消息的時候,此處應該填寫自己的業(yè)務邏輯,我們服務端只是負責收到消息,實際開發(fā)中可能是兩個人在聊天,我們這邊收到消息后,應該當消息轉(zhuǎn)發(fā)給接受者
???? * 接收者到底是誰,一般情況下,如果是和客服聊天,我們這里應該是另外一個客服的連接頁面,也是連接這里,然后將所有的客服存起來,隨機或者按照某種規(guī)則選擇客服進行通信
???? * 如果是用戶指定的人,那么在消息中應該會帶有標記,比如發(fā)送給哪個人,我們?nèi)〕鰜碇笳业綄Ψ降倪B接,發(fā)過去即可
???? * @param message 收到的消息,實際上,收到的消息中應當包含消息最終要發(fā)給誰,這樣服務端就可以知道轉(zhuǎn)發(fā)給誰了
???? */
??? @OnMessage//此注解的作用是當收到消息的時候執(zhí)行
??? public void onMessage(Session session ,String message) {
??????? System.out.println(session);
??????? //------實際開發(fā)中替換為自己的業(yè)務邏輯-------
??????? System.out.println("當前收到的消息是:"+message);
??????? JSONObject jsonObject = JSONObject.fromObject(message);
??????? String toName = jsonObject.getString("toName");//接收者
??????? String content = jsonObject.getString("content");//真正的消息內(nèi)容,但是我們將這個內(nèi)容修改后發(fā)過去,因為用戶在頁面需要判斷出是誰給我發(fā)的消息,所以還需要一個發(fā)送者的信息
??????? sendMessage(toName,"來自: "+name+" 的消息,內(nèi)容是: "+content);//此處直接拼接的字符串,沒有弄成 json, 實際開發(fā)請自行處理
??? }
??? /**
???? * 當服務端出現(xiàn)異常的時候,比如,用戶直接非法斷開連接導致 socket 出現(xiàn)異常
???? * @param session 出現(xiàn)異常的連接
???? * @param e 異常內(nèi)容
???? */
??? @OnError//此注解的作用是當出現(xiàn)異常的時候執(zhí)行
??? public void onError(Session session,Throwable e) {
??????? try {
??????????? session.close();
??????????? allClients.remove(name);
??????? } catch (IOException e1) {
??????????? e1.printStackTrace();
??????? }
??????? e.printStackTrace();
??? }
??? /**
???? * 當連接關閉的時候
???? */
??? @OnClose//此注解的作用是 當連接關閉的時候執(zhí)行
??? public void onClose(Session session) {
??????? System.out.println(session);
??????? allClients.remove(name);//將當前連接移除
??? }
??? /**
???? * 發(fā)送消息
???? * @param name 接收方的名字
???? * @param message 發(fā)送的內(nèi)容
???? */
??? public void sendMessage(String name, String message) {
??????? Session toSession = allClients.get(name);//找到目標所在對應的 session
??????????? if (toSession != null) {
??????????????? toSession.getAsyncRemote().sendText(message);// 發(fā)送消息
??????????????? return;
??????????? }
??????????? session.getAsyncRemote().sendText("對方不在線");//如果對方不在線,告訴當前用戶
??? }
??? public String getName() {
??????? return name;
??? }
??? public void setName(String name) {
??????? this.name = name;
??? }
??? public Session getSession() {
??????? return session;
??? }
??? public void setSession(Session session) {
??????? this.session = session;
??? }
??? public static Map<String, Session> getAllClients() {
??????? return allClients;
??? }
??? public static void setAllClients(Map<String, Session> allClients) {
??????? WebSocket.allClients = allClients;
??? }
}
html 中比較簡單,就是單純聊天,沒有做很復雜的名單列表,聊天記錄列表等功能,
使用的時候 開多個瀏覽器, 各自填寫自己的名字,連接后, 就可以填寫收消息人的名字,發(fā)送消息了
<!DOCTYPE html>
<html lang="en">
<head>
??? <meta charset="UTF-8">
??? <title>Title</title>
??? <script type="text/javascript">
??????? var websocket = null;
??????? function abc() {
??????????? //var username = localStorage.getItem("name");
??????????? var username=document.getElementById("me").value;
??????????? //判斷當前瀏覽器是否支持WebSocket
??????????? if ('WebSocket' in window) {
??????????????? websocket = new WebSocket("ws://" + document.location.host + "/websocket/"+username);
??????????? } else {
??????????????? alert('當前瀏覽器 Not support websocket')
??????????? }
??????????? //連接發(fā)生錯誤的回調(diào)方法
??????????? websocket.onerror = function() {
??????????????? setMessageInnerHTML("WebSocket連接發(fā)生錯誤");
??????????? };
??????????? //連接成功建立的回調(diào)方法
??????????? websocket.onopen = function() {
??????????????? setMessageInnerHTML("WebSocket連接成功");
??????????? }
??????????? //接收到消息的回調(diào)方法
??????????? websocket.onmessage = function(event) {
??????????????? setMessageInnerHTML(event.data);
??????????? }
??????????? //連接關閉的回調(diào)方法
??????????? websocket.onclose = function() {
??????????????? setMessageInnerHTML("WebSocket連接關閉");
??????????? }
??????????? //監(jiān)聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。
??????????? window.onbeforeunload = function() {
??????????????? closeWebSocket();
??????????? }
??????? }
??????? /**
???????? * 發(fā)送消息
???????? */
??????? function sendmessage() {
??????????? var toName=document.getElementById("to").value;
??????????? if (websocket!=null) {
??????????????? var content=document.getElementById("content").value;
??????????????? var message='{"toName":"'+toName+'","content":"'+content+'"}';//將發(fā)送的內(nèi)容拼接為 json 字符串,服務端用于解析好處理
??????????????? websocket.send(message);
??????????? }
??????? }
??????? //關閉WebSocket連接
??????? function closeWebSocket() {
??????????? if (websocket!=null) {
??????????????? websocket.close();
??????????? }
??????? }
??????? function setMessageInnerHTML(data) {
??????????? document.getElementById("neirong").innerHTML = data;
??????? }
??? </script>
</head>
<body>
?用戶名:<input type="text" id="me" /> <button onclick="abc()"> 連接</button><br>
?<!--實際接收者應該由用戶選擇,或者由系統(tǒng)安排,比如客服的話,應該是服務端已經(jīng)存儲了所有在線的客服,用戶只需要發(fā)送消息即可,如果是兩個用戶聊天,則應該有用戶列表,選擇后指定目標-->
??? 接收者:<input type="text" id="to" /><br>
??? 內(nèi)容:<input type="text" id="content" /><br>
??? <button onclick="sendmessage()">發(fā)送</button><br>
<br>
<br>
<br>
<span id="neirong"></span>
</body>
</html>
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。