springboot整合websocket实现简单聊天功能

什么是websocket?

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议,使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

WebSocket消息推送流程

由于springboot创建项目相对比较简单,配置也很简单

使用idea创建一个springboot项目

需要的依赖:

选上这几个就够了

pom文件: 

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xiaomifeng1010</groupId>
    <artifactId>websocketdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>websocketdemo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

项目结构:

前端文件放在static文件夹下:

show.html

<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>测试websocket点对点发送</title>
<script src="js/websocket.js"></script>
<script src="js/jquery.min.js"></script>
<script src="js/sockjs.min.js"></script>
<script src="js/stomp.min.js"></script>
<script id="code">
    var DEBUG_FLAG = true;
    $(function()
    {
        //启动websocket
        connect();
    });

    function send() {
      var msg = $("#msg").val();
      stompClient.send("/send", {}, msg);
    }

    function sendToUser() {
      var msg = $("#msg").val();
      var toUserId = $("#userId").val();
      var data  = {"fromUserId": userId, "toUserId": toUserId, "msg": msg};
      stompClient.send("/sendToUser", {}, JSON.stringify(data));
    }
</script>
</head>

<body style="margin: 0px;padding: 0px;overflow: hidden; ">
  <!-- 显示消息-->
  <textarea id="debuggerInfo" style="width:100%;height:200px;"></textarea>
  <!-- 发送消息-->
  <div>用户:<input type="text" id="userId"></input></div>
  <div>消息:<input type="text" id="msg"></input></div>
  <div><input type="button" value="发送消息" onclick="sendToUser()"></input></div>
</body>
</html>

 js文件有三个min.js的是开源库需要自己下载,还有一个js文件websocket.js是自定义的js文件

websocket.js

var stompClient = null;
var wsCreateHandler = null;
var userId = null;

function connect() {
    var host = window.location.host; // 带有端口号
    userId =  GetQueryString("userId");
    var socket = new SockJS("http://" + host + "/websocket");
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function (frame) {
            writeToScreen("connected: " + frame);
            stompClient.subscribe('/topic', function (response) {
                writeToScreen(response.body);
            });

            stompClient.subscribe("/user/" + userId + "/topic", function (response) {
                writeToScreen(response.body);
            });

            stompClient.subscribe('/sendToAll', function (response) {
                writeToScreen("sendToAll:" + response.body);
            });

        }, function (error) {
            wsCreateHandler && clearTimeout(wsCreateHandler);
            wsCreateHandler = setTimeout(function () {
                console.log("重连...");
                connect();
                console.log("重连完成");
            }, 1000);
        }
    )
}

function disconnect() {
    if (stompClient != null) {
        stompClient.disconnect();
    }
    writeToScreen("disconnected");
}

function writeToScreen(message) {
    if(DEBUG_FLAG)
    {
        $("#debuggerInfo").val($("#debuggerInfo").val() + "\n" + message);
    }
}

function GetQueryString(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
    var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配
    var context = "";
    if (r != null)
        context = r[2];
    reg = null;
    r = null;
    return context == null || context == "" || context == "undefined" ? "" : context;
}

后端的配置及代码

application.properties中只配置了服务器端口就可以了

server.port=8939

启动类和servlet初始化类

package com.xiaomifeng1010.websocket;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebsocketdemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebsocketdemoApplication.class, args);
    }

}
package com.xiaomifeng1010.websocket;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebsocketdemoApplication.class);
    }

}

这项目中有两个项目包configuration包和controller包

配置类:

package com.xiaomifeng1010.websocket.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry){
        //客户端连接端点
        registry.addEndpoint("/websocket")
                .setAllowedOrigins("*")
                .withSockJS();
    }


    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic/","/queue/");
        registry.setUserDestinationPrefix("/queue/");
        registry.setApplicationDestinationPrefixes("/app");
    }

}

@EnableWebSocketMessageBroker 作用是开启websocket服务,registerStompEndpoints方法配置websocket消息服务端

controller类

package com.xiaomifeng1010.websocket.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;


@RestController
public class WebsocketController {
    @Autowired
    private SimpMessagingTemplate template;

    @MessageMapping("/sendToAll")
    public String sendToAll(String msg) {
        return msg;
    }


     //@MessageMapping("/sendToAll")
    //public void sendToAll(String msg) {
    //    String destination = "/queue/chat";
     //   template.convertAndSend(destination, msg);
    //}

    @MessageMapping("/send")
    @SendTo("/topic")
    public String say(String msg) {
        return msg;
    }

    @MessageMapping("/sendToUser")
    public void sendToUserByTemplate(Map<String,String> params) {
        String fromUserId = params.get("fromUserId");
        String toUserId = params.get("toUserId");
        String msg = "来自" + fromUserId + "消息:" + params.get("msg");

        template.convertAndSendToUser(toUserId,"/topic", msg);
    }

    @GetMapping("/sendToAllByTemplate")
    @MessageMapping("/sendToAllByTemplate")
    public void sendToAllByTemplate(@RequestParam String msg) {
        template.convertAndSend("/topic", msg);
    }

    @GetMapping("/send")
    public String msgReply(@RequestParam String msg) {
        template.convertAndSend("/topic", msg);
        return msg;
    }
}

@MessageMapping的作用类似@requestMapping的作用,声明请求映射路径的

1、@SendTo 不通用,固定发送给指定的订阅者
 2、@SimpMessagingTemplate 灵活,支持多种发送方式
现在的show.html文件中发请求是发到"/sendToUser"这个请求的

  @MessageMapping("/sendToUser")
    public void sendToUserByTemplate(Map<String,String> params) {
        String fromUserId = params.get("fromUserId");
        String toUserId = params.get("toUserId");
        String msg = "来自" + fromUserId + "消息:" + params.get("msg");

        template.convertAndSendToUser(toUserId,"/topic", msg);
    }

可以从show.html文件中看出

启动springboot项目,然后在浏览器中访问show.html

访问成功,会展示连接信息

请求中带上userId参数,表示fromUser的值,用户对应的文本输入框输入的是toUser的值

toUser值的获取:

 fromUser值的获取:

是从get请求中获取的参数值

 发送消息的时候,直接使用的是stompClient发送的请求

后端代码:

在刚才的那个窗口 浏览器地址栏输入的userId=1,用户的文本框输入的也是1(那么当前打开的窗口就是1号客户端,fromUser和toUse都是1,相当于1号自己给自己发信息,服务端的信息还是返回给了1号,可以看到信息来自1,消息是4)

可以多开几个页面窗口,模拟多个消息发送窗口

在开一个用户2,给1号发送消息5

然后查看1号用户窗口:

可以看到2号用户给1号用户发送的信息5

再开一个窗口,模拟3号用户 

然后从1号用户窗口给3号发信息233

再观察3号用户窗口:

可以看到1号用户发送的信息233,从而实现了点对点,用户对精确目标用户来发送信息 。

在任何一个用户的窗口,F12查看network都可以

然后看websocket请求

可以看到http请求,http协议升级成了websocket协议(ws),requestURL是以ws开头而不是http开头了,connection的值是upgrade (升级)了

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot一个用于快速构建基于Spring框架的Java应用程序的开源框架。它简化了Spring应用程序的开发过程,并提供了许多内置的功能和插件,使得开发人员可以更加专注于业务逻辑的实现WebSocket是一种在Web浏览器和Web服务器之间建立持久连接的通信协议,能够实现实时双向通信。 要实现聊天软件的功能,可以使用Spring Boot来快速搭建项目结构和配置。首先,需要在pom.xml文件中添加WebSocket的依赖,例如使用SpringSpring WebSocket库: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 然后,需要创建一个WebSocket配置类来配置WebSocket的相关信息,例如定义访问WebSocket的端点、配置消息传输方式等。可以继承Spring提供的AbstractWebSocketMessageBrokerConfigurer类,并重写相关方法: ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/chat").withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/app"); } } ``` 在上述配置类中,使用"/chat"作为WebSocket的端点,并启用了基于内存的消息代理(SimpleBroker),其中"/topic"为消息主题的前缀,"/app"为应用程序请求的前缀。 接下来,可以创建一个WebSocket处理器类来处理WebSocket的连接、关闭和消息等事件。可以实现SpringWebSocketHandler接口,并重写相关方法: ```java @Component public class ChatHandler extends TextWebSocketHandler { private static final List<WebSocketSession> sessions = new ArrayList<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { sessions.remove(session); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { for (WebSocketSession s : sessions) { s.sendMessage(message); } } } ``` 上述处理器类中,使用一个静态List来保存所有连接的WebSocketSession,以便将消息发送给所有已连接的客户端。 最后,在需要使用WebSocket的控制器或服务中,可以使用@Autowired注解将ChatHandler注入,并使用它来发送消息。 总结来说,通过以上的步骤,我们可以使用Spring Boot整合WebSocket实现聊天软件的功能。当有新的WebSocket连接建立时,我们将其保存在一个静态List中,并在收到消息时将消息发送给所有的连接。通过Spring Boot的简化开发流程和WebSocket的实时双向通信特性,实现一个简单聊天软件。 ### 回答2: Spring Boot一个用于开发Java应用程序的框架,它能够帮助开发人员更快速、更简洁地构建应用程序。WebSocket是HTML5新增的一种协议,它能够在客户端与服务器之间建立持久的双向通信连接,实时地传输数据。 要实现聊天软件的功能,首先需要导入Spring BootWebSocket的相关依赖。在pom.xml文件中添加Spring BootWebSocket的依赖项。 在Spring Boot的主类中,使用@EnableWebSocket注解启用WebSocket的支持。编写一个WebSocket处理器类,继承自TextWebSocketHandler,并重写其中的方法。在onTextMessage方法中处理接收到的文本消息,在sendMessage方法中处理发送消息。 配置WebSocket的映射路径和处理器,使用@Configuration注解和实现WebSocketConfigurer接口。重写registerWebSocketHandlers方法,设置WebSocket的映射路径和处理器。 在前端界面中,使用JavaScript代码连接WebSocket服务器,并处理接收消息和发送消息的逻辑。通过WebSocket对象的onmessage方法处理接收到的消息,并将消息显示在聊天界面上。通过WebSocket对象的send方法发送消息给服务器。 通过以上步骤,就可以实现Spring BootWebSocket整合,从而实现聊天软件的功能。开发人员可以根据具体的需求,进一步完善聊天软件的功能,例如用户名的验证、消息的存储和管理等。 总结起来,使用Spring BootWebSocket可以快速、简洁地实现聊天软件。借助Spring Boot的开发效率和WebSocket的实时通信功能,开发人员能够轻松地构建出高效、稳定的聊天软件。 ### 回答3: Spring Boot一个基于 Spring 框架的开源服务端开发框架,提供了快速开发和方便部署的特性。WebSocket 是一种基于TCP协议的双向通信协议,通过浏览器与服务器建立持久连接,实现实时通信。 使用 Spring Boot 整合 WebSocket 实现聊天软件的步骤如下: 1. 创建一个 Spring Boot 项目,引入 WebSocket 依赖包。 2. 在配置类上添加 `@EnableWebSocket` 注解以启用 WebSocket 功能。 3. 创建一个 WebSocket 处理器类,继承自 `TextWebSocketHandler`,覆写其中的方法,如 `handleTextMessage()` 和 `afterConnectionEstablished()`。 4. 在 `handleTextMessage()` 方法中,获取客户端发送的消息,处理后将消息发送给所有连接到服务器的客户端。 5. 在 `afterConnectionEstablished()` 方法中,可以处理客户端连接成功后的逻辑。 6. 创建一个控制器类,处理客户端与服务器的交互,如发送消息、接收消息等。 7. 在控制器类中,使用 `@Autowired` 注入 WebSocket 处理器类的对象,并通过该对象发送消息给客户端。 8. 在前端页面中使用 JavaScript 创建 WebSocket 连接,并实现相应的回调函数,实现与服务器的实时通信。 通过以上步骤,可以实现一个简单聊天软件。用户在页面上发送消息,消息通过 WebSocket 连接发送到服务器,服务器将消息广播给所有客户端,实现实时聊天功能。 总之,借助 Spring Boot 提供的便利性和 WebSocket 协议的实时通信特性,可以快速实现一个聊天软件。不仅可以在浏览器上实现聊天功能,还可以通过移动端等其他客户端实现跨平台的聊天应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值