springboot整合websocket实现点对点和全体发消息

背景 最近项目里有个类似备忘录的功能,每个用户管理多个客户,每个客户都有一个备忘录,一旦员工管理的客户多了,备忘录自然也多了,往往这时员工就搞不清啥时候该干啥了,所以要做一个类似小秘书的功能,按照备忘录里设置执行时间前30分钟通知一下员工,当然其他的消息都可以通知。
功能介绍 员工会针对某个客户添加一个执行计划,哪天几点上门/电话/短信拜访客户或其他事项。如果说我们设置在执行时间前30分钟后台主动推送消息到前台通知员工的话这时需要用到的技术是:延时队列+websocket
延时队列 我这边用的是rabbitmq,添加执行计划成功后,把执行时间减半小时压入延时队列里,等待到期消费,到期后调用websocket向前台发消息通知员工。
当然也可以写定时任务1min轮训一次,但这样太low。
**websocket:**springboot整合websocket
由于本篇主要讲解springboot整合websocket,所以延时队列怎么实现暂时不做赘述:

  1. maven先加入依赖:
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
  1. 写个websocket配置类:
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket配置
 * @author zhanghang
 * @date 2019/1/3 17:53
 */
@Component
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
  1. 由于我们的websocket对象中肯定需要用到用户信息,但是WsSession终是没有的,只能从HttpSession中拿,所以写一个获取HttpSession的配置类
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

/**
 * 协助server获取http session
 * @author zhanghang
 * @date 2019/1/4 13:58
 */
public class HttpSessionWSHelper extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession=(HttpSession) request.getHttpSession();
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}
  1. 然后再写websocket的具体实现类
import com.ccq.calling.config.shiro.ShiroUser;
import com.ccq.calling.utils.MyApp;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * websocket实现
 * @author zhanghang
 * @date 2019/1/3 17:54
 */
@Component
@ServerEndpoint(value = "/websocket",configurator = HttpSessionWSHelper.class)
@Slf4j
public class WebSocket {
    private Integer userId;
    private Session session;
    private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();

    @OnOpen
    public void onOpen(Session session) {
        HttpSession httpSession = (HttpSession) session.getUserProperties().get(HttpSession.class.getName());
        ShiroUser shiroUser = (ShiroUser)((SimplePrincipalCollection) httpSession.getAttribute(MyApp.HTTPSESSION_USER_ATTR)).getPrimaryPrincipal();
        this.userId = shiroUser.getId();
        this.session = session;
        webSockets.add(this);
        log.info("【websocket消息】有新的连接, 总数:{}", webSockets.size());
    }


    @OnClose
    public void onClose() {
        webSockets.remove(this);
        log.info("【websocket消息】连接断开, 总数:{}", webSockets.size());
    }

    @OnMessage
    public void onMessage(String message) {
        log.info("【websocket消息】收到客户端发来的消息:{}", message);
    }

    /**
     * 点对点广播消息
     * @param userId 要广播的用户id
     * @param msg 消息
     */
    public void sendP2PMessage(Integer userId,String msg){
        for (WebSocket webSocket: webSockets) {
            log.info("【websocket消息】点对点广播消息, userId={},message={}", userId,msg);
            try {
                if (webSocket.userId.intValue() == userId.intValue()) {
                    webSocket.session.getBasicRemote().sendText(msg);
                }
            } catch (Exception e) {
                log.error("=================websocket点对点广播消息出错===================");
                log.error(e.getMessage(),e);
            }
        }
    }

    /**
     * 全体广播消息
     * @param msg 消息
     */
    public void sendMessage(String msg){
        for (WebSocket webSocket: webSockets) {
            log.info("【websocket消息】全体广播消息,message={}",msg);
            try {
                webSocket.session.getBasicRemote().sendText(msg);
            } catch (Exception e) {
                log.error("=================websocket全体广播消息出错===================");
                log.error(e.getMessage(),e);
            }
        }
    }
}
  1. 前端代码:
	<script>
        var websocket = null;
        if('WebSocket' in window){
            websocket = new WebSocket('ws://localhost:8888/websocket');
        }else{
            alert("该浏览器不支持WebSocket");
        }

        websocket.onopen = function (event) {
            console.log("建立连接");
        }

        websocket.onclose = function (event) {
            console.log("断开连接");
        }

        websocket.onmessage = function (event) {
            console.log("收到消息:" + event.data);
        }

        websocket.onerror = function (event) {
            alert("websocket通信发生错误");
        }

        window.onbeforeunload = function (event) {
            websocket.close();
        }
    </script>
  1. 然后我们再写个测试类去测试一下:
import com.ccq.calling.config.websocket.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zhanghang
 * @date 2019/1/3 17:57
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private WebSocket webSocket;

    @GetMapping("/sendP2PMessage/{userId}/{msg}")
    public void sendP2PMessage(@PathVariable("userId") Integer userId,@PathVariable("msg") String msg){
        webSocket.sendP2PMessage(userId,msg);
    }

    @GetMapping("/sendMessage/{msg}")
    public void sendMessage(@PathVariable("msg") String msg){
        webSocket.sendMessage(msg);
    }
}
### 回答1: Spring Boot是一个用于快速构建基于Spring框架的Java应用程序的开源框架。它简化了Spring应用程序的开发过程,并提供了许多内置的功能和插件,使得开发人员可以更加专注于业务逻辑的实现WebSocket是一种在Web浏览器和Web服务器之间建立持久连接的通信协议,能够实现实时双向通信。 要实现聊天软件的功能,可以使用Spring Boot来快速搭建项目结构和配置。首先,需要在pom.xml文件中添加WebSocket的依赖,例如使用Spring的Spring 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的连接、关闭和消息等事件。可以实现Spring的WebSocketHandler接口,并重写相关方法: ```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 Boot和WebSocket的相关依赖。在pom.xml文件中添加Spring Boot和WebSocket的依赖项。 在Spring Boot的主类中,使用@EnableWebSocket注解启用WebSocket的支持。编写一个WebSocket处理器类,继承自TextWebSocketHandler,并重写其中的方法。在onTextMessage方法中处理接收到的文本消息,在sendMessage方法中处理发送消息。 配置WebSocket的映射路径和处理器,使用@Configuration注解和实现WebSocketConfigurer接口。重写registerWebSocketHandlers方法,设置WebSocket的映射路径和处理器。 在前端界面中,使用JavaScript代码连接WebSocket服务器,并处理接收消息和发送消息的逻辑。通过WebSocket对象的onmessage方法处理接收到的消息,并将消息显示在聊天界面上。通过WebSocket对象的send方法发送消息给服务器。 通过以上步骤,就可以实现Spring Boot和WebSocket整合,从而实现聊天软件的功能。开发人员可以根据具体的需求,进一步完善聊天软件的功能,例如用户名的验证、消息的存储和管理等。 总结起来,使用Spring Boot和WebSocket可以快速、简洁地实现聊天软件。借助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 协议的实时通信特性,可以快速实现一个聊天软件。不仅可以在浏览器上实现聊天功能,还可以通过移动端等其他客户端实现跨平台的聊天应用。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值