效果图----请各位看官轻些喷
![](https://img.haomeiwen.com/i16553236/13ba73d2678d0090.png)
![](https://img.haomeiwen.com/i16553236/e4c6f15840c60883.png)
前端+css+js
<%@page contentType="text/html;charset=UTF-8"language="java" %>
<html !DOCTYPE html>
<head>
<meta charset="utf-8">
<title>websocket</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
//以下内容换成自己的路径
<link rel="stylesheet" href="${pageContext.request.contextPath }/static/layui/css/layui.css"/>
<script type="text/javascript" src="${pageContext.request.contextPath }/static/js/jquery-3.4.0.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/static/layui/layui.js"></script>
<style>
.fatherDiv {
height:80%;
width:70%;
position:relative;
top:20px;
left:100px;
border:1px black solid;
}
.otherSay {
text-align:left;
}
.mine {
text-align:right;
}
.users {
height:40px;
line-height:40px;
background-color:#EAEAEA;
}
.users::before {
content:" ";
background-image:url('<%=request.getContextPath()%>/static/images/face.jpg');
background-size:30px 30px;
display:inline-block;
height:30px;
width:30px;
vertical-align:middle;
margin:0 10px;
}
.otherSay::before {
content:" ";
background-image:url('<%=request.getContextPath()%>/static/images/face.jpg');
background-size:30px 30px;
display:inline-block;
height:30px;
width:30px;
vertical-align:middle;
margin:0 10px;
}
.mine::after {
content:" ";
background-image:url('<%=request.getContextPath()%>/static/images/girl.jpeg');
background-size:30px 30px;
display:inline-block;
height:30px;
width:30px;
vertical-align:middle;
margin:0 10px;
}
.addTimer {
text-align:center;
}
.peopleSay {
padding-top:10px;
}
.active {
background-color:#C1C1C1;
}
.info_text {
position:relative;
top:-38px;
left:35px;
}
</style>
</head>
<body>
<div class="fatherDiv">
<%--移动:4/12 | 平板:5/12 | 桌面:4/12--%>
<%--显示在线人数--%>
<div class="layui-col-xs4 layui-col-sm5 layui-col-md4">
<p class="grid-demo layui-bg-green" style="text-align:center">会话</p>
<div id="onLineUser"></div>
</div>
<%--移动:4/12 | 平板:7/12 | 桌面:8/12--%>
<%--显示聊天记录--%>
<div class="layui-col-xs4 layui-col-sm7 layui-col-md8">
<p class="grid-demo layui-bg-gray" style="text-align:center">${username},你好</p>
<div id="message" style="height:475px;background-color:#EDEDED;overflow-y:auto"></div>
<div id="msgSay" style="margin-top:10px;text-align:right;border:1px dimgrey solid;border-radius:5px">
<textarea type="text" id="whatISaid" style="display:block;width:100%;height:10%;border:none"></textarea>
<button onclick="send()" class="layui-btn layui-btn-normal"
style="height:30px;margin-right:10px;margin-bottom:5px;">发送
</button>
</div>
</div>
</div>
</body>
<script type="text/javascript">
var username = '${username}';
$(document).ready(function () {
var time = localStorage.getItem("createTimeOfWebSocket");
if (time == "" || time == null || time == undefined) {
localStorage.setItem("createTimeOfWebSocket", new Date().getTime());
} else if (new Date().getTime() - time > 604800000) {//7天清空一次
localStorage.clear();
}
});
var webSocket;
var toWho = "ALL";
if ("WebSocket" in window) {
// 打到正式服务器上为wss:,本地时为:ws://
webSocket = new WebSocket("ws://" + 主机地址+ "/websocket/${username}");
//连通之后的回调事件
webSocket.onopen= function () {
console.log("已经连通了websocket");
};
//接收后台服务端的消息
webSocket.onmessage= function (evt) {
var received_msg = evt.data;
console.log("数据已接收:" + received_msg);
var obj = JSON.parse(received_msg);
console.log("可以解析成json:" + obj.messageType);
//1代表上线 2代表下线 3代表在线名单 4代表普通消息
if (obj.messageType== 1) {
//把名称放入到list中
var onlineName = obj.username;
var text = "<p class='users' id=" + onlineName + " onclick='sendMe(this)'>" + onlineName + "<span class='layui-badge-dot info_text' style='display: none;'></span></p>";
$("#onLineUser").append(text);
}
else if (obj.messageType== 2) {
//下线就移除它
var offlineName = obj.username;
$("#" + offlineName).remove();
//需要把之前的聊天记录保存在本地,然后打开新的聊天
var msg = $("#message")[0].innerHTML;
//这是把现在聊的人的聊天记录存进历史记录中
localStorage.setItem(offlineName + username, msg);
//如果只剩自己了就等到别人上线
if(obj.onlineUsers.length==1&&obj.onlineUsers[0]=='${username}'){
return false;
}else{
//给第一个用户抹黑
$("#onLineUser").find("p").eq(0).addClass('active');
toWho = $("#onLineUser").find("p")[0].innerText;
//把记录加在messageDIV中
var div = document.getElementById('message');
div.innerHTML= localStorage.getItem(toWho + username);
div.scrollTop= div.scrollHeight;
}
}
else if (obj.messageType== 3) {
var onlineName = obj.onlineUsers;
//如果只剩自己了就等到别人上线
if(onlineName.length==1&&onlineName[0]==${username}){
return false;
}else{
for (var i = 0; i < onlineName.length; i++) {
if (onlineName[i] != '${username}') {
$("#onLineUser").append("<p class='users' id=" + onlineName[i] + " onclick='sendMe(this)'>" + onlineName[i] + "<span class='layui-badge-dot info_text' style='display: none;'></span></p>");
}
}
//给第一个用户抹黑
$("#onLineUser").find("p").eq(0).addClass('active');
toWho = $("#onLineUser").find("p")[0].innerText;
}
} else {
console.log('有消息')
if (toWho != obj.fromusername) {
//设置样式
$('#' + obj.fromusername).find('span').eq(0).css({
'display': 'flex',
'top': '-38px',
'left': '38px'
});
var remsg=localStorage.getItem(obj.fromusername+ username);
//如果不是当前选中用户发来的消息,直接写到历史记录中,不展示出来
var msg = remsg==null?'': remsg +
'<div class="peopleSay"><p class="otherSay">' +
obj.textMessage+ '</p></div>';
localStorage.setItem(obj.fromusername+ username, msg);
} else {
setMessageInnerHTMLOtherSay(obj.textMessage);
}
}
};
//连接关闭的回调事件
webSocket.onclose= function () {
setMessageInnerHTMLOtherSay("连接已经关闭....");
};
} else {
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
//将别人说的消息显示在网页上
function setMessageInnerHTMLOtherSay(innerHTML) {
$("#message").append('<div class="peopleSay"><p class="otherSay">' + innerHTML+ '</p></div>')
var div = document.getElementById('message');
div.scrollTop= div.scrollHeight;
}
//将自己说的消息显示在网页上
function setMessageInnerHTMLMine(innerHTML) {
$("#message").append('<div class="peopleSay"><p class="mine">' + innerHTML+ '</p></div>')
var div = document.getElementById('message');
div.scrollTop= div.scrollHeight;
}
function closeWebSocket() {
//直接关闭websocket的连接
webSocket.close();
}
function send() {
var message = {
"message": $("#whatISaid").val().trim(),
"username": '${username}',
"to": toWho
};
setMessageInnerHTMLMine($("#whatISaid").val());
webSocket.send(JSON.stringify(message));
//追加时间
var time = timestampToTime();
$("#message").append('<div class="addTimer">' + time + '</div>');
$("#whatISaid").val('');
}
$('#whatISaid').on('keyup',function(event){
if(event.keyCode== 13) {
send();
}
});
//点击某一个人的头像后,对他进行通话,获取聊天记录,如果是第一个就不用获取聊天记录了
function sendMe(data) {
console.log(1)
//需要把之前的聊天记录保存在本地,然后打开新的聊天
var msg = $("#message")[0].innerHTML;
var key=toWho + username;
//这是把现在聊的人存进历史记录中
localStorage.setItem(key, msg);
//清空所有的人的active类
$("#onLineUser p").removeClass('active');
//对点击的添加新类
//把对象改为刚刚点击的人
toWho = data.textContent;
$(data)[0].classList.add('active');
$("#message").empty();
var key1=toWho + username;
//把记录加在messageDIV中
var div = document.getElementById('message');
div.innerHTML= localStorage.getItem(key1);
console.log(key1,localStorage.getItem(key1));
div.scrollTop= div.scrollHeight;
//设置样式
$('#' + toWho).find('span').eq(0).css('display', 'none');
}
function timestampToTime() {
var date = new Date();//时间戳为10位需*1000,时间戳为13位的话不需乘1000
var Y = date.getFullYear() + '-';
var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
var D = date.getDate() < 10 ? '0' + date.getDate() + ' ' : date.getDate() + ' ';
var h = date.getHours() < 10 ? '0' + date.getHours() + ':' : date.getHours() + ':';
var m = date.getMinutes() < 10 ? '0' + date.getMinutes() + ':' : date.getMinutes() + ':';
var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
return Y + M + D + h + m + s;
}
</script>
</html>
后台
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author hjy18
*/
@Component
@ServerEndpoint("/websocket/{username}")
public class WebSocket {
/**
* 定义一个全局的记录器,通过LoggerFactory获取
*/
private final static Logger logger = LoggerFactory.getLogger(WebSocket.class);
/**
* 在线人数
*/
protected static int onlineNumber=0;
/**
* 以用户的姓名为key,websocke为对象保存起来
*/
private static Map<String,WebSocket> clients=new ConcurrentHashMap<>(16);
/**
* 会话
*/
private Session session;
/**
* 用户昵称
*/
private String username;
/**
* 建立连接
*
* @param session
*/
@OnOpen
public void onOpen(@PathParam("username") String username, Session session){
String name="";
try {
name = new String(username.getBytes("ISO-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
synchronized (this){
onlineNumber++;
}
System.out.println("现在来连接的客户id:"+session.getId()+"用户名:"+name);
this.username= name;
this.session= session;
System.out.println("有新连接加入! 当前在线人数" + onlineNumber);
try {
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
//先给所有人发送通知,说我上线了
Map<String,Object> map1 = new HashMap<>(16);
map1.put("messageType",1);
map1.put("username",name);
sendMessageAll(JSON.toJSONString(map1),name);
//把自己的信息加入到map当中去
clients.put(name, this);
//给自己发一条消息:告诉自己现在都有谁在线
Map<String,Object> map2 = new HashMap<>(16);
map2.put("messageType",3);
//移除掉自己
Set<String> set = clients.keySet();
map2.put("onlineUsers",set);
sendMessageTo(JSON.toJSONString(map2),name);
}
catch (IOException e){
logger.error(name+"上线的时候通知所有人发生了错误");
}
}
@OnError
public void onError(Session session, Throwable error) {
logger.error("服务端发生了错误"+error.getMessage());
//error.printStackTrace();
}
/**
* 连接关闭
*/
@OnClose
public void onClose(){
synchronized (this){
onlineNumber--;
}
clients.remove(username);
try {
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
Map<String,Object> map1 = new HashMap<>(16);
map1.put("messageType",2);
map1.put("onlineUsers",clients.keySet());
map1.put("username",username);
sendMessageAll(JSON.toJSONString(map1),username);
}
catch (IOException e){
System.out.println(username+"下线的时候通知所有人发生了错误");
}
System.out.println("有连接关闭! 当前在线人数" + onlineNumber);
}
/**
* 收到客户端的消息
*
* @param message 消息
* @param session 会话
*/
@OnMessage
public void onMessage(String message, Session session)
{
try {
System.out.println("来自客户端消息:" + message+"客户端的id是:"+session.getId());
JSONObject jsonObject = JSON.parseObject(message);
String textMessage = jsonObject.getString("message");
String fromusername = jsonObject.getString("username");
String tousername = jsonObject.getString("to");
//如果不是发给所有,那么就发给某一个人
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
Map<String,Object> map1 = new HashMap<>(16);
map1.put("messageType",4);
map1.put("textMessage",textMessage);
map1.put("fromusername",fromusername);
if(tousername.equals("All")){
map1.put("tousername","所有人");
sendMessageAll(JSON.toJSONString(map1),fromusername);
}
else{
map1.put("tousername",tousername);
sendMessageTo(JSON.toJSONString(map1),tousername);
}
}
catch (Exception e){
System.out.println("发生了错误了");
e.printStackTrace();
}
}
public void sendMessageTo(String message, String ToUserName) throws IOException {
for (WebSocket item : clients.values()) {
if (item.username.equals(ToUserName) ) {
item.session.getAsyncRemote().sendText(message);
break;
}
}
}
public void sendMessageAll(String message, String FromUserName) throws IOException {
for (WebSocket item : clients.values()) {
item.session.getAsyncRemote().sendText(message);
}
}
public static synchronized int getOnlineCount() {
return onlineNumber;
}
}
网友评论