Java+WebSocket制作聊天室(私聊与群聊)

WebSocket是一种在单个TCP连接上进行全双工通信的协议。顾名思义我们的使用经常就是用于进行实时的消息推送,今天我们是用SpringBoot来实现简易的聊天室,其中包括私聊和群聊。
首先是先把自己需要的界面弄好,我就简单的制作了一下
在这里插入图片描述
讲解一下界面的设计,首先我们是需要有发送方和接收方,我是用用户id来记录,然后他们都是需要用session来保存,相当于是系统的用户在线状态嘛,所以首先步骤一,要进行用户登录(创建连接),然后就是请求获取设计好的websocket服务,连接好了服务就是相当于在一个聊天室内,如果没有指定接收方时就是群聊,有接收方就是私聊。
接下来就是代码啦,先给出html的代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<html>
	<head>
		<meta charset="utf-8" />
		<title>WebSocket</title>
	</head>
	<script src="jquery-3.4.1.min.js"></script>
	<script type="text/javascript" src="websocket.js"></script>
	<script type="text/javascript" src="mine.js"></script>
	<style>
		#responseText{
			width:237px;
			height: 200px;
			border: 1px solid;
		}
		.userId{
			width: 110px;
		}
	</style>
	<body>
		<input type="text" id="sendId" class="userId"  placeholder="输入连接的用户ID" />
		<button onclick="checkTextById('sendId');createUser();">创建连接</button>
		<button onclick="checkTextById('sendId');openSocket();">请求连接</button><br /><br />
		<input type="text" id="requestText" placeholder="输入你的内容" />
		<input type="text" id="receiveId" class="userId" placeholder="输入接收的用户ID" />
		<button onclick="checkTextById('requestText');sendMessage();">发送消息</button><br /><br />
		<!--显示结果-->
		<div id="responseText">聊天室:</div><br />
		<span id="serverTxt">尚未连接服务</span>
	</body>
</html>

js代码:

//websocket.js

var socket;//注意:360浏览器不支持websocket
function openSocket() {
    if(typeof(WebSocket) == "undefined") {
        console.log("您的浏览器不支持WebSocket");
    }else {
        console.log("您的浏览器支持WebSocket");
        //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
        var userId = document.getElementById('sendId').value;
        var socketUrl = "ws://localhost:19429/webSocket/" + userId;
        console.log(socketUrl);
        if (socket != null) {
            socket.close();
            socket = null;
        }
        socket = new WebSocket(socketUrl);
        //打开事件
        socket.onopen = function () {
            console.log("websocket已打开");
            document.getElementById('serverTxt').innerText = userId+"已连接websocket";
            //socket.send("这是来自客户端的消息" + location.href + new Date());
        };
        //获得消息事件
        socket.onmessage = function (msg) {
            var serverMsg = "收到服务端信息:" + msg.data;
            console.log("类型:" + typeof (msg.data));
            var msgJson = eval('(' + msg.data + ')');
            var div = document.createElement("div");
            var responseText = document.getElementById('responseText');
            var type = "(私聊)";
            if (null == msgJson.toUserId || msgJson.toUserId == "") {
                type = "(群聊)";
            }
            div.innerHTML = msgJson.userId+type+":"+msgJson.contentText;
            responseText.appendChild(div);
            console.log(serverMsg);
            //发现消息进入    开始处理前端触发逻辑
        };
        //关闭事件
        socket.onclose = function () {
            console.log("websocket已关闭");
            document.getElementById('serverTxt').innerText = "尚未连接服务";
        };
        //发生了错误事件
        socket.onerror = function () {
            console.log("websocket发生了错误");
        }
    }
}

//websocket发送消息
function sendMessage() {
    var toUserId = document.getElementById('receiveId').value;//接收的用户ID
    var userId = document.getElementById('sendId').value;//发送的用户ID
    var contentText = document.getElementById('requestText').value;
    if(typeof(WebSocket) == "undefined") {
        console.log("您的浏览器不支持WebSocket");
    }else {
        // console.log("您的浏览器支持WebSocket");
        if (userId.trim().length>0 && contentText.trim().length>0){
            var msg = '{"userId":"'+userId+'","toUserId":"'+toUserId+'","contentText":"'+contentText+'"}';
            console.log(msg);
            socket.send(msg);
            if (toUserId.trim().length>0){
                var responseText = document.getElementById('responseText');
                var div = document.createElement("div");
                div.innerHTML = userId+"(私聊):"+contentText;
                responseText.appendChild(div);
            }
            alert("发送成功!");
        }else {
            alert("发送失败!");
        }
   }
}


//mine.js

//通过id判断文本组件是否为空
function checkTextById(id) {
    var Txt = document.getElementById(id);

    //判断是否存在这个组件
    if (Txt!=null){
        if (Txt.value.trim().length==0){
           alert("内容不允许为空!");
        }
    }else{
        alert("id为"+id+"组件不存在!");
    }
}

function createUser() {
    var userId = document.getElementById("sendId").value;
    if (userId.trim().length>0) {
        $.ajax({
            url: "/createUser",
            async: true,
            type: "POST",
            data: {"userId":userId},
            success: function (data) {
                if (data=="1"){
                    document.getElementById('serverTxt').innerText = userId+"已创建";
                }
            },
            error: function () {
                alert("请求失败");
            },
            dataType: "text"
        });
    }else{
        alert("创建用户id不能为空!");
    }
}

java代码部分我是通过搭建SpringBoot项目的,不过不影响使用,先贴出代码部分,首先需要有转换session的工具类,然后还需要登陆(创建session),用户实体类只需要弄一个uuid即可。

配置类以及转换类:

//配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebConfig {
    /**
     * 支持websocket
     * 如果不使用内置tomcat,则无需配置
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}


//转换session
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

/**
 * 用于从websocket中获取用户session
 */
public class HttpSessionConfigurator extends ServerEndpointConfig.Configurator  {

    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        sec.getUserProperties().put(HttpSession.class.getName(), httpSession);
    }
}

websocket服务:

import com.alibaba.fastjson.JSONObject;
import com.example.demo.config.HttpSessionConfigurator;
import com.example.demo.po.User;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

//注入 HttpSessionConfigurator.class配置httpSession类
@ServerEndpoint(value = "/webSocket/{sid}",configurator =  HttpSessionConfigurator.class)
@Component
public class WebSocketServer {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static AtomicInteger onlineNum = new AtomicInteger();

    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    //发送消息
    public void sendMessage(Session session, String message) throws IOException {
        if(session != null){
            synchronized (session) {
//                System.out.println("发送数据:" + message);
                session.getBasicRemote().sendText(message);
            }
        }
    }

    //给指定用户发送信息
    public void sendInfo(String userId, String message){
        Session session = sessionPools.get(userId);
        try {
            if (sessionPools.get(userId) != null){
                sendMessage(session, message);
            }else{
                System.out.println("用户"+userId+"不在线");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "sid") String userId, EndpointConfig config){
        try {
            HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
            User user = (User) httpSession.getAttribute("userSession");
            //判断是否还需加入连接
            if (user!=null && !sessionPools.containsKey(user.getUuid())){
                sessionPools.put(String.valueOf(user.getUuid()), session);
                addOnlineCount();
                System.out.println(userId + "加入webSocket!当前人数为" + onlineNum);
                sendMessage(session, "欢迎" + user.getUuid() + "加入连接!");
            }else{
                System.out.println("没有连接加入,当前人数为"+onlineNum);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //关闭连接时调用
    @OnClose
    public void onClose(@PathParam(value = "sid") String userId){
        //判断是否有连接
        if (sessionPools.containsKey(userId)){
            sessionPools.remove(userId);
            subOnlineCount();
            System.out.println(userId + "断开webSocket连接!当前人数为" + onlineNum);
        }else{
            System.out.println("用户"+userId+"不存在连接,无需断开连接");
        }
    }

    //收到客户端信息
    @OnMessage
    public void onMessage(String message){
        try {
            //转换成为JSONObject对象
            JSONObject jsonObj = JSONObject.parseObject(message);

            if (jsonObj.containsKey("toUserId") && !"".equals(jsonObj.get("toUserId"))){
                //指定用户
                sendInfo((String) jsonObj.get("toUserId"),message);
            }else{
                //群发
                for (Session session: sessionPools.values()) {
                    try {
                        sendMessage(session, message);
                    } catch(Exception e){
                        e.printStackTrace();
                        continue;
                    }
                }
            }
        } catch(Exception e){
            e.printStackTrace();
        }
    }

    //错误时调用
    @OnError
    public void onError(Session session, Throwable throwable){
        System.out.println("发生错误");
        throwable.printStackTrace();
    }

    //增加在线人数
    public static void addOnlineCount(){
        onlineNum.incrementAndGet();
    }

    //减少在线人数
    public static void subOnlineCount() {
        onlineNum.decrementAndGet();
    }
}

最后效果如下:
在这里插入图片描述
需要注意的是:
1.需要先创建连接(即创建session)
2.创建连接后要连接服务(加入至聊天室)
3.不指定接收方则是群聊

代码在资源里O(∩_∩)O

  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
对于JavaWebSocket的下载,你可以按照以下步骤进行操作: 1. 首先,你需要在Java项目中添加WebSocket的依赖。可以在项目的pom.xml文件中添加以下依赖项: ```xml <dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.1</version> </dependency> ``` 2. 接下来,你需要创建一个WebSocket的配置类。这个配置类需要使用`@Configuration`注解,并且需要添加`@Bean`注解来创建`ServerEndpointExporter`的实例。这个实例将帮助你支持WebSocket。以下是一个示例配置类: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } ``` 3. 然后,你需要创建一个WebSocket的处理类。这个类需要使用`@ServerEndpoint`注解,并且需要实现WebSocket的相关方法。你可以在这个类中处理WebSocket的连接、消息接收和发送等操作。以下是一个示例处理类: ```java import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/websocket") public class WebSocketHandler { @OnOpen public void onOpen(Session session) { // 处理WebSocket连接的逻辑 } @OnMessage public void onMessage(String message, Session session) { // 处理WebSocket消息的逻辑 } } ``` 4. 最后,你可以在你的Java项目中使用WebSocket。你可以在前端使用JavaScript的WebSocket对象来与后端的WebSocket进行通信。以下是一个示例的JavaScript代码: ```javascript var socket = new WebSocket("ws://localhost:8080/websocket"); socket.onopen = function() { // WebSocket连接成功后的逻辑 }; socket.onmessage = function(event) { var message = event.data; // 处理接收到的WebSocket消息的逻辑 }; socket.onclose = function() { // WebSocket连接关闭后的逻辑 }; function sendMessage(message) { socket.send(message); // 发送WebSocket消息的逻辑 } ``` 这样,你就可以在Java项目中使用WebSocket进行通信和数据传输了。希望对你有帮助! #### 引用[.reference_title] - *1* [java+vue+websocket实现实时获取kubernetes pod日志并展示](https://blog.csdn.net/xujingyiss/article/details/121749011)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [java+ffmpeg+websocket+jsmpeg 调用摄像头RTSP在浏览器显示](https://blog.csdn.net/qq_36304149/article/details/114983991)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Java+WebSocket制作聊天与群)](https://blog.csdn.net/weixin_43316702/article/details/118469339)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谦风(Java)

一起学习,一起进步(✪ω✪)

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值