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

dao层使用jpa

1.数据库三张表的表结构
message表,消息信息表
springBoot使用webscoket,根据订阅信息发送信息给不同的用户_第1张图片
message_receive接受消息表
springBoot使用webscoket,根据订阅信息发送信息给不同的用户_第2张图片
subscrib订阅消息表
springBoot使用webscoket,根据订阅信息发送信息给不同的用户_第3张图片
我想的是发送消息根据订阅表中的订阅类型发送到某某人那里,缺少一张消息类型表,如果需要可以加上

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 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 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 
         * @return
         */
        public static  T getBean(Class clazz) {
            return getApplicationContext().getBean(clazz);
        }

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

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




    
    
    

    
    发送消息页面


Welcome
标题: 类型: 内容:

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

你可能感兴趣的:(It)