介绍
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信–允许服务器主动发送信息给客户端。
前端代码
实现连接后端,接收发送消息(私发,群发)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CharBox</title>
</head>
<body>
<div id="connection">
<!--建立连接-->
<input type="text" name="username">
<button id="connBtn">Connection</button>
</div>
<div id="sendAll">
<!--群发消息-->
<input id="allMsg" type="text" name="msg">
<button id="allBtn">SendAll</button>
</div>
<div id="sendTo">
<!--私发消息-->
<input id="toMsg" type="text" name="lineMsg">
<select id="userList">
<option>请选择</option>
</select>
<button id="toBtn">SendTo</button>
</div>
<!--消息展示-->
<div class="content">
<div class="name"></div>
<div class="info"></div>
</div>
<!--引入JQuery-->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
<!--实现WebSocket-->
<script type="text/javascript">
var webSocket = null
var userList = []
var url = "ws://localhost:8080/char/"
// 寻找服务器建立连接
$("#connBtn").on('click', function(){
// 获取要连接的用户
var username = $("input[name='username']").val()
// 添加私人
userList.push(username)
$("#userList").empty()
$.each(userList, function(index, item){
$("#userList").append("<option>"+item+"</option>")
})
if ("WebSocket" in window) {
// 浏览器支持WebSocket
var ws = new WebSocket(url+username)
console.log("连接创建成功")
webSocket = ws
// 服务端的返回
webSocket.onmessage = function(cvt) {
var rec_msg = cvt.data // Json格式
var jsonMsg = JSON.parse(rec_msg)
var msg = jsonMsg.msg
switch (msg) {
case "sendAll":
sendAll(jsonMsg);
break;
case "sendTo":
sendTo(jsonMsg);
break;
case "onLineUsers":
onLineUsers(jsonMsg);
break;
}
}
} else {
// 浏览器不支持WebSocket
console.log("浏览器不支持WebSocket")
}
})
var content = $(".content");
function sendAll(jsonMsg) {
// 接受到服务器的群发消息,把消息显示到聊天窗口
var jsonObj = JSON.parse(jsonMsg.data);
console.log(jsonObj)
var infoContent = jsonObj.info;
var infoFromUser = jsonObj.fromUser;
var infoTime = jsonObj.time;
var contentDiv = content.clone();//又多了一个div class=info
contentDiv.find(".name").text(infoFromUser+" "+infoTime);
contentDiv.find(".info").text(infoContent);
$(".content").parent().append(contentDiv);
}
function sendTo(jsonMsg) {
var jsonObj = JSON.parse(jsonMsg.data)
console.log(jsonObj)
var infoContent = jsonObj.info;
var infoFromUser = jsonObj.fromUser;
var infoTime = jsonObj.time;
var contentDiv = content.clone();//又多了一个div class=info
contentDiv.find(".name").text(infoFromUser+" "+infoTime);
contentDiv.find(".info").text(infoContent);
// 再添加一个DIV
$(".content").parent().append(contentDiv);
}
function onLineUsers(jsonMsg) {
var users = JSON.parse(jsonMsg.data);
$("#userList").empty();
$.each(users, function(index, item){
$("#userList").append("<option>"+item+"</option>")
})
}
// 群发消息
$("#allBtn").on('click', function(){
var info = $("input[name='msg']").val()
var sendMsg = {
"msg": "sendAll",
"data": info
}
webSocket.send(JSON.stringify(sendMsg))
console.log("消息发送")
})
// 私发消息
$("#toBtn").on('click', function(){
var info = $("input[name='lineMsg']").val()
var toUser = $("#userList").val()
var sendMsg = {
"msg": "sendTo",
"data": {
"toUser": toUser,
"info": info
}
}
webSocket.send(JSON.stringify(sendMsg))
console.log("消息私发")
})
</script>
</body>
</html>
后端代码
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
//连接地址
@ServerEndpoint("/char/{username}")
public class CharServer2 {
// 群聊服务器
private Session session; // 客户端连接 产生多个会话 多个session
private String username; //
// 通过类变量 存储通话对象
private static Map<String, CharServer2> clients = new ConcurrentHashMap<String, CharServer2>(); // 存储会话对象
private static int onlineCount = 0; // 会话个数
private Set<String> clientsName = null;
@OnOpen
public void onOpen(@PathParam(value = "username")String username, Session session) throws IOException {
this.session = session;
System.out.println("建立连接:" + username);
this.username = username;
// 有客户端连接 将客户端会话对象存储到clients对象里
clients.put(username, this);
// 会话个数添加
addOnlineCount();
// 更新用户列表 将clients对象里的用户转发到说有客户端去渲染展示
sendUserList();
}
public static synchronized void addOnlineCount() {
// 会话数增加
CharServer2.onlineCount++;
}
public static synchronized void subOnlineCount() {
// 会话数减少
CharServer2.onlineCount--;
}
// 发送用户列表
public void sendUserList() {
Set<String> userSet = this.clients.keySet();
Commond sendMsg = new Commond();
sendMsg.setMsg("onLineUsers");
sendMsg.setData(JSON.toJSONString(userSet));
// 循环给每个对话发送会话用户列表
for (CharServer2 item: clients.values()) {
item.session.getAsyncRemote().sendText(JSON.toJSONString(sendMsg));
}
}
@OnMessage
// 转发信息
public void onMessage(@PathParam(value="username")String username,String message) throws IOException {
// 解析message 转成JSON格式
System.out.println(message);
JSONObject jsonTo = JSON.parseObject(message);
// 获取msg的值
String msg = jsonTo.getString("msg");
// 获取data的值
String data = jsonTo.getString("data");
if("sendAll".equals(msg)){
// 群发
sendMessageAll(data);
}else if("sendTo".equals(msg)){
// 私发
sendMessageTo(data);
}
}
// 私发
public void sendMessageTo(String data) throws IOException {
// 创建返回信息对象
Commond sendMsg = new Commond();
// 设置群发或者私发
sendMsg.setMsg("sendTo");
// 将传来的数据转为JSON格式
JSONObject jsonObj = JSON.parseObject(data);
// 创建JSON对象
JSONObject obj = new JSONObject();
// 添加私发的信息
obj.put("info",jsonObj.getString("info"));
// 添加发送者
obj.put("fromUser",this.username);
// 添加发送时间
obj.put("time",new Date());
// JSON对象设置为Commond的data
sendMsg.setData(JSON.toJSONString(obj));
// 私发信息 对话服务器存储的会话去做循环 找到要发送的人的会话 发送信息过去
for (CharServer2 item : clients.values()) {
// 如果会话对象中存在要发送信息的用户toUser 则发送信息
if (item.username.equals(jsonObj.getString("toUser")) )
item.session.getAsyncRemote().sendText(JSON.toJSONString(sendMsg));
}
}
// 群发
public void sendMessageAll(String message) throws IOException {
// 创建会话对象
Commond sendMsg = new Commond();
// 设置群发或者私发
sendMsg.setMsg("sendAll");
// 创建JSON对象
JSONObject obj = new JSONObject();
// 设置相关信息
obj.put("info",message);
obj.put("fromUser",this.username);
obj.put("time",new Date());
sendMsg.setData(JSON.toJSONString(obj));
// 循环发送信息给会话里存在的对象
for (CharServer2 item : clients.values()) {
item.session.getAsyncRemote().sendText(JSON.toJSONString(sendMsg));
}
}
@OnClose
public void onClose(@PathParam(value="username")String username){
System.out.println("连接下线");
// 移除下线的用户
clients.remove(username);
// 在线会话数减一
subOnlineCount();
}
@OnError
public void onError(Throwable t){
System.out.println("连接错误");
}
}
// 返回数据对象
class Commond{
String code; // 码
String msg; // 验证信息
String data; // 返回信息
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Commond(String code, String msg, String data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Commond() {
}
}