基于STOMP协议 实现的简单在线聊天 技术点:springboot+websocket+sockjs

1、websocket 简单了解

WebSocket协议RFC 6455提供了一种标准化方法,可以通过单个TCP连接在客户端和服务器之间建立全双工双向通信通道。它是与HTTP不同的TCP协议,但旨在通过端口80和443在HTTP上工作,并允许重复使用现有的防火墙规则。

WebSocket交互始于一个HTTP请求,该请求使用HTTP Upgrade标头进行升级,或者在这种情况下切换到WebSocket协议。以下示例显示了这种交互:

GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket (1)
Connection: Upgrade  (2)
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080

(1)该Upgrade

(2)使用Upgrade连接

具有WebSocket支持的服务器代替通常的200状态代码,返回类似于以下内容的输出:

HTTP/1.1 101 Switching Protocols 
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp

以上均摘自spring官网,具体的就不介绍了,我把链接放这里,需要了解的自己点开看好了

具体链接:点我去spring官网查看具体的websocket

2、具体实现

主要功能:  1、联系人列表上要有所有上线的人员,并且实现实时更新

                  2、实现一对一的在线实时聊天

先上效果图:

2个浏览器  模拟 唐僧 和悟空 登录

唐僧找悟空聊天

唐僧发了: 空空,我们去花果山ktv吧

悟空回复:不去,你上次还没有结账呢

一个简易的实时在线聊天,这是个简单的demo,所以布局和聊天的逻辑还不是很完善。

这个效果实现需要的了解几个知识:

1、前端:ui框架是用的layui  可以自行百度了解一下

                2 个html互相传值的问题,网上大概有3中方法,这里用的是window.open和window.opener之间传值。

2、后端:springboot+websocket  

 先上后端的代码:

pom.xml 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.demo.chat</groupId>
    <artifactId>chat-chat</artifactId>
    <version>1.0-SNAPSHOT</version>



    <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>
        </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>
</project>

WebSocketConfig类 

用来配置WebSocketConfig相关信息

@Configuration
///注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    /**
     * 配置消息代理
     * @param config
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        //允许订阅的前缀   点对点应配置一个/user消息代理,广播式应配置一个/topic消息代理
        config.enableSimpleBroker("/topic","/user");

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


    /**
     * //注册STOMP协议的节点(chat),并映射指定的url
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //注册一个STOMP的endpoint,并指定使用SockJS协议
        registry.addEndpoint("/chat").withSockJS();
    }
}

ChatController类 

用来处理更新在线人数  点对点实时消息发送

@Controller
public class ChatController {
    @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("/chatInfo")
    @ResponseBody
    public String chat(String message,String username){
        System.out.println("-------------------"+message+"---"+username);

        template.convertAndSendToUser(username,"chat",message);
        return  "success";
    }

}

Application类  

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

}

前端界面就不展示,毕竟是简单的实现,把主要的js代码贴上来。

chat.html的 js代码:

<script>
	var sendToname ="";//发送给谁
    var info = "";//自己是誰

    $(function() {



        sendToname = parent.$("#sendUsername").val();
        info = parent.$("#loginName").val();

        $("#header").text(sendToname); //设置聊天信息的人
        $("#sendButton").click(function () {
            var chatMsg = $("#sendVal").val();
            $.ajax({
                url: "/chatInfo",// 发送聊天信息给对应的人
                type: "post",
				data:'message='+chatMsg+'&username='+sendToname,
                dataType: "json",
                success: function (data) {

                }
            });
        });




        var socket = new SockJS('/chat');

        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {

            //订阅聊天的消息,发给我
            stompClient.subscribe('/user/'+info+"/chat", function (data) {
                console.log("我收到信息了----------"+data.body);
                initChatData(data.body);
            });

        });

    })

    function initChatData (messgae) {

		//动态添加聊天信息
        $("#content").append(" <li ><div class=\"msg\">"+messgae+"</div></li>");

    };

</script>

contacts.html的 js代码:

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

    $(function(){

        $.ajax({
            url:"/userInfo",//发送在线人数给所有客户端
            type:"post",
            dataType:"json",
            success:function(data){
                console.log("当前登录的用户:"+data);
                info=data.info;
                $("#loginName").val(data.info); //存下当前登录的名字
            }

        });
        //连接ws
        var socket = new SockJS('/chat');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            //订阅-------获取在线人数
            stompClient.subscribe('/topic/userList', function (data) {
                initOnLine(data.body)
            });
           /* //訂閲  聊天的消息,發給我
            stompClient.subscribe('/user/'+info+"/chat", function (data) {
                console.log("当前"+info+"我收到的消息:"+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){
            if (info==v){
                //如果当前登录的是自己,则标注是(自己)
                $("#onLine").append(" <li class=\"layui-nav-item\"><a href=\"javascript:chat(\'"+v+"\')\">"+v+' (自己)'+"</a></li>");
            }else {
                $("#onLine").append(" <li class=\"layui-nav-item\"><a href=\"javascript:chat(\'"+v+"\')\">"+v+"</a></li>");
            }


        })
    }
</script>

代码比较简单,上面都有注释,有问题谢谢指正。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值