SpringBoot——集成WebSocket

1、WebSocket应用

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信一允许服务器主动发送信息给客户端,这样就可以实现从客户端发送消息到服务器,而服务器又可以转发消息到客户端,这样就能够实现客户端之间的交互。

对于WebSocket的开发,Spring也提供了良好的支持。目前很多浏览器已经实现了WebSocket协议,但是依I旧存在着很多浏览器没有实现该协议,为了兼容那些没有实现该协议的浏览器,往往还需要通过STOMP协议来完成这些兼容。

2、开发简易的WebSocket服务

本案例开发一个简易的在线网络聊天室,实现访问用户的群聊功能。

2.1、项目依赖

<?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.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

        <!--引入Spring Boot内嵌的Tomcat对JSP的解析包,不加解析不了jsp页面-->
        <!--如果只是使用JSP页面,可以只添加该依赖-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>

        <!--如果使用JSTL必须添加该依赖-->
        <!--jstl标签依赖的jar包start-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <!--如果要使用servlet必须添加该以下两个依赖-->
        <!-- servlet依赖的jar包-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <!--源文件位置-->
                <directory>src/main/webapp</directory>
                <!--指定编译到META-INF/resources,该目录不能随便写-->
                <targetPath>META-INF/resources</targetPath>
                <!--指定要把哪些文件编译进去,**表示webapp目录及子目录,*.*表示所有文件-->
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.2、springboot配置

#指定内嵌Tomcat端口号
server:
  port: 8080
  servlet:
    context-path: /

#配置SpringMVC视图解析器
#其中:/ 表示目录为src/main/webapp
spring:
  mvc:
    view:
      prefix: /
      suffix: .jsp

2.3、自定义WebSocket服务端点配置

对于WebSocket的使用,可以先通过Spring创建Java配置文件。在这个文件中,先新建ServerEndpointExporter对象,通过它可以定义WebSocket服务器的端点,这样客户端就能请求服务器的端点:

@Configuration
public class WebSocketConfig {
    //创建服务器端点
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

有了这个Bean,就可以使用@ServerEndpoint定义一个端点服务类。在这个站点的服务类中,还可以定义WebSocket的打开、关闭、错误和发送消息的方法:

@ServerEndpoint("/ws")
@Service
public class WebSocketServiceImpl {
    //静态变量,用来记录当前在线连接数。应该设计为线程安全的
    private static int onlineCount = 0;
    // concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServiceImpl对象
    private static CopyOnWriteArraySet<WebSocketServiceImpl> webSocketSet = new CopyOnWriteArraySet<>();
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;

    /**
     * 连接建立成功调用的方法
     * @param session
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);//加入set中
        addOnlineCount();//在线数加1
        System.out.println("有新连接加入!当前在线人数为:" + getOnlineCount());
        //获取当前用户名称
        Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
        String name = requestParameterMap.get("name").get(0);
        try {
            sendMessage("欢迎" + name + "加入聊天室!");
        } catch (IOException e) {
            System.out.println("IO异常");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this); //从set中删除
        subOnlineCount();//在线数减1
        System.out.println("有一连接关闭!当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);
        //群发消息
        for (WebSocketServiceImpl socket : webSocketSet) {
            try {
                //获取当前用户名称
                Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
                String name = requestParameterMap.get("name").get(0);
                //发送消息
                if (socket.session == session) {
                    socket.sendMessage(message + "<--" + name);
                } else {
                    socket.sendMessage(name + "-->" + message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

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

    /**
     * 发送消息
     * @param message
     * @throws IOException
     */
    private void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 返回在线人数
     * @return
     */
    private static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 连接人数增加
     */
    private static synchronized void addOnlineCount() {
        WebSocketServiceImpl.onlineCount++;
    }

    /**
     * 连接人数减少
     */
    private static synchronized void subOnlineCount() {
        WebSocketServiceImpl.onlineCount--;
    }
}
  • @ServerEndpoint((“/ws”):表示让Spring创建WebSocket的服务端点,其中请求地址是“ws”。
  • @OnOpen:标注客户端打开WebSocket服务端点调用方法。
  • @OnClose:标注客户端关闭WebSocket服务端点调用方法。
  • @OnMessage:标注客户端发送消息,WebSocket服务端点调用方法。
  • @OnError:标注客户端请求WebSocket服务端点发生异常调用方法。

因为每一个客户端打开时,都会为其创建一个WebSocketServiceImpl对象,所以这里的打开方法中都会去计数并且将这个对象保存到CopyOnWriteArraySet中,这样就可以知道拥有多少连接。对于关闭方法则是清除这个对象,并且计数减一。对于消息发送方法,则是通过轮询对所有的客户端连接都给予发送消息,所以所有的连接都可以收到这个消息。但是有时候可能只是需要发送给特定的用户,则需要得到用户的信息,然后再发送给特定的用户。

2.4、JSP页面

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>网络聊天室</title>
</head>
<body>
<h2>欢迎使用在线网络聊天室</h2>
<br/>
<form method="get" action="chat">
    <input name="name" type="text" value="" placeholder="请输入您的昵称">
    <button type="submit">提交</button>
</form>
</div>
</body>
</html>

websocket.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>网络聊天室</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-3.2.1.min.js"></script>
</head>
<script type="text/javascript">
    var websocket = null;

    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        //创建WebSocket对象,连接服务器端点
        websocket = new WebSocket("ws://localhost:8080/ws?name=${name}");
    } else {
        alert('Not support websocket')
    }

    //连接发生错误的回调方法
    websocket.onerror = function () {
        appendMessage("error");
    };

    //连接成功建立的回调方法
    websocket.onopen = function (event) {
        appendMessage("open");
    };

    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        appendMessage(event.data);
    };

    //连接关闭的回调方法
    websocket.onclose = function () {
        appendMessage("close");
    };

    //监听窗口关闭事件,当窗口关闭时,主动关闭websocket连接
    //防止连接还没断开就关闭窗口,server端会抛出异常
    window.onbeforeunload = function () {
        websocket.close();
    };

    //将消息显示在网页上
    function appendMessage(message) {
        var context = $('#context').html() + '<br/>' + message;
        $('#context').html(context);
    };

    //关闭连接
    function closeWebSocket() {
        websocket.close();
    };

    //发送消息
    function sendMessage() {
        var message = $('#message').val();
        websocket.send(message);
    };
</script>
<body>
    <h2>在线网络聊天室</h2>
    <br/>
    <input id="message" type="text">
    <button onclick="sendMessage()">发送消息</button>
    <button onclick="closeWebSocket()">关闭WebSocket连接</button>
    <div id="context">
    </div>
</body>
</html>

2.5、Controller

@Controller
@RequestMapping("/websocket")
public class WebSocketController {

    //跳转首页
    @GetMapping("/index")
    public String index() {
        return "index";
    }

    //接收name参数,跳转websocket页面
    @GetMapping("/chat")
    public String websocket(String name, HttpServletRequest request) {
        System.out.println(name);
        request.setAttribute("name", name);
        return "websocket";
    }
}

2.6、测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot集成WebSocket可以通过以下步骤实现: 1. 首先,在pom.xml文件中添加WebSocket的依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建一个WebSocketConfig类,用于配置WebSocket相关的参数和处理器: ``` @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new WebSocketHandler(), "/websocket"); // 指定WebSocket处理器和连接的路径 } } ``` 3. 创建一个WebSocketHandler类,实现WebSocketHandler接口: ``` @Component public class WebSocketHandler extends TextWebSocketHandler { private static final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { // 处理收到的文本消息 String payload = message.getPayload(); // 发送消息给所有连接的客户端 for (WebSocketSession webSocketSession : sessions) { webSocketSession.sendMessage(new TextMessage(payload)); } } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { sessions.remove(session); } } ``` 4. 在Vue中使用WebSocket连接服务器: ``` new Vue({ created() { this.socket = new WebSocket('ws://localhost:8080/websocket'); this.socket.onmessage = this.handleMessage; }, methods: { handleMessage(event) { // 收到消息后的处理逻辑 } } }) ``` 以上是Spring Boot和Vue集成WebSocket的基本步骤。通过配置WebSocketConfig类和创建WebSocketHandler类实现服务器端的消息处理和推送,然后在Vue中创建WebSocket对象进行连接并处理收到的消息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值