消息不再转发到服务器配置中,Spring Boot中使用WebSocket总结(二):向指定用户发送WebSocket消息并处理对方不在线的情况...

在上一篇文章( www.zifangsky.cn/1355.html )中我介绍了在Spring项目中使用WebSocket的几种实现方式。但是,上篇文章中只介绍了服务端采用广播模式给所有客户端发送消息,然而我们有时需要服务端给指定用户的客户端发送消息(比如:发送Web通知、实时打印用户任务的日志、两个用户点对点聊天等)。

关于服务端如何给指定用户的客户端发送消息,一般可以通过以下三种方案来实现:

方案一 :WebSocket使用“Java提供的@ServerEndpoint注解”实现或者使用“Spring低层级API”实现,在建立连接时从 HttpSession 中获取用户登录后的用户名,然后把“ 用户名+该WebSocket连接 ”存储到 ConcurrentHashMap 。给指定用户发送消息,只需要 根据接收者的用户名获取对方已经建立的WebSocket连接,接着给他发送消息即可 。

方案二 :在页面的监听路径前面动态添加当前登录的“ 用户ID/用户名 ”,这样给指定用户发送消息,只需要发送广播消息到监听了前面那个路径的客户端即可。

方案三 :这种方案类似于方案一。使用Spring的高级API实现WebSocket,然后自定义 HandshakeHandler 类并重写 determineUser 方法,其目的是为了在建立连接时使用用户登录后的用户名作为此次WebSocket的凭证,最后我们就可以使用 messagingTemplate.convertAndSendToUser 方法给指定用户发送消息了。

使用SimpMessagingTemplate发送消息

使用 org.springframework.messaging.simp.SimpMessagingTemplate 类可以在服务端的任意地方给客户端发送消息。此外,在我们配置Spring支持STOMP后 SimpMessagingTemplate 类就会被自动装配到Spring的上下文中,因此我们只需要在想要使用的地方使用 @Autowired 注解注入SimpMessagingTemplate即可使用。

需要说明的是, SimpMessagingTemplate 类有两个重要的方法,它们分别是:

public void convertAndSend(D destination, Object payload) :给监听了路径 destination 的所有客户端发送消息 payload

public void convertAndSendToUser(String user, String destination, Object payload) :给监听了路径 destination 的用户 user 发送消息 payload

一个简单示例:

package cn.zifangsky.stompwebsocket.controller;

import cn.zifangsky.stompwebsocket.model.websocket.Greeting;

import cn.zifangsky.stompwebsocket.model.websocket.HelloMessage;

import cn.zifangsky.stompwebsocket.service.RedisService;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.messaging.simp.SimpMessagingTemplate;

import org.springframework.messaging.simp.user.SimpUserRegistry;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

/**

* 测试{@link org.springframework.messaging.simp.SimpMessagingTemplate}类的基本用法

* @author zifangsky

* @date 2018/10/10

* @since 1.0.0

*/

@Controller

@RequestMapping(("/wsTemplate"))

public class MessageTemplateController {

private final Logger logger = LoggerFactory.getLogger(getClass());

@Autowired

private SimpMessagingTemplate messagingTemplate;

@Autowired

private SimpUserRegistry userRegistry;

@Resource(name = "redisServiceImpl")

private RedisService redisService;

/**

* 简单测试SimpMessagingTemplate的用法

*/

@PostMapping("/greeting")

@ResponseBody

public String greeting(@RequestBody Greeting greeting) {

this.messagingTemplate.convertAndSend("/topic/greeting", new HelloMessage("Hello," + greeting.getName() + "!"));

return "ok";

}

}

复制代码

很显然,这里发送的地址是上篇文章中最后那个示例监听的地址,在客户端页面建立连接后,我们使用 Postman 请求一下上面这个方法,效果如下:

ac73342a19aaf8f62277e76bc70e6e0f.png

然后我们可以发现页面中也收到消息了:

2c1f04a79f1a375f72ee1d3f78a5115f.png

向指定用户发送WebSocket消息并处理对方不在线的情况

给指定用户发送消息:

如果接收者在线,则直接发送消息;

否则将消息存储到redis,等用户上线后主动拉取未读消息。

(1)自定义HandshakeInterceptor,用于禁止未登录用户连接WebSocket:

package cn.zifangsky.stompwebsocket.interceptor.websocket;

import cn.zifangsky.stompwebsocket.common.Constants;

import cn.zifangsky.stompwebsocket.common.SpringContextUtils;

import cn.zifangsky.stompwebsocket.model.User;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.stereotype.Component;

import org.springframework.web.socket.WebSocketHandler;

import org.springframework.web.socket.server.HandshakeInterceptor;

import javax.servlet.http.HttpSession;

import java.text.MessageFormat;

import java.util.Map;

/**

* 自定义{@link org.springframework.web.socket.server.HandshakeInterceptor},实现“需要登录才允许连接WebSocket”

*

* @author zifangsky

* @date 2018/10/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值