spring boot 集成 websocket

pom.xml

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
MessageHandler
package com.shareworx.websocket;


import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shareworx.model.WebsocketMessageModel;
import com.shareworx.platform.util.DateUtil;
import com.shareworx.pojo.Message;

import com.shareworx.service.WebsocketMessageBusinessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


@Component
public class MessageHandler extends TextWebSocketHandler {

    @Autowired
    private static final ObjectMapper MAPPER = new ObjectMapper();

    private static final Map<Long, WebSocketSession> SESSIONS = new HashMap<>();

    @Autowired
    private WebsocketMessageBusinessService websocketMessageBusinessService;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        Long uid =  (Long) session.getAttributes().get("uid");
        String uname =  (String) session.getAttributes().get("uname");

        // 将当前用户的session放置到map中,后面会使用相应的session通信
        SESSIONS.put(uid, session);
        System.out.println(uid+"的连接已经建立了..............用户名:"+uname);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage
            textMessage) throws Exception {
        Long uid = (Long) session.getAttributes().get("uid");
        JsonNode jsonNode = MAPPER.readTree(textMessage.getPayload());
        Long toId = jsonNode.get("toId").asLong();
        String msg = jsonNode.get("msg").asText();
        String date = DateUtil.formatDateTime(new Date());

        Message message = Message.builder()
                .fromId(uid)
                .toId(toId)
                .msg(msg)
                .sendDate(date)
                .build();
        //保存到数据库
        WebsocketMessageModel websocketMessageModel = new WebsocketMessageModel();
        websocketMessageModel.setDeleteFlag(0);
        websocketMessageModel.setFromId(uid);
        websocketMessageModel.setToId(toId);
        websocketMessageModel.setMsg(msg);
        websocketMessageModel.setStatus(1);
        websocketMessageModel.setSendDate(date);
        websocketMessageBusinessService.save(websocketMessageModel);
        message.setId(websocketMessageModel.getId());
        String msgJson = MAPPER.writeValueAsString(message);

        // 判断to用户是否在线
        WebSocketSession toSession = SESSIONS.get(toId);
        if (toSession != null && toSession.isOpen()) {
            toSession.sendMessage(new TextMessage(msgJson));
        } else {
            //todo  该用户可能下线,可能在其他的节点中,发送消息到MQ系统

         }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        Long uid = (Long) session.getAttributes().get("uid");
        SESSIONS.remove(uid);
        System.out.println(uid+"的连接已经断开");
    }


     public void onMessage(String msg) {
        try {
            JsonNode jsonNode = MAPPER.readTree(msg);
            Long toId = jsonNode.get("toId").asLong();

            // 判断to用户是否在线
            WebSocketSession toSession = SESSIONS.get(toId);
            if (toSession != null && toSession.isOpen()) {
                toSession.sendMessage(new TextMessage(msg));
            } else {
                // 不需要做处理
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 给某个用户发送消息
     *
     * @param userId
     * @param msg
     */
    public void sendMessageToUser(Long userId, Message msg) {
        for (Map.Entry<Long, WebSocketSession> longWebSocketSessionEntry : SESSIONS.entrySet()) {
            Long key = longWebSocketSessionEntry.getKey();
            WebSocketSession session = longWebSocketSessionEntry.getValue();

             Long toId = msg.getToId();
            if ( toId!=null && toId.equals(userId)) {
                try {
                    if (session.isOpen()) {
                        //保存到数据库
                        WebsocketMessageModel websocketMessageModel = new WebsocketMessageModel();
                        websocketMessageModel.setDeleteFlag(0);
                        websocketMessageModel.setFromId(msg.getFromId());
                        websocketMessageModel.setToId(msg.getToId());
                        websocketMessageModel.setMsg(msg.getMsg());
                        websocketMessageModel.setStatus(1);
                        websocketMessageModel.setSendDate(msg.getSendDate());
                        websocketMessageBusinessService.save(websocketMessageModel);
                        msg.setId(websocketMessageModel.getId());
                        session.sendMessage(new TextMessage(MAPPER.writeValueAsString(msg)));
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }

        }

    }

    /**
     * 给所有在线用户发送消息
     *
     * @param message
     */
    public void sendMessageToUsers(TextMessage message) {
        for (Map.Entry<Long, WebSocketSession> longWebSocketSessionEntry : SESSIONS.entrySet()) {
            WebSocketSession session = longWebSocketSessionEntry.getValue();
                 try {
                    if (session.isOpen()) {
                        session.sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
}

说明

通过继承 TextWebSocketHandler 类并覆盖相应方法,可以对 websocket 的事件进行处理,这里可以同原生注解的那几个注解连起来看

  1. afterConnectionEstablished 方法是在 socket 连接成功后被触发,同原生注解里的 @OnOpen 功能
  2. **afterConnectionClosed **方法是在 socket 连接关闭后被触发,同原生注解里的 @OnClose 功能
  3. **handleTextMessage **方法是在客户端发送信息时触发,同原生注解里的 @OnMessage 功能
MessageHandshakeInterceptor
package com.shareworx.websocket;

import com.shareworx.service.IUserService;
import com.shareworx.util.JWTUtils;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import java.util.Map;

@Component
public class MessageHandshakeInterceptor implements HandshakeInterceptor {
    @Autowired
    private IUserService service;

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        try {
            String token = ((ServletServerHttpRequest) request).getServletRequest().getParameter("token");
            if (StringUtils.isBlank(token)) {
                return false;
            }
            Claims claims = JWTUtils.getClaims(token);
            if (claims == null) {
                return false;
            }
            String username = claims.get("username").toString();
            if (StringUtils.isBlank(username)) {
                return false;
            }
            Long id = service.getUserIdByUserName(username);
            if (id == null) {
                return false;
            }
            attributes.put("uid", id);
            attributes.put("uname", username);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {

    }
}

 

说明

通过实现 HandshakeInterceptor 接口来定义握手拦截器,注意这里与上面 Handler 的事件是不同的,这里是建立握手时的事件,分为握手前与握手后,而 Handler 的事件是在握手成功后的基础上建立 socket 的连接。所以在如果把认证放在这个步骤相对来说最节省服务器资源。它主要有两个方法 beforeHandshake 与 **afterHandshake **,顾名思义一个在握手前触发,一个在握手后触发。

 WebSocketConfig

package com.shareworx.websocket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    private MessageHandler messageHandler;
    @Autowired
    private MessageHandshakeInterceptor messageHandshakeInterceptor;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(this.messageHandler, "/ws")
                .setAllowedOrigins("*")
                .addInterceptors(this.messageHandshakeInterceptor);
    }
}

说明

通过实现 WebSocketConfigurer 类并覆盖相应的方法进行 websocket 的配置。我们主要覆盖 registerWebSocketHandlers 这个方法。通过向 WebSocketHandlerRegistry 设置不同参数来进行配置。其中 **addHandler **方法添加我们上面的写的 ws 的 handler 处理类,第二个参数是你暴露出的 ws 路径。**addInterceptors **添加我们写的握手过滤器。**setAllowedOrigins("*") **这个是关闭跨域校验,方便本地调试,线上推荐打开。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot可以很容易地集成WebSocket来实现后台向前端推送信息。首先,在你的项目中添加WebSocket的依赖。然后,在controller层加上相应的注解,如@SpringBootApplication和@EnableWebSocket。最后,启动项目并访问指定的URL来与WebSocket进行交互。 具体步骤如下: 1. 添加WebSocket的依赖到你的项目中,可以在pom.xml文件中添加以下代码: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 在controller层,加上@SpringBootApplication和@EnableWebSocket注解,如下所示: ```java @SpringBootApplication @EnableWebSocket public class MywebsocketApplication { public static void main(String[] args) { SpringApplication.run(MywebsocketApplication.class, args); } } ``` 3. 创建一个WebSocket处理器类,可以通过继承自AbstractWebSocketHandler来实现。你可以在这个类中定义处理WebSocket连接、消息发送和接收的逻辑。 4. 在controller中,创建一个处理WebSocket请求的方法,并使用@MessageMapping注解来指定接收消息的路径。在这个方法中,你可以调用WebSocket处理器类的方法来处理消息,并使用WebSocketSession对象来发送消息给前端。 5. 启动你的项目,并访问指定的URL(例如http://localhost:8081/demo/toWebSocketDemo/{cid}),跳转到页面后,就可以与WebSocket进行交互了。 以上就是Spring Boot集成WebSocket的基本步骤。你可以根据具体的需求来进一步扩展和定制WebSocket的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [SpringBoot 集成WebSocket详解](https://blog.csdn.net/qq_42402854/article/details/130948270)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [springboot 集成webSocket](https://blog.csdn.net/just_learing/article/details/125899260)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值