基于WebSocket实现客户聊天室

目录

一、实现聊天室原理

二、聊天室前端代码

三、聊天室后端代码(重点)

四、聊天室实现效果展示


一、实现聊天室原理

1.1 介绍websocket协议

websocket是一种通信协议,再通过websocket实现弹幕聊天室时候,实现原理是客户端首先使用http协议请求服务器将通信协议转为websocket协议。

1.2、websocket的API

websocket分为客户端与服务器,其实现的API都不一样。

前端创建websocket案例:

html 复制代码
<script>
let ws = new WebSocket("ws:/localhost/chat")
ws.open = function(){
};

ws.onmessage = function(evt){
    //通过evt.data 可以获取服务器发送的数据
};

ws.onclose = function(){
};
 
</script>

1.3 项目实现流程

1.4 项目结构


二、聊天室前端代码

前端核心在于两个:一个登陆界面,一个聊天室界面。

登陆界面:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <title>聊天室-登录</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="keywords"
          content="Transparent Sign In Form Responsive Widget,Login form widgets, Sign up Web forms , Login signup Responsive web form,Flat Pricing table,Flat Drop downs,Registration Forms,News letter Forms,Elements"/>
    <script type="application/x-javascript">
        addEventListener("load", function () {
            setTimeout(hideURLbar, 0);
        }, false);

        function hideURLbar() {
            window.scrollTo(0, 1);
        }
    </script>

    <script src="js/jquery-1.9.1.min.js"></script>
    <link rel="icon" href="img/chat.ico" type="image/x-icon"/>
    <link rel="stylesheet" href="css/font-awesome.css"/> <!-- Font-Awesome-Icons-CSS -->
    <link rel="stylesheet" href="css/login.css" type="text/css" media="all"/> <!-- Style-CSS -->
</head>


<body class="background">
<div class="header-w3l">
    <h1>聊天室</h1>
</div>
<div class="main-content-agile" id="app">
    <div class="sub-main-w3">
        <h2>登录</h2>
        <form id="loginForm">
            <div class="icon1">
                <input placeholder="用户名" id="username" v-model="user.username" type="text"/>
            </div>

            <div class="icon2">
                <input placeholder="密码" id="password" v-model="user.password" type="password"/>
            </div>

            <div class="clear"></div>
            <input type="button" id="btn1" @click="login" value="登录"/>
			<div class="icon1">
                <span id="err_msg" style="color: red; ">{{errMessage}}</span>
            </div>
        </form>
    </div>
</div>
<div class="footer">
    <p>北京传智播客教育科技有限公司 版权所有Copyright 2006-2019  All Rights Reserved </p>
</div>
<script src="js/vue.js"></script>
<script src="js/axios-0.18.0.js"></script>
<script>
    new Vue({
        el:"#app",
        data() {
            return {
                errMessage: "",
                user:{
                    username:"",
                    password:""
                }
            }
        },
        methods: {
            login() {
                axios.post("user/login",this.user).then(res => {
                    //判断登陆是否成功
                    if(res.data.flag) {
                        location.href = "main.html"
                    } else {
                        this.errMessage = res.data.message;
                    }
                });
            }
        }
    });
</script>
</body>
</html>

效果:

聊天室页面:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <title>黑马畅聊-登录</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="keywords"
          content="Transparent Sign In Form Responsive Widget,Login form widgets, Sign up Web forms , Login signup Responsive web form,Flat Pricing table,Flat Drop downs,Registration Forms,News letter Forms,Elements"/>
    <script type="application/x-javascript">
        addEventListener("load", function () {
            setTimeout(hideURLbar, 0);
        }, false);

        function hideURLbar() {
            window.scrollTo(0, 1);
        }
    </script>

    <script src="js/jquery-1.9.1.min.js"></script>
    <link rel="icon" href="img/chat.ico" type="image/x-icon"/>
    <link rel="stylesheet" href="css/font-awesome.css"/> <!-- Font-Awesome-Icons-CSS -->
    <link rel="stylesheet" href="css/login.css" type="text/css" media="all"/> <!-- Style-CSS -->
</head>


<body class="background">
<div class="header-w3l">
    <h1>聊天室</h1>
</div>
<div class="main-content-agile" id="app">
    <div class="sub-main-w3">
        <h2>登录</h2>
        <form id="loginForm">
            <div class="icon1">
                <input placeholder="用户名" id="username" v-model="user.username" type="text"/>
            </div>

            <div class="icon2">
                <input placeholder="密码" id="password" v-model="user.password" type="password"/>
            </div>

            <div class="clear"></div>
            <input type="button" id="btn1" @click="login" value="登录"/>
			<div class="icon1">
                <span id="err_msg" style="color: red; ">{{errMessage}}</span>
            </div>
        </form>
    </div>
</div>
<div class="footer">
    <p>北京传智播客教育科技有限公司 版权所有Copyright 2006-2019  All Rights Reserved </p>
</div>
<script src="js/vue.js"></script>
<script src="js/axios-0.18.0.js"></script>
<script>
    new Vue({
        el:"#app",
        data() {
            return {
                errMessage: "",
                user:{
                    username:"",
                    password:""
                }
            }
        },
        methods: {
            login() {
                axios.post("user/login",this.user).then(res => {
                    //判断登陆是否成功
                    if(res.data.flag) {
                        location.href = "main.html"
                    } else {
                        this.errMessage = res.data.message;
                    }
                });
            }
        }
    });
</script>
</body>
</html>

三、聊天室后端代码(重点)

3.1首先需要创建springboot项目,并导入以下jar包.

XML 复制代码
<!--        使用阿里巴巴的fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>

<!--        实现websocket的jar包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

3.2 实现websocket,还需要对其进行配置,创建两个配置类

第一个进行websocketConfig的配置

java 复制代码
@Configuration
public class WebsocketConfig {

// 将ServerEndPointExplorer加入ioc容器中
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

第二个配置是获取httpsession配置

java 复制代码
public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {

    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        //获取HttpSession对象
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        //将httpSession对象保存起来
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}

项目中需要ServerEndPoint存储所有用户的session对象,通过session实现用户之间的交流。所以还需要获取所有httpsession对象。

3.3 确定消息格式(JSON)

为了确保实现的消息格式的准确,需要创建对应工具类,确保对应的格式的准确。

java 复制代码
public class MessageUtils {

    public static String getMessage(boolean isSystemMessage,String fromName, Object message) {

        ResultMessage result = new ResultMessage();
        result.setSystem(isSystemMessage);
        result.setMessage(message);
        if(fromName != null) {
            result.setFromName(fromName);
        }
        return JSON.toJSONString(result);
    }
}

3.4 然后就是所有实体类的创建。

对于前端实体类,需要用户,封装http请求实体。

对于聊天室,需要用户发送的信息,服务器给用户发送的信息。

java 复制代码
@Data
public class Result {
    private boolean flag;
    private String message;
}
java 复制代码
@Data
public class User {

    private String userId;
    private String username;
    private String password;
}
java 复制代码
@Data
public class Message {
    private String toName;
    private String message;
}
java 复制代码
@Data
public class ResultMessage {

    private boolean isSystem;
    private String fromName;
    private Object message;//如果是系统消息是数组
}

3.5 后端基础功能的实现

后端实现登陆功能:用户名可以随意输入,但是密码必须是123。

java 复制代码
    @PostMapping("/login")
    public Result login(@RequestBody User user, HttpSession session) {
        Result result = new Result();
        if(user != null && "123".equals(user.getPassword())) {
            result.setFlag(true);
            //将数据存储到session对象中
            session.setAttribute("user",user.getUsername());
        } else {
            result.setFlag(false);
            result.setMessage("登陆失败");
        }
        return result;
    }

后端实现获取用户名称功能:

java 复制代码
 @GetMapping("/getUsername")
    public String getUsername(HttpSession session) {

        String username = (String) session.getAttribute("user");
        return username;
    }

3.6 通过session发送消息的核心功能**(重点)**

java 复制代码
@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfig.class)
@Component
public class ChatEndpoint {

    private static Map<String,Session> onlineUsers = new ConcurrentHashMap<>();

    static {
        // 初始化onlineUsers对象
        onlineUsers = new ConcurrentHashMap<>();
    }

    private HttpSession httpSession;

    /**
     * 建立websocket连接后,被调用
     * @param session
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        //1,将session进行保存
        this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        String user = (String) this.httpSession.getAttribute("user");
        onlineUsers.put(user,session);
        //2,广播消息。需要将登陆的所有的用户推送给所有的用户
        String message = MessageUtils.getMessage(true,null,getFriends());
        broadcastAllUsers(message);
    }

    public Set getFriends() {
        Set<String> set = onlineUsers.keySet();
        return set;
    }

    private void broadcastAllUsers(String message) {
        try {
            //遍历map集合
            Set<Map.Entry<String, Session>> entries = onlineUsers.entrySet();
            for (Map.Entry<String, Session> entry : entries) {
                //获取到所有用户对应的session对象
                Session session = entry.getValue();
                //发送消息
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            //记录日志
        }
    }

    /**
     * 浏览器发送消息到服务端,该方法被调用
     *
     * 张三  -->  李四
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        try {
            //将消息推送给指定的用户
            Message msg = JSON.parseObject(message, Message.class);
            //获取 消息接收方的用户名
            String toName = msg.getToName();
            String mess = msg.getMessage();
            //获取消息接收方用户对象的session对象
            Session session = onlineUsers.get(toName);
            String user = (String) this.httpSession.getAttribute("user");
            String msg1 = MessageUtils.getMessage(false, user, mess);
            session.getBasicRemote().sendText(msg1);
        } catch (Exception e) {
            //记录日志
        }
    }

    /**
     * 断开 websocket 连接时被调用
     * @param session
     */
    @OnClose
    public void onClose(Session session) {
        //1,从onlineUsers中剔除当前用户的session对象
        String user = (String) this.httpSession.getAttribute("user");
        onlineUsers.remove(user);
        //2,通知其他所有的用户,当前用户下线了
        String message = MessageUtils.getMessage(true,null,getFriends());
        broadcastAllUsers(message);
    }
}

代码重点在于对session的使用,将内容放在对应用户session的共享域中,后端则负责统一管理所有用户的session。


四、聊天室实现效果展示

4.1 登陆功能:

4.2 在线与不在线,当后端运行后才能显示在线

4.3 当有其他人登陆时候弹出对应用户名称

4.4 通过点击对应的名称进行一对一聊天

4.5 实现聊天功能


相关推荐
ONE_PUNCH_Ge14 分钟前
Go 语言泛型
开发语言·后端·golang
良许Linux27 分钟前
DSP的选型和应用
后端·stm32·单片机·程序员·嵌入式
Godspeed Zhao28 分钟前
现代智能汽车系统——网络
网络·汽车
不光头强35 分钟前
spring boot项目欢迎页设置方式
java·spring boot·后端
怪兽毕设1 小时前
基于SpringBoot的选课调查系统
java·vue.js·spring boot·后端·node.js·选课调查系统
学IT的周星星1 小时前
Spring Boot Web 开发实战:第二天,从零搭个“会卖萌”的小项目
spring boot·后端·tomcat
郑州光合科技余经理1 小时前
可独立部署的Java同城O2O系统架构:技术落地
java·开发语言·前端·后端·小程序·系统架构·uni-app
Remember_9932 小时前
Spring 事务深度解析:实现方式、隔离级别与传播机制全攻略
java·开发语言·数据库·后端·spring·leetcode·oracle
未来之窗软件服务2 小时前
自己平台接入国家网络身份认证公共服务接入
网络·仙盟创梦ide·东方仙盟
要做一个小太阳2 小时前
华为Atlas 900 A3 SuperPoD 超节点网络架构
运维·服务器·网络·华为·架构