springBoot使用webscoket,根据订阅信息发送信息给不同的用户

dao层使用jpa

1.数据库三张表的表结构
message表,消息信息表
asasaas在这里插入图片描述
message_receive接受消息表
在这里插入图片描述
subscrib订阅消息表
在这里插入图片描述
我想的是发送消息根据订阅表中的订阅类型发送到某某人那里,缺少一张消息类型表,如果需要可以加上

2.WebSocket配置类

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

3.因为MyWebScoket中的session没有存储HttpSession中的信息,需要将HttpSession加入到MyWebScoket中,以获取用户信息,否则获取不到用户信息,

public class GetHttpSessionConfigurator 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);
    }

}

4.myWebScoket测试类,使用map用来存放每个客户端对应的MyWebSocket对象和用户名字关联,以便发送消息时
根据订阅信息查询并通知在线用户查看信息

@ServerEndpoint(value = "/websocket",configurator=GetHttpSessionConfigurator.class)
@Component
public class MyWebSocket {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Map,用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteMap<String,MyWebSocket> webSocketSet = new CopyOnWriteMap<>();
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        User user = getUserInfo();
        webSocketSet.put(user.getUsername(),this);     //加入set中
        addOnlineCount();           //在线数加1
        System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
        /*try {
            sendMessage("连接成功,当前的人数是"+getOnlineCount());
        } catch (IOException e) {
            System.out.println("IO异常");
        }*/
    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        User user = getUserInfo();
        webSocketSet.remove(user.getUsername());  //从set中删除
        subOnlineCount();           //在线数减1
        System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param messageJson 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String messageJson) {
        JSONObject jsonObject = JSON.parseObject(messageJson);
        Message message = jsonObject.toJavaObject(Message.class);
        //获取消息创建人和创建时间
        message.setCreator(getUserInfo().getId());
        message.setCreateTime(LocalDateTime.now());
        System.out.println("来自客户端的消息:" + message.getContent());
        //获取spring容器内的SubscribService
        SubscribService subscribService = SpringContextUtils.getBean(SubscribService.class);
        MessageService messageService = SpringContextUtils.getBean(MessageService.class);
        MessageReceiveService messageReceiveService = SpringContextUtils.getBean(MessageReceiveService.class);
        //保存消息信息到数据库
        Message messageData = messageService.save(message);
        //获取订阅信息,根据订阅信息把信息转发到指定的用户
        List<Subscrib> subscribs = subscribService.findAllByType(message.getType());

        for (Subscrib su:subscribs) {
            //新增消息接收信息
            MessageReceive messageReceive = new MessageReceive();
            messageReceive.setIsRead(0);
            messageReceive.setMessageId(messageData.getId());
            messageReceive.setCreateTime(LocalDateTime.now());
            messageReceive.setReceiver(su.getSubscriber());
            //保存消息接收信息到数据库
            messageReceiveService.save(messageReceive);
            //群发消息
            for (String sub : webSocketSet.keySet()) {
                if(su.getSubscriber().equals(sub)){
                    MyWebSocket item = webSocketSet.get(sub);
                    try {
                        item.sendMessage(message.getContent());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

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

     public void sendMessage(String message) throws IOException {
         this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
     }
    private User getUserInfo(){
        return (User)((HttpSession)session.getUserProperties().get(HttpSession.class.getName())).getAttribute("user");
    }
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        MyWebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        MyWebSocket.onlineCount--;
    }
}

获取ioc容器中bean的工具类

@Component
    public class SpringContextUtils implements ApplicationContextAware {

        /**
         * 上下文对象实例
         */
        private static ApplicationContext applicationContext;

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }

        /**
         * 获取applicationContext
         *
         * @return
         */
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }

        /**
         * 通过name获取 Bean.
         *
         * @param name
         * @return
         */
        public static Object getBean(String name) {
            return getApplicationContext().getBean(name);
        }

        /**
         * 通过class获取Bean.
         *
         * @param clazz
         * @param <T>
         * @return
         */
        public static <T> T getBean(Class<T> clazz) {
            return getApplicationContext().getBean(clazz);
        }

        /**
         * 通过name,以及Clazz返回指定的Bean
         *
         * @param name
         * @param clazz
         * @param <T>
         * @return
         */
        public static <T> T getBean(String name, Class<T> clazz) {
            return getApplicationContext().getBean(name, clazz);
        }
    }

前端页面,测试是类型输入1,页面下方js最好封装到公共js里面,主界面引入一下。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="Bookmark" href="/favicon.ico">
    <link rel="Shortcut Icon" href="/favicon.ico"/>

    <script type="text/javascript" th:src="@{/lib/jquery/1.9.1/jquery.min.js}"></script>
    <title>发送消息页面</title>
</head>
<body style="text-align: center">
Welcome<br/>
标题:<input id="title">
类型:<input id="type">
内容:<textarea id="content" rows="1" cols="10"></textarea>

<button onclick="send()">提交</button>    <!--<button onclick="closeWebSocket()">Close</button>-->

<div id="message"></div>
</body>

<script type="text/javascript">
    var websocket = null;

    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        websocket = new WebSocket("ws://localhost:8080/xiaoxi/websocket");
    }
    else{
        alert('Not support websocket')
    }

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

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

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

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

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

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML){
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

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

    //发送消息
    function send(){
        var message={};
        message['title']=$("#title").val();
        message['type']=$("#type").val();
        message['content']=$("#content").val();
        websocket.send(JSON.stringify(message));
    }
</script>
</html>

必须登录,然后将信息存储到session中
在页面上输入信息发送,在另外一个浏览器中使用订阅人登录就能自动弹出信息框了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中使用WebSocket发送信息可以通过以下步骤实现: 1. 添加依赖:在`pom.xml`文件中添加WebSocket相关的依赖,例如: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建WebSocket配置类:创建一个配置类,用于配置WebSocket相关的Bean和处理器。可以使用`@EnableWebSocket`注解启用WebSocket支持,并实现`WebSocketConfigurer`接口来配置WebSocket的处理器和拦截器。 3. 创建WebSocket处理器:创建一个类,实现`WebSocketHandler`接口,重写相应的方法来处理WebSocket连接、消息发送和接收等操作。 4. 配置WebSocket处理器:在配置类中注册WebSocket处理器,可以使用`registerHandler()`方法将处理器注册到指定的路径上。 5. 创建前端页面:在前端页面中使用JavaScript代码来建立WebSocket连接,并发送和接收消息。 下面是一个简单的示例代码: ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(), "/websocket").setAllowedOrigins("*"); } @Bean public WebSocketHandler myHandler() { return new MyHandler(); } } @Component public class MyHandler implements WebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { // 连接建立后的处理逻辑 } @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { // 处理接收到的消息 } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { // 处理传输错误 } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { // 连接关闭后的处理逻辑 } @Override public boolean supportsPartialMessages() { return false; } } ``` 在前端页面中,可以使用JavaScript代码来建立WebSocket连接,并发送和接收消息。例如: ```javascript var socket = new WebSocket("ws://localhost:8080/websocket"); socket.onopen = function() { // 连接建立后的处理逻辑 }; socket.onmessage = function(event) { var message = event.data; // 处理接收到的消息 }; socket.onclose = function(event) { // 连接关闭后的处理逻辑 }; function sendMessage() { var message = "Hello, WebSocket!"; socket.send(message); } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值