websocket的介绍就不多说了,简单来说就是http协议只能支持客户端访问springboot的接口,然后springboot返回相应的数据,但是ws的协议是可以主动向用户的客户端发送消息,所以可以用来做实时传输。
接下来由浅入深,一步一步来做完这个聊天室,不同阶段的代码我会放在网盘,可以根据需要自取。
首先创建一个基础的Springboot项目
package com;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication
@EnableSwagger2
@MapperScan(basePackages = { "com.mapper" })
public class ChatDemo {
public static void main(String[] args) {
SpringApplication.run(ChatDemo.class, args);
}
}
在pom.xml中导入websocket环境
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建启动websocket支持的.java文件
这个类会在springboot启动的时候自动注入,所以复制粘贴过去就可以了。
package com.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
//启动websocket支持
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
创建websocket启动类
下面时一个简化过的启动类,虽然我们最终目标是写聊天室,但是最基本的还是先搞清楚最基础的websocket的连接,网上大部分的教程都有不同程度的魔改过,代码阅读难度较高,所以我将网上的代码进行了简化方便入门和魔改。
package com.server;
import java.io.IOException;
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 org.springframework.stereotype.Component;
/**
* 客户端访问该链接即可和服务端建立连接
*/
@ServerEndpoint("/login_connect/{userId}")
@Component
public class WebSocketServer {
//使用session向连接的用户发送信息
private Session session;
//记录连接到此socke的用户id
private String userId = "";
//用户连接成功后会自动调用该方法
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) throws
IOException {
this.session = session;
this.userId = userId;
System.out.println("连接成功,用户ID为:" + userId);
//连接成功后向连接的用户返回 “连接成功” 信息
this.session.getBasicRemote().sendText("连接成功");
}
//关闭连接后自动调用
@OnClose
public void onClose() {
System.out.println("close connect");
}
//收到用户发来的消息时调用
@OnMessage
public void onMessage(String message, Session session) throws IOException {
System.out.println("收到id为:"+this.userId+"的用户发来的消息:"+message);
}
//错误时调用
@OnError
public void onError(Session session, Throwable error) {
}
}
接下来是客户端代码
因为是在本地跑所以我是直接在HbuilderX中创建的新的前端项目
下面是代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>websocket通讯</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var socket = null;
function openSocket() {
//获取用户输入的用户id
var userid=document.getElementById("userid").value;
//这个链接地址对应了springboot跑的端口和上面标注的访问的接口
var socketUrl = "ws://localhost:8081/login_connect/" +userid;
socket = new WebSocket(socketUrl);
//下面几个方法对应了服务端的几个方法
//连接成功
socket.onopen = function() {
console.log("websocket已打开");
};
//发生了错误事件
socket.onerror = function() {
console.log("websocket发生了错误");
}
//收到消息
socket.onmessage = function(msg) {
console.log("服务器发送的数据:" + msg.data);
};
//关闭连接后运行
socket.onclose = function() {
console.log("websocket已关闭");
};
}
//发送数据给服务器
function sendMessage() {
socket.send(document.getElementById("message").value);
}
</script>
<body>
用户名:<input id="userid" value="test_user">
<br>
发送的信息:<input id="message"value="test websocket connection"><br>
<button onclick="openSocket()">连接到websocket</button><br>
<button onclick="sendMessage()">发送消息</button>
</body>
</html>
3.点击发送按钮后 springboot控制台
上述代码实现了最简单的客户端向服务端建立连接,然后服务端发送消息给客户端告知连接成功,然后客户端发送消息给服务端,实现了最简单的双向交互
我先把上面的代码压缩分享到这里,后面进行魔改,由于原始工程文件是之前用的另外一个项目的魔改框架,还保留了很多其他依赖,可能会有点大。
链接:https://pan.baidu.com/s/1SYOZL58jugDNnaqqZ5yO-Q
提取码:1234
–来自百度网盘超级会员V2的分享
<!–############################分割线################################–>
然后接下来我们把这个过程慢慢复杂化,比如上述的功能为服务端和客户端进行数据交换,接下来我们先来实现客户端对客户端的数据交互,也就是客户端A将消息发给服务端,然后服务端将消息发给客户端B。
首先对上面的javasocket实现类进行一些修改(可以复制粘贴将原本的代码覆盖)
因为一个websocket的实现类就说明连接了一个客户端,所以如果多个客户端连接到服务器的话,我们就可以创建一个容器来存放这些类,然后通过userid来区分,所以我们使用hashmap来存储这些连接,将该容器设为静态,然后我们可以在任意一个连接中调用所有的连接,就可以通过这个容器向任意用户发送消息。
// 用来存放所有的连接,静态
private static ConcurrentHashMap<String, WebSocketServer> webSocketMap =
new ConcurrentHashMap<>();
// 用户连接成功后会自动调用该方法
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) throws IOException {
this.session = session;
this.userId = userId;
System.out.println("连接成功,用户ID为:" + userId);
// 连接成功后向连接的用户返回 “连接成功” 信息
this.session.getBasicRemote().sendText("连接成功");
// 然后将该连接存入ChatController
webSocketMap.put(this.userId, this);
}
接下来我们添加一个发送消息给该客户端的方法,方便客户端的连接被其他用户调用,然后就可以发送消息给该用户。
// 发送消息给此客户端
public void sendmessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
然后重写一下OnMessage方法,将用户发送过来的消息分解为json,内容为接收者id:receiveuserid、和发送的消息:message,当然从客户端传过来的数据为一条字符串,我们用JSON工具将他转化为对象,然后根据receiveruserid从SocketHashMap中取出相应的websocket连接,然后通过调用上面写的sendmessage方法将消息发送给接收者客户端。
// 收到用户发来的消息时调用
@OnMessage
public void onMessage(String message, Session session) throws IOException {
System.out.println(message);
JSONObject json = JSON.parseObject(message);
System.out.println(json.getString("receiveuserid") + "||" + json.getString("message"));
webSocketMap.get(json.getString("receiveuserid"))
.sendmessage("用户:" + this.userId + "说:" + json.getString("message"));
}
改完后的代码如下:
package com.server;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
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 org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.controller.ChatController;
import bean.Message;
/**
* 客户端访问该链接即可和服务端建立连接
*/
@ServerEndpoint("/login_connect/{userId}")
@Component
public class WebSocketServer {
// 用来存放所有的连接,静态
private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
// 使用session向连接的用户发送信息
private Session session;
// 记录连接到此socke的用户id
private String userId = "";
// 用户连接成功后会自动调用该方法
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) throws IOException {
this.session = session;
this.userId = userId;
System.out.println("连接成功,用户ID为:" + userId);
// 连接成功后向连接的用户返回 “连接成功” 信息
this.session.getBasicRemote().sendText("连接成功");
// 然后将该连接存入ChatController
webSocketMap.put(this.userId, this);
}
// 关闭连接后自动调用
@OnClose
public void onClose() {
System.out.println("close connect");
}
// 收到用户发来的消息时调用
@OnMessage
public void onMessage(String message, Session session) throws IOException {
System.out.println(message);
JSONObject json = JSON.parseObject(message);
System.out.println(json.getString("receiveuserid") + "||" + json.getString("message"));
webSocketMap.get(json.getString("receiveuserid"))
.sendmessage("用户:" + this.userId + "说:" + json.getString("message"));
}
// 错误时调用
@OnError
public void onError(Session session, Throwable error) {
System.out.println("error");
}
// 发送消息给此客户端
public void sendmessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
}
后端的代码改完了,然后前端代码也要进行一定的适配
主要是添加了接收用户的id的输入框,js代码将发送的数据的格式写成了json,内容为receiverid和message。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>websocket通讯</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var socket = null;
var userid = "";
function openSocket() {
//获取用户输入的用户id
userid = document.getElementById("userid").value;
//这个链接地址对应了springboot跑的端口和上面标注的访问的接口
var socketUrl = "ws://localhost:8081/login_connect/" + userid;
socket = new WebSocket(socketUrl);
//下面几个方法对应了服务端的几个方法
//连接成功
socket.onopen = function() {
console.log("websocket已打开");
};
//发生了错误事件
socket.onerror = function() {
console.log("websocket发生了错误");
}
//收到消息
socket.onmessage = function(msg) {
console.log("服务器发送的数据:" + msg.data);
};
//关闭连接后运行
socket.onclose = function() {
console.log("websocket已关闭");
};
}
//发送数据给服务器
function sendMessage() {
socket.send('{"receiveuserid":"' + $("#receiveuserid").val() + '","message":"' + $("#message").val() +'"}');
}
</script>
<body>
用户名:<input id="userid" value="test_user">
<br>
接收人:<input id="receiveuserid" value="test_user">
<br>
发送的信息:<input id="message" value="test websocket connection"><br>
<button onclick="openSocket()">连接到websocket</button><br>
<button onclick="sendMessage()">发送消息</button>
</body>
</html>
用户A界面:
用户B界面:
后端界面:
第二阶段的代码,自取
链接:https://pan.baidu.com/s/1sDpelZH1n_bFUXEd46MgdQ
提取码:1234
–来自百度网盘超级会员V2的分享
<!–############################分割线################################–>
接下来我们为这个聊天室添加一个群聊天室的功能
首先,当我们不再只是单纯的传输数据,而是聊天,那么消息就会复杂起来,所以我们先创建一个bean用来存储基本的消息
package com.entiry;
public class Message {
private String userid;//发送者id
private String message;//内容
private String type;//消息类型: new_user 新用户上线|| server 服务器消息|| tochatroom 聊天室消息|| offline 用户下线
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getTouser() {
return touser;
}
public void setTouser(String touser) {
this.touser = touser;
}
}
我在这边把消息类型分成了四种
new_user 新用户上线|| server 服务器消息|| tochatroom 聊天室消息|| offline 用户下线
在我们使用Message类来进行数据传输后,就不能再跟以前一样,只传基本String了,而是把String复杂化了,也就是将Message类转化为JSON字符然后发送给前端然后前端再进行解析(其实可以直接将return 类型改成Message 但是因为中途改的话要改的代码蛮多的,我就懒得弄了)
然后我们继续魔改WebSocketServer
// 给除自己以外的所有用户发消息
public void sendmessagetootherusers(String message) throws IOException {
//获取所有连接中的用户id
Enumeration<String> userkeys = webSocketMap.keys();
//通过便利来向所有用户发送消息
while (userkeys.hasMoreElements()) {
String userid = userkeys.nextElement();
//通过对比排除自己
if (userid != userId) {
webSocketMap.get(userid).sendmessage(message);
}
}
}
// 收到用户发来的消息时调用
@OnMessage
public void onMessage(String message, Session session) throws IOException {
//将收到的消息转化为JSON对象
JSONObject json = JSON.parseObject(message);
//判断消息类型,聊天室消息就直接将消息发送给所有除自己外的用户
if (json.getString("type").equals("tochatroom")) {
//创建消息类,将消息类型、消息内容、发送消息者的id放进去
Message msg = new Message();
msg.setMessage(json.getString("message"));
msg.setUserid(userId);
msg.setType("tochatroom");
//然后将消息发送给其他用户
sendmessagetootherusers(JSON.toJSONString(msg));
}
}
然后是当连接关闭的方法
// 关闭连接后自动调用
@OnClose
public void onClose() throws IOException {
// 将断开连接的socket从map中移除
webSocketMap.remove(userId);
// 给所有客户端发送offline消息类型,内容为离线用户的ID
Message msg = new Message();
msg.setType("offline");
msg.setMessage(userId);
sendmessagetootherusers(JSON.toJSONString(msg));
}
然后是当有客户端连接时
// 用户连接成功后会自动调用该方法
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) throws IOException {
this.session = session;
this.userId = userId;
Message message = new Message();
message.setType("new_user");
message.setMessage(userId);
//将该连接加入到SocketMap中
webSocketMap.put(this.userId, this);
// 向所有用户广播,userid上线了
sendmessagetootherusers(JSON.toJSONString(message));
}
下面是完整代码
package com.server;
import java.io.IOException;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;
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 org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.entiry.Message;
/**
* 客户端访问该链接即可和服务端建立连接
*/
@ServerEndpoint("/login_connect/{userId}")
@Component
public class WebSocketServer {
// 用来存放所有的连接,静态
public static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
// 使用session向连接的用户发送信息
private Session session;
// 记录连接到此socke的用户id
private String userId = "";
// 用户连接成功后会自动调用该方法
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) throws IOException {
this.session = session;
this.userId = userId;
Message message = new Message();
message.setType("new_user");
message.setMessage(userId);
//将该连接加入到SocketMap中
webSocketMap.put(this.userId, this);
// 向所有用户广播,userid上线了
sendmessagetootherusers(JSON.toJSONString(message));
}
// 关闭连接后自动调用
@OnClose
public void onClose() throws IOException {
// 将断开连接的socket从map中移除
webSocketMap.remove(userId);
// 给所有客户端发送offline消息类型,内容为离线用户的ID
Message msg = new Message();
msg.setType("offline");
msg.setMessage(userId);
sendmessagetootherusers(JSON.toJSONString(msg));
}
// 收到用户发来的消息时调用
@OnMessage
public void onMessage(String message, Session session) throws IOException {
// 将收到的消息转化为JSON对象
JSONObject json = JSON.parseObject(message);
// 判断消息类型,聊天室消息就直接将消息发送给所有除自己外的用户
if (json.getString("type").equals("tochatroom")) {
// 创建消息类,将消息类型、消息内容、发送消息者的id放进去
Message msg = new Message();
msg.setMessage(json.getString("message"));
msg.setUserid(userId);
msg.setType("tochatroom");
// 然后将消息发送给其他用户
sendmessagetootherusers(JSON.toJSONString(msg));
}
}
// 错误时调用
@OnError
public void onError(Session session, Throwable error) {
System.out.println("error");
}
// 给除自己以外的所有用户发消息
public void sendmessagetootherusers(String message) throws IOException {
// 获取所有连接中的用户id
Enumeration<String> userkeys = webSocketMap.keys();
// 通过便利来向所有用户发送消息
while (userkeys.hasMoreElements()) {
String userid = userkeys.nextElement();
// 通过对比排除自己
if (userid != userId) {
webSocketMap.get(userid).sendmessage(message);
}
}
}
// 发送消息给此客户端
public void sendmessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
}
然后我们需要一个Controller来让用户能有更复杂的操作
但是因为我们的项目是前后端分离项目,所以要写一些配置文件来支持外部访问
package com.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CrossConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
然后在创建Controller之前,我们再写一个类来存用户信息,好让客户端来获取当前已登录用户
(这里的代码很简单,有点脱裤子放屁,但是这种方式比较方便以后的扩展,虽然这个类里面只有userID,用数组也可以实现,但是当程序复杂后数据就多起来了,所以还是得习惯这种写法)
package com.entiry;
import java.io.Serializable;
public class User {
private String userID;//用户ID
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
}
然后是Controller方法
package com.controller;
import com.server.WebSocketServer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.server.support.WebSocketHandlerMapping;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import com.entiry.User;
/**
* WebSocketController
*
* @author zhengkai.blog.csdn.net
*/
@RestController
public class ChatController {
//获取所有在线人员
@RequestMapping("/getUsers")
public List<User> getUsers() {
//获取所有的用户名然后注入到列表里面然后返回给前端
List<User> users = new ArrayList<>();
Enumeration<String> userkeys = WebSocketServer.webSocketMap.keys();
while (userkeys.hasMoreElements()) {
String userid = userkeys.nextElement();
User tempuser = new User();
tempuser.setUserID(userid);
users.add(tempuser);
}
return users;
}
//查询某个用户是否在线,返回布尔型
@RequestMapping("/isOnline")
public boolean isOnline(@RequestBody String userid) {
System.out.println(userid);
return WebSocketServer.webSocketMap.containsKey(userid);
}
}
这个controller只实现了两个方法,但是拓展的话还是很方便的。
然后后端的内容就全做完了,接下来是修改前端来适配后端的代码,由于体量变大了,所以我把js css分开来写了
这边我先直接放出代码
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title id="tittle">聊天室</title>
<link rel="stylesheet" href="css/A.css" type="text/css" />
</head>
<script src="js/jquery-3.4.1.js"></script>
<script src="js/A.js"></script>
<script>
</script>
<body>
<div class="main_block">
<!--标题-->
<div class="top">聊天室</div>
<div class="connect">
<font style="float: left;">&nbsp;&nbsp;|&nbsp;用户名:</font>
<input class="userid_input" id="userid" placeholder="请输入用户名">
<button id="connect_botton" class="userid_input" onclick="openSocket()">连接到多人聊天室</button>
<font style="float: left;">&nbsp;&nbsp;<font id="tip"></font>
</font>
<font style="float: right;">当前在线:<font id="nowusercount"></font>人&nbsp;&nbsp;&nbsp;</font>
</div>
<div class="line"></div>
<div class="chat_room">
<div class="users" id="users">
<div class="user" style="background-color: #6e90ff;">公共聊天室</div>
</div>
<div class="chat">
<dl class="messages" id="messages">
</dl>
</div>
</div>
<div class="line"></div>
<div class="send">
<textarea placeholder="输入消息..." class="text_input" id="sendmessage"
></textarea>
<div class="line"></div>
<button id="sendbutton" onclick="sendMessage()" class="send_button">发送消息</button>
</div>
</div>
</body>
</html>
CSS:
.main_block {
width: 700px;
height: 900px;
margin: 0 auto;
border: 1px solid black;
}
.top {
width: 100%;
height: 40px;
background-color: #47a9ff;
font-size: 20px;
color: white;
line-height: 40px;
text-align: center;
font-weight: bold;
}
.connect {
width: 100%;
height: 30px;
line-height: 30px;
font-size: 17px;
background-color: white;
}
.userid_input {
margin-top: 5px;
float: left;
}
.line {
float: left;
width: 100%;
height: 1px;
background-color: black;
}
.chat_room {
width: 100%;
height: 650px;
background-color: #fff;
}
.users {
width: 170px;
float: left;
overflow-y: scroll;
height: 100%;
}
.user {
cursor: pointer;
width: 100%;
height: 40px;
background-color: #9dcdff;
color: white;
line-height: 40px;
text-align: center;
font-style: 17px;
margin-bottom: 3px;
}
.user:hover {
background-color: #81baff;
}
.chat {
overflow-y: scroll;
width: 530px;
height: 100%;
float: left;
}
.messages {
width: 95%;
margin-left: 3%;
}
.sender_id {
margin-bottom: 5px;
font-weight: bold;
}
.sender_message {
margin-bottom: 5px;
width: 55%;
background-color: #9dcdff;
border-radius: 3px;
font-size: 15px;
padding: 7px;
}
.user_id {
margin-left: 85%;
margin-bottom: 5px;
font-weight: bold;
}
.user_message {
margin-left: 30%;
margin-bottom: 5px;
width: 55%;
background-color: #69ff8c;
border-radius: 3px;
font-size: 15px;
padding: 7px;
}
.send {
width: 100%;
height: 178px;
}
.text_input {
font-size: 15px;
background-color: #f3f3f3;
resize: none;
float: right;
border: 0px solid red;
width: 694px;
height: 130px;
}
.send_button {
margin-top: 5px;
float: right;
margin-right: 10px;
height: 30px;
width: 100px;
font-size: 15px;
font-weight: bold;
border: 0px solid red;
border-radius: 3px;
color: white;
background-color: #47a9ff;
}
.server_message {
width: 100%;
height: 30px;
font-size: 13px;
color: #9c9c9c;
float: left;
margin-left: 0%;
line-height: 30px;
text-align: center;
}
JS:
var socket = null;//socket连接
var userid = "";//当前用户id
var nowusercount = 0;//当前在线人数
//窗口运行时先获取一次在线列表
window.onload = function() {
getonlineusers();
}
//获取所有在线用户,然后把用户列表更新在列表中
function getonlineusers() {
$.ajax({
url: "http://localhost:8081/getUsers", //请求路径
//data: userid = "177", //要发送的数据
contentType: "application/json;charset=UTF-8", //发送数据的格式
type: "post", //访问方式
dataType: "text", //回调(常用json,text)
success: function(data) {
console.log(data);
var onlineusers = JSON.parse(data);
nowusercount = onlineusers.length
$("#nowusercount").text(nowusercount);
var list = '<div class="user" style="background-color: #6e90ff;">公共聊天室</div>';
//将获取到的数据遍历然后存储在list中
for (var a = 0; a < onlineusers.length; a++) {
//排除自己
if (onlineusers[a].userID != userid) {
list = list + '<div class="user">' + onlineusers[a].userID +
'</div>';
}
}
//将元素渲染在页面
$("#users").html(list);
}
});
}
//连接方法
function openSocket() {
//用户名不能输入为空
if ($("#userid").val() != "") {
userid = $("#userid").val();
//先查询一下是否已经有人用了这个用户名
$.ajax({
url: "http://localhost:8081/isOnline", //请求路径
data: userid = $("#userid").val(), //要发送的数据
contentType: "application/json;charset=UTF-8", //发送数据的格式
type: "post", //访问方式
dataType: "text", //回调(常用json,text)
success: function(data) {
//如果已经有人在使用这个用户名,则不继续往下走
if (data == "true") {
$("#tip").text("用户已存在");
setTimeout(function() {
$("#tip").text("");
}, 2500);
} else {
//当没人用过此用户名的时候则连接服务器
$("#tip").text("连接成功");
//将链接按钮和输入用户名的输入框设为不可用
$("#connect_botton").attr("disabled", true);
$("#userid").attr("disabled", true);
$("#connect_botton").text("已连接");
setTimeout(function() {
$("#tip").text("");
}, 2500);
//获取用户输入的用户id
userid = $("#userid").val();
$("#tittle").text("聊天室:" + userid);
//这个链接地址对应了springboot跑的端口和上面标注的访问的接口
var socketUrl = "ws://localhost:8081/login_connect/" + userid;
socket = new WebSocket(socketUrl);
//下面几个方法对应了服务端的几个方法
//连接成功
socket.onopen = function() {
//连接成功后获取最新在线用户列表
getonlineusers();
};
//发生了错误事件
socket.onerror = function() {
console.log("websocket发生了错误");
}
//收到消息
socket.onmessage = function(msg) {
console.log(msg.data);
var message = JSON.parse(msg.data);
//接收到的消息为new_user类型
//刷新用户列表然后提示用户上线
if (message.type == "new_user") {
getonlineusers();
nowusercount++;
$("#nowusercount").text(nowusercount);
sendservermessage("用户‘" + message.message + "’上线")
}
//接收到chatroom类型的消息直接展示在聊天室
if (message.type == "tochatroom") {
addothermessage(message.userid, message.message);
}
//接收到offline的消息提示离线然后刷新用户列表
if (message.type == "offline") {
sendservermessage("用户‘" + message.message + "’离线");
getonlineusers();
}
};
//关闭连接后运行
socket.onclose = function() {
console.log("websocket已关闭");
};
}
},
error: function() {}
});
} else {
$("#tip").text("请输入用户名");
setTimeout(function() {
$("#tip").text("");
}, 2500);
}
}
//发送数据给服务器
function sendMessage() {
if ($("#sendmessage").val() != "") {
//输入框中输入的消息类型为tochatroom
socket.send('{"type":"tochatroom","message":"' + $("#sendmessage").val() +
'"}');
addusermessage(userid, $("#sendmessage").val());
$("#sendmessage").val("");
}else{
$("#sendbutton").text("不能为空");
setTimeout(function() {
$("#sendbutton").text("发送消息");
}, 1500);
}
}
//将别人的消息渲染到页面
function addothermessage(sender, message) {
$("#messages").html($("#messages").html() + '<dt class="sender_id">' +
sender + '</dt><dd class="sender_message">' + message + '</dd>')
}
//将自己的消息渲染到页面
function addusermessage(userid, message) {
$("#messages").html($("#messages").html() + '<dt class="user_id">' +
userid + '</dt><dd class="user_message">' + message + '</dd>')
}
//将系统的消息渲染到页面
function sendservermessage(message) {
$("#messages").html($("#messages").html() + '<dd class="server_message">' + message + '</dd>')
}
前端除js代码我都写好了注释,代码写的很简单,所以阅读起来难度也不大相信上手还是会很快的。
第三阶段源码
链接:https://pan.baidu.com/s/11UemzHvQCSOVYWfsMrJ3mg
提取码:1234
–来自百度网盘超级会员V2的分享
这次做的聊天室因为没有用到数据库,所以不能进行登录,消息保存等操作,也没有实现加好友、删好友、私聊等功能,但是最基础的几个功能都已经实现了,如果是从阶段1开始设计的话,可以将这个项目复杂化,加上所有需要的功能,但是总的来说,会socket,和基础的数据库,那么上述功能都可以实现。
原文地址:https://blog.csdn.net/loveisbunny/article/details/126919477
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_9363.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!