当前位置:网站首页>web聊天室实现
web聊天室实现
2022-07-04 13:54:00 【全栈程序员站长】
大家好,又见面了,我是你们的朋友全栈君。
后端:
package com.jsx.chat;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import net.sf.json.JSONObject;
@ServerEndpoint("/websocket/{userId}")
public class ChatServer {
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); // 日期格式化
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
private static CopyOnWriteArraySet<ChatServer> webSocketSet = new CopyOnWriteArraySet<ChatServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
private String userId;
/**
* 连接建立成功调用的方法
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void open(@PathParam("userId")String userIds,Session session) {
// 添加初始化操作
System.out.println("---初始化----userId:"+userIds);
this.session = session;
//获取当前登录用户的id
this.userId = userIds;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
}
/**
* 接受客户端的消息,并把消息发送给所有连接的会话
* @param message 客户端发来的消息
* @param session 客户端的会话
*/
@OnMessage
public void getMessage(String message, Session session1) {
// 把客户端的消息解析为JSON对象
JSONObject jsonObject = JSONObject.fromObject(message);
// 在消息中添加发送日期
jsonObject.put("date", DATE_FORMAT.format(new Date()));
// -----------------------把消息发送给所有连接的会话--------------------------------
System.out.println("来自客户端的消息"+this.userId+":" + message);
for(ChatServer item: webSocketSet){
try {
//当前用户右侧显示,非本用户左侧显示
if(this.userId.equals(item.userId)){jsonObject.put("isSelf", true);}
else{jsonObject.put("isSelf", false);}
// 发送JSON格式的消息
item.sendMessage(jsonObject.toString());
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
@OnClose
public void close() {
// 添加关闭会话时的操作
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
@OnError
public void error(Throwable t) {
// 添加处理错误的操作
System.out.println("发生错误");
t.printStackTrace();
}
/**
* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
* @param message json消息
* @throws IOException
*/
public synchronized void sendMessage(String message) throws IOException{
this.session.getAsyncRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
ChatServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
ChatServer.onlineCount--;
}
}
前端:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>即时群聊</title>
<meta name="renderer" content="webkit">
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link rel="stylesheet" href="css/chat.css">
<link rel="alternate icon" href="assets/i/favicon.ico">
<link rel="stylesheet" href="assets/css/amazeui.min.css">
<link rel="stylesheet" href="assets/css/app.css">
<link href="umeditor/themes/default/css/umeditor.css" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
}
.chat-content-container {
height: 29rem;
overflow-y: auto;
border: 1px solid silver;
border-bottom: 0px;
}
.container{
border: 1px solid #cdcaca;
padding:0px 0px;
}
.am-u-sm-6{
left:0px;
}
.am-u-sm-push-6{
width:100%;
}
</style>
</head>
<body>
<input id="username" type="hidden" value="${user.username}"><br>
<input id="name" type="hidden" value="${user.name}"><br>
<!-- 聊天内容框开始 -->
<div class="am-container container" >
<div class="am-u-sm-12" style="background:#dcad50;">
<!-- <div class="am-u-sm-3 am-u-sm-push-6"> -->
<h3 style="text-align:center;margin-top:auto;margin-bottom:auto;padding:3px 0px;font-size:20px">聊天室</h3>
<!-- </div> -->
</div>
<div class="chat-content-container">
<div class="am-u-sm-6 am-u-sm-push-6">
<ul id="message-list" class="am-comments-list am-comments-list-flip"></ul>
</div>
</div>
<!-- </div> -->
<!-- 聊天内容框结束 -->
<div class="message-input am-margin-top">
<!-- 输入内容框开始 -->
<div class="am-g am-g-fixed" style="padding:10px 0px;border-top:1px solid #b5a4a4">
<div class="am-u-sm-12">
<form class="am-form">
<div class="am-form-group">
<script type="text/plain" id="myEditor" style="width: 100%;height: 20rem;"></script>
</div>
</form>
</div>
</div>
<!-- 输入昵称框开始 -->
<!-- <div class="am-g am-g-fixed am-margin-top"> -->
<div class="am-u-sm-6" style="display: none;">
<div id="message-input-nickname" class="am-input-group am-input-group-primary">
<span class="am-input-group-label"><i class="am-icon-user"></i></span>
<input id="nickname" type="text" class="am-form-field" value="${user.name}"/>
</div>
</div>
<div class="am-u-sm-12">
<p style="text-align:right;margin:0px">
<button onclick="f()" class="am-btn am-btn-warning">
关闭
</button>
<button id="send" type="button" class="send am-btn am-btn-primary">
<i class="am-icon-send"></i>发送
</button>
</p>
</div>
<!-- </div> -->
<!-- </div> -->
</div>
</div>
<script src="assets/js/jquery.min.js"></script>
<script charset="utf-8" src="umeditor/umeditor.config.js"></script>
<script charset="utf-8" src="umeditor/umeditor.min.js"></script>
<script src="umeditor/lang/zh-cn/zh-cn.js"></script>
<script>
function f(){
window.location.href="friend.jsp";
}
$(function() {
var id = $('#username').val();
var name = $('#name').val();
//随机方法 生成id模拟用户
function rand(num){
return parseInt(id);
}
// 初始化消息输入框
var um = UM.getEditor('myEditor');
// 使昵称框获取焦点
$('#nickname')[0].focus();
// 新建WebSocket对象,最后的/WebSocket跟服务器端的@ServerEndpoint("/websocket")对应
//var socket = new WebSocket('ws://${pageContext.request.getServerName()}:${pageContext.request.getServerPort()}${pageContext.request.contextPath}/websocket');
//var socket = new WebSocket("ws://localhost:8080/Chat/websocket");
var target = "ws://"+window.location.host+"/Chat/websocket"+"/"+rand();
//alert(target);
var socket = new WebSocket(target);
// 处理服务器端发送的数据
socket.onmessage = function(event) {
addMessage(event.data);
};
// 点击Send按钮时的操作
$('#send').on('click', function() {
var nickname = $('#nickname').val();
//alert(um.getContent()); //内容
//alert(nickname); //昵称
if (!um.hasContents()) { // 判断消息输入框是否为空
// 消息输入框获取焦点
um.focus();
// 添加抖动效果
$('.edui-container').addClass('am-animation-shake');
setTimeout("$('.edui-container').removeClass('am-animation-shake')", 1000);
} else if (nickname == '') { // 判断昵称框是否为空
//昵称框获取焦点
$('#nickname')[0].focus();
// 添加抖动效果
$('#message-input-nickname').addClass('am-animation-shake');
setTimeout("$('#message-input-nickname').removeClass('am-animation-shake')", 1000);
} else {
// 发送消息
socket.send(JSON.stringify({
content : um.getContent(),
nickname : name
}));
// 清空消息输入框
um.setContent('');
// 消息输入框获取焦点
um.focus();
}
});
// 把消息添加到聊天内容中
function addMessage(message) {
message = JSON.parse(message);
var messageItem = '<li class="am-comment '
+ (message.isSelf ? 'am-comment-flip' : 'am-comment')
+ '">'
+ '<a href="javascript:void(0)" ><img src="assets/images/'
+ (message.isSelf ? 'self.jpg' : 'others.jpg')
+ '" alt="" class="am-comment-avatar" width="48" height="48"/></a>'
+ '<div class="am-comment-main"><header class="am-comment-hd"><div class="am-comment-meta">'
+ '<a href="javascript:void(0)" class="am-comment-author">'
+ message.nickname + '</a> <time>' + message.date
+ '</time></div></header>'
+ '<div class="am-comment-bd">' + message.content
+ '</div></div></li>';
$(messageItem).appendTo('#message-list');
// 把滚动条滚动到底部
$(".chat-content-container").scrollTop($(".chat-content-container")[0].scrollHeight);
}
});
</script>
</body>
</html>
因为我的账户设计到数据库等操作,因此如果想直接测试的话可以修改上述nickname中的值为随机生成即可!
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/149294.html原文链接:https://javaforall.cn
边栏推荐
- PLC Analog input analog conversion FC s_ ITR (CoDeSys platform)
- 重排数组
- 智能客服赛道:网易七鱼、微洱科技打法迥异
- How to match chords
- .Net之延迟队列
- C language achievement management system for middle school students
- Five minutes per day machine learning: use gradient descent to complete the fitting of multi feature linear regression model
- C language course design questions
- Exploration and practice of eventbridge in the field of SaaS enterprise integration
- [local differential privacy and random response code implementation] differential privacy code implementation series (13)
猜你喜欢
金额计算用 BigDecimal 就万无一失了?看看这五个坑吧~~
Ranking list of databases in July: mongodb and Oracle scores fell the most
Ffprobe common commands
Halcon knowledge: NCC_ Model template matching
程序员自曝接私活:10个月时间接了30多个单子,纯收入40万
[C language] Pointer written test questions
LeetCode 1200 最小绝对差[排序] HERODING的LeetCode之路
智能客服赛道:网易七鱼、微洱科技打法迥异
Five minutes of machine learning every day: how to use matrix to represent the sample data of multiple characteristic variables?
MP3是如何诞生的?
随机推荐
go-zero微服务实战系列(九、极致优化秒杀性能)
Go zero micro service practical series (IX. ultimate optimization of seckill performance)
5G电视难成竞争优势,视频资源成中国广电最后武器
How to match chords
leecode学习笔记-约瑟夫问题
输入宽度!
微博、虎牙挺进兴趣社区:同行不同路
2022 financial products that can be invested
Openresty redirection
开源人张亮的 17 年成长路线,热爱才能坚持
Introduction to asynchronous task capability of function calculation - task trigger de duplication
关于FPGA底层资源的细节问题
如何搭建一支搞垮公司的技术团队?
炒股网上开户安全吗?会不会被骗。
MySQL组合索引(多列索引)使用与优化案例详解
03 storage system
Flutter reports an error no mediaquery widget ancestor found
Dialogue with ye Yanxiu, senior consultant of Longzhi and atlassian certification expert: where should Chinese users go when atlassian products enter the post server era?
C language personal address book management system
Graduation season - personal summary