WebSocket笔记②——利用WebSocket实现点对点聊天(待完善)

点对点聊天工程

采用的springboot框架搭建的mvc项目

依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.0.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
        <version>2.0.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>webjars-locator-core</artifactId>
        <version>0.40</version>
    </dependency>
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>sockjs-client</artifactId>
        <version>1.0.2</version>
    </dependency>
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>stomp-websocket</artifactId>
        <version>2.3.3</version>
    </dependency>
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>bootstrap</artifactId>
        <version>3.3.7</version>
    </dependency>
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>jquery</artifactId>
        <version>3.1.0</version>
    </dependency>
</dependencies>

前端

这里是采用的layui框架搭建的一个简单页面,总共有三个页面,登陆页面、聊天页面和主页面。

js和css文件

layui的js、css和图片文件,还有layui依赖的jquery框架
在这里插入图片描述

登陆页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>layout 后台大布局 - Layui</title>
    <link rel="stylesheet" href="/layui/css/layui.css">
</head>
    <body>
        <div id="loginForm" style="width: 500px">
            <form class="layui-form" action="/login" method="post">
                <div class="layui-form-item" style="padding-top:10px;">
                    <label class="layui-form-label">用戶名</label>
                    <div class="layui-input-inline">
                        <input type="text" name="username" required  lay-verify="required" placeholder="请输入用戶名" autocomplete="off" class="layui-input">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">密码框</label>
                    <div class="layui-input-inline">
                        <input type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
                    </div>
                    <div class="layui-form-mid layui-word-aux">辅助文字</div>
                </div>

                <div class="layui-form-item">
                    <div class="layui-input-block">
                        <button class="layui-btn" id="luban" lay-submit lay-filter="luban">立即提交</button>
                        <button type="reset" class="layui-btn layui-btn-primary">重置</button>
                    </div>
                </div>
            </form>
        </div>
    </body>


<script src="jquery.js"></script>
<script src="/layui/layui.js"></script>
<script>

    layui.use('layer', function() {
        layer.open({
            type: 1,
            content: $('#loginForm'),
            maxWidth: 600
        });
    });

</script>
</html>

主界面

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>layout 后台大布局 - Layui</title>
    <link rel="stylesheet" href="/layui/css/layui.css">
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
    <div class="layui-header">
        <div class="layui-logo">layui 后台布局</div>
        <!-- 头部区域(可配合layui已有的水平导航) -->
        <ul class="layui-nav layui-layout-left">
            <li class="layui-nav-item"><a href="">控制台</a></li>
            <li class="layui-nav-item"><a href="">商品管理</a></li>
            <li class="layui-nav-item"><a href="">用户</a></li>
            <li class="layui-nav-item">
                <a href="javascript:;">其它系统</a>
                <dl class="layui-nav-child">
                    <dd><a href="">邮件管理</a></dd>
                    <dd><a href="">消息管理</a></dd>
                    <dd><a href="">授权管理</a></dd>
                </dl>
            </li>
        </ul>
        <ul class="layui-nav layui-layout-right">
            <li class="layui-nav-item">
                <a href="javascript:;">
                    <img src="http://t.cn/RCzsdCq" class="layui-nav-img">
                    贤心
                </a>
                <dl class="layui-nav-child">
                    <dd><a href="">基本资料</a></dd>
                    <dd><a href="">安全设置</a></dd>
                </dl>
            </li>
            <li class="layui-nav-item"><a href="">退了</a></li>
        </ul>
    </div>

    <div class="layui-side layui-bg-black">
        <div class="layui-side-scroll">
            <!-- 左侧导航区域(可配合layui已有的垂直导航) -->
            <ul class="layui-nav layui-nav-tree"  lay-filter="test" id="onLine">

            </ul>
        </div>
    </div>

    <div class="layui-body">
        <!-- 内容主体区域 -->
        <div style="padding: 15px;">内容主体区域</div>
    </div>

    <div class="layui-footer">
        <!-- 底部固定区域 -->
        © layui.com - 底部固定区域
    </div>

    <!--找谁聊天的人的名字 sendToUserName -->
    <input id="sendUsername">

</div>
<script src="/layui/layui.js"></script>
<script src="/jquery.js"></script>
<script src="/webjars/sockjs-client/1.0.2/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/2.3.3/stomp.min.js"></script>
<script src="app.js"></script>


<script>
    //JavaScript代码区域
    layui.use('element', function(){
        var element = layui.element;
        // element.render("nav");
    });

    $(function(){
        var info="";
        $.ajax({
            url:"/userInfo",//发送在线人数给所有客户端
            type:"post",
            dataType:"json",
            success:function(data){
                console.log(data);
                info=data.info;
            }

        });
        //连接ws
        var socket = new SockJS('/luban');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            //订阅-------获取在线人数
            stompClient.subscribe('/topic/userList', function (data) {
                initOnLine(data.body)
            });
            //訂閲  聊天的消息,發給我
            stompClient.subscribe('/user/'+info+"/luban", function (data) {
                console.log(data);
            });

            $.ajax({
                url:"/userList",//发送在线人数给所有客户端
                type:"post",
                dataType:"json",
                success:function(data){

                }

            })
        });



    })


    function chat(obj){

        //把sendToUserName存到一个input
        $("#sendUsername").val(obj);

        layui.use('layer', function() {
            layer.open({
                area: ['700px', '900px'],
                type: 2,
                content: 'chat.html',
                maxWidth: 600,
            });
        });

    }
    function initOnLine(data){
        //user1,user2,user3,user4
        data = data.split(",");
        //[user1,user2.....]
        $("#onLine").html("");

        $.each(data,function(i,v){
            $("#onLine").append(" <li class=\"layui-nav-item\"><a href=\"javascript:chat(\'"+v+"\')\">"+v+"</a></li>");
        })
    }
</script>
</body>
</html>

聊天页面

<!DOCTYPE html>   
<html>   
<head>   
    <meta charset="UTF-8">   
    <title>HTML5模拟微信聊天界面</title> 
	<style>
		#container{
			    border-radius: 10px;
				width: 450px;
				height: 700px;
				background: #f3f2f2;
				margin: 80px auto;
				position: relative;
				box-shadow: 10px 40px 55px #e8e5e5;
		}
		#header{
			    background: #191818;
				height: 50px;
				color: #fff;
				border-radius: 2px;
				line-height: 50px;
				text-align: center;
				font-size: 12px;
		}
		#footer{
				text-align:center;
				position: absolute;
				bottom: 0;
				background: #1f1e1e;
				width: 450px;
				height: 50px;
				border-radius: 2px;
		}
		
		#footer input{
				padding-left: 6px;
				float:left;
				width: 360px;
				height: 30px;
				border-radius: 6px;
				margin: 8px 10px;
				border: 0px;
		}
		#sendButton{
				font-weight: 800;
				font-size: 10px;
				background: #0e8007;
				width: 45px;
				height: 30px;
				float: left;
				line-height: 30px;
				margin: 8px;
				border-radius: 4px;
				cursor: pointer;
		}
		#content{
				overflow: auto;
				height:600px;
				width:450px;
				margin:0;
				padding:5px;
				list-style: none;
		}
		#content li{
			list-style-type:none;
			clear: both;
			overflow: hidden;
		
		}
		.msg{
			padding: 10px;
			max-width: 300px;
			height: 30px;
			background: #7cbb55;
			float: right;
			margin-right: 10px;
			border-radius: 6px;
			line-height: 30px;
			text-align: center;
		}
	</style>
</head>
	<body>
		<div id="container">
			<div id="header">
				安琪拉小姐姐
			</div>
			
			<ul id="content">
				<li>
					<div class="msg">
						fdsfsdfdsfdsfds
					<div>
				</li>
			</ul>
			
			<div id="footer">
				<div id="sendBox">
					<input id="sendVal">
				</div>
				<div id="sendButton">发送</div>
			</div>
			
		</div>
	</body>
<script src="/jquery.js"></script>
<script src="/webjars/sockjs-client/1.0.2/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/2.3.3/stomp.min.js"></script>
<script>
	var sendToname ="";//發送給誰
    var info = "";//自己是誰
    $(function() {
        sendToname = parent.$("#sendUsername").val();
        $("#sendButton").click(function () {
            var chatMsg = $("#sendVal").val();
            $.ajax({
                url: "/chat",//发送在线人数给所有客户端
                type: "post",
				data:'message='+chatMsg+'&username='+sendToname,
                dataType: "json",
                success: function (data) {
                    //info = data.info;
                }
            });
        });




        var socket = new SockJS('/luban');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            console.log(sendToname+"pppppppppppppppppppppppp")
            //訂閲  聊天的消息,發給我
            stompClient.subscribe('/user/' +info+"/luban", function (data) {
                console.log(data);
            });

        });

    })

</script>
</html>

后端

websocket配置类

需要注册相关的订阅路径,配置监听的路径

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        //允许订阅的前缀
        config.enableSimpleBroker("/topic","/user");

        //路由到controller
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/luban").withSockJS();
    }

}

Controller

package com.luban.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Controller
public class LubanController {

    @Autowired
    SimpMessagingTemplate template;


    /**
     * 登录的controller
     * @param username
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping("/login")
    public void login(String username, HttpServletRequest request, HttpServletResponse response) throws IOException {
        //维护一个在线人员的列表
        Contains.list.add(username);
        //把当前登录人存到session
        request.getSession().setAttribute("uname",username);
        response.sendRedirect("main.html");
    }


    /**
     * 获取当前登录的用户信息
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    @RequestMapping("/userInfo")
    @ResponseBody
    public String login(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String info = request.getSession().getAttribute("uname").toString();
        return "{\"info\":\""+info+"\"}";
    }

    /**
     * server 更新在线人数列表的方法
     * 他会给所有订阅了/topic/userList的ws客户端发送消息
     * @return
     */
    @RequestMapping("/userList")
    @ResponseBody
    public String userList(){
        String allUser="";
        for (String s : Contains.list) {
            allUser+=s+",";
        }
        allUser =   allUser.substring(0,allUser.length()-1);
        template.convertAndSend("/topic/userList",allUser);
        return "success";
    }


    /**
     * 客户端发送消息方法
     * @param message
     * @param username
     * @return
     */
    @RequestMapping("/chat")
    @ResponseBody
    public String chat(String message,String username){
        System.out.println("-------------------"+message+"---"+username);
        //convertAndSend("/user/'user3'/luban")
        template.convertAndSendToUser(username,"luban",message);
        return  "success";
    }
}

下面的类是做缓存作用的

public class Contains {

    public static List<String> list = new ArrayList();
}

启动类

@SpringBootApplication
public class Testws {
    public static void main(String[] args) {
        SpringApplication.run(Testws.class);
    }
}

效果

  • 登陆界面

在这里插入图片描述

  • 主界面

左侧显示在线人员
在这里插入图片描述

  • 聊天界面

点击左侧的其他用户会弹出聊天窗口
在这里插入图片描述
在聊天框中输入消息后点击发送消息
在这里插入图片描述
可以收到发送过来的消息
在这里插入图片描述

整体架构图

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值