Java 原生 WebSocket 仅H5支持
2018-03-22 本文已影响0人
酷酷的小k
简述:支持发送公告、发送指定用户及异地登录。
所需jar包:
javaee-api.jar
gson.jar
定义收发消息实体类:
package com.test.springWebsocket;
public class WebMessage {
/**
* 用户id
*/
private Long userId;
/**
* 用户名
*/
private String username;
/**
* 客户端标记
*/
private String clientMark;
/**
* 内容
*/
private String contents;
/**
* 消息类型,1.公告,2.点对点发消息,3.检查异地登录
*/
private String type;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getClientMark() {
return clientMark;
}
public void setClientMark(String clientMark) {
this.clientMark = clientMark;
}
public String getContents() {
return contents;
}
public void setContents(String contents) {
this.contents = contents;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
定义WebSocketServlet类:
package com.test.nativeWebsocket;
import com.google.gson.Gson;
import com.test.springWebsocket.WebMessage;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
/**
* 所需jar包:javaee-api.jar
* 客户端连接的url
*/
@ServerEndpoint("/native-socket-endpoint/{userId}/{username}/{clientMark}")
public class CustomWebSocketServlet {
private Long userId;
private String username;
private String clientMark;
private Session session;
public Long getUserId() {
return userId;
}
public String getUsername() {
return username;
}
public String getClientMark() {
return clientMark;
}
public Session getSession() {
return session;
}
/**
* 连接建立成功调用的方法
*
* @param session 可选的参数.session为与某个客户端的连接会话,需要通过它来给客户端发送数据
* @param userId userId
* @param username username
* @param clientMark clientMark
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") Long userId, @PathParam("username") String username, @PathParam("clientMark") String clientMark) {
WebMessage webMsg = new WebMessage();
webMsg.setUserId(userId);
webMsg.setUsername(username);
webMsg.setClientMark(clientMark);
webMsg.setType("3");
CustomWebSocketHandler.sendToUserMsg(webMsg);
this.session = session;
this.userId = userId;
this.username = username;
this.clientMark = clientMark;
CustomWebSocketHandler.addWebSocketServlet(this);
System.out.println(String.format("用户<%s>打开WebSocket连接...", username));
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
CustomWebSocketHandler.removeWebSocketServlet(this);
System.out.println(String.format("用户<%s>关闭WebSocket连接...", username));
}
/**
* 收到客户端消息后调用的方法
*
* @param msg 客户端发送过来的消息
* @param session 可选的参数
*/
@OnMessage
public void onMessage(String msg, Session session) {
WebMessage webMsg = new Gson().fromJson(msg, WebMessage.class);
if (webMsg.getUserId() == null) {
CustomWebSocketHandler.sendToAllMsg(webMsg);
} else {
CustomWebSocketHandler.sendToUserMsg(webMsg);
}
}
/**
* 发生错误时调用
*
* @param session Session
* @param error Throwable
*/
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
}
定义WebSocketHandler类:
package com.test.nativeWebsocket;
import com.google.gson.Gson;
import com.test.springWebsocket.WebMessage;
import java.util.ArrayList;
import java.util.List;
public class CustomWebSocketHandler {
private static List<CustomWebSocketServlet> userSocketList = new ArrayList<>();
public static synchronized void addWebSocketServlet(CustomWebSocketServlet webSocketServlet) {
userSocketList.add(webSocketServlet);
}
public static synchronized void removeWebSocketServlet(CustomWebSocketServlet webSocketServlet) {
userSocketList.remove(webSocketServlet);
}
/**
* 将消息发送给所有用户
*
* @param webMsg WebMessage
*/
public static void sendToAllMsg(WebMessage webMsg) {
String jsonStr = new Gson().toJson(webMsg);
for (CustomWebSocketServlet webSocketServlet : userSocketList) {
try {
//webSocketServlet.getSession().getBasicRemote().sendText(jsonStr);
webSocketServlet.getSession().getAsyncRemote().sendText(jsonStr);
} catch (Exception e) {
System.out.println(String.format("用户<%s>发送消息失败|消息体<%s>", webSocketServlet.getUsername(), jsonStr));
e.printStackTrace();
}
}
}
/**
* 将消息发送给指定用户
*
* @param webMsg WebMessage
*/
public static void sendToUserMsg(WebMessage webMsg) {
String jsonStr = new Gson().toJson(webMsg);
for (CustomWebSocketServlet webSocketServlet : userSocketList) {
if (webSocketServlet.getUserId().equals(webMsg.getUserId())) {
try {
//webSocketServlet.getSession().getBasicRemote().sendText(jsonStr);
webSocketServlet.getSession().getAsyncRemote().sendText(jsonStr);
} catch (Exception e) {
System.out.println(String.format("用户<%s>发送消息失败|消息体<%s>", webSocketServlet.getUsername(), jsonStr));
e.printStackTrace();
}
}
}
}
}
定义jsp页面RequestMapping:
/**
* 原生 WebSocket 页面
*
* @param request HttpServletRequest
* @return String
*/
@RequestMapping("/native-websocket.xhtm")
public String nativeWebsocket(HttpServletRequest request) {
String clientMark = (String) request.getSession().getAttribute("clientMark");
if (clientMark == null) {
clientMark = GenerateUtil.getUUID();
request.getSession().setAttribute("clientMark", clientMark);
}
Admin admin = (Admin) request.getSession().getAttribute("admin");
request.setAttribute("userId", admin.getId());
request.setAttribute("username", admin.getAdmin());
request.setAttribute("clientMark", clientMark);
return "nativeWebsocket/nativeWebsocket";
}
定义jsp页面:
<!DOCTYPE html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
String rootPath = request.getContextPath();
String wsBasePath = "ws://" + request.getServerName() + ":" + request.getServerPort() + rootPath + "/";
%>
<html>
<head>
<title>Native WebSocket</title>
<meta http-equiv="Expires" content="0"/>
<meta http-equiv="Cache" content="no-cache"/>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Cache-Control" content="no-cache"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="text/javascript" src="../../../static/js/plugins/jquery/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
var userId = "${userId}";
var username = "${username}";
var clientMark = "${clientMark}";
var wsBasePath = "<%=wsBasePath%>";
</script>
<style>
.c_box {
width: 800px;
height: 300px;
border: 1px solid;
overflow: auto;
}
</style>
</head>
<body>
<div>用户id:${userId}</div>
<div>用户名:${username}</div>
<div>
<span>公告:</span>
<input type="text" id="notice"/>
<input type="button" id="sendNotice" value="发送"/>
</div>
<div>
<span>用户id:</span>
<input type="text" id="toUserId"/>
<span>消息:</span>
<input type="text" id="toUserMsg"/>
<input type="button" id="sendToUser" value="发送"/>
</div>
<div>公告列表:</div>
<div id="noticeList" class="c_box"></div>
<div>消息列表:</div>
<div id="msgList" class="c_box"></div>
<script type="text/javascript" src="../../../static/js/nativeWebsocket/nativeWebsocket.js"></script>
</body>
</html>
定义JavaScript脚本:
var ws = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
ws = new WebSocket(wsBasePath + "native-socket-endpoint/" + userId + "/" + username + "/" + clientMark);
//连接发生错误的回调方法
ws.onerror = function () {
console.log("WebSocket连接错误");
};
//连接成功建立的回调方法
ws.onopen = function () {
console.log("WebSocket连接成功");
};
//接收到消息的回调方法
ws.onmessage = function (event) {
showMsg(JSON.parse(event.data));
};
//连接关闭的回调方法
ws.onclose = function () {
console.log("WebSocket连接关闭");
};
} else {
alert('当前浏览器 Not support WebSocket');
}
function closeSocket() {
if (ws == null || ws.readyState == 2 || ws.readyState == 3) {
return true;
}
ws.close();
}
function showMsg(webMsg) {
switch (webMsg['type']) {
//公告
case '1': {
var noticeHtm = '<div>' + webMsg['contents'] + '</div>';
$('#noticeList').append(noticeHtm);
$("#noticeList").scrollTop($("#noticeList")[0].scrollHeight);
break;
}
//点对点发消息
case '2': {
var msgHtm = '<div>' + webMsg['contents'] + '</div>';
$('#msgList').append(msgHtm);
$("#msgList").scrollTop($("#msgList")[0].scrollHeight);
break;
}
//检查异地登录
case '3': {
if (webMsg['clientMark'] != clientMark) {
closeSocket();
alert('您的账号在另一处登录');
}
break;
}
default: {
alert("WebSocket接收到未知消息...");
break;
}
}
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭WebSocket连接,防止连接还没断开就关闭窗口,server端会抛异常.
window.onbeforeunload = function () {
closeSocket();
};
$("#sendNotice").on("click", function () {
if (ws == null) {
alert('WebSocket连接未打开');
return true;
}
if (ws.readyState == 0) {
alert('WebSocket正在连接中,请稍后再发送消息');
return true;
}
if (ws.readyState == 2) {
alert('WebSocket连接正在关闭中,无法发送消息');
return true;
}
if (ws.readyState == 3) {
alert('WebSocket连接已关闭,无法发送消息');
return true;
}
var notice = $("#notice").val();
if (notice.length > 0) {
var webMsg = {
'contents': notice,
'type': '1'
};
ws.send(JSON.stringify(webMsg));
}
});
$("#sendToUser").on("click", function () {
if (ws == null) {
alert('WebSocket连接未打开');
return true;
}
if (ws.readyState == 0) {
alert('WebSocket正在连接中,请稍后再发送消息');
return true;
}
if (ws.readyState == 2) {
alert('WebSocket连接正在关闭中,无法发送消息');
return true;
}
if (ws.readyState == 3) {
alert('WebSocket连接已关闭,无法发送消息');
return true;
}
var toUserId = $("#toUserId").val();
var toUserMsg = $("#toUserMsg").val();
if (toUserId.length > 0 && toUserMsg.length > 0) {
var webMsg = {
'userId': toUserId,
'username': username,
'contents': toUserMsg,
'type': '2'
};
ws.send(JSON.stringify(webMsg));
}
});