定义:
-
sockjs.js: 浏览器JavaScript库,它提供了一个类似于网络的对象。SockJS提供了一个连贯的、跨浏览器的Javascript API,它在浏览器和web服务器之间创建了一个低延迟、全双工、跨域通信通道。
-
STOMP:简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。有点像TCP和HTTP之间的关系,在websocket的通信中,有了STOMP协议后,客户端和服务端能够以更友好的方式进行交流。如果没有提供第三方的STOMP代理,比如Rabbitmq等,那么使用的就是spring容器自己提供的STOMP代理。
关系:
能够使用sock.js建立websocket的客户端连接。websocket可以使用STOMP协议作为传输的协议。
样例代码如下:
- 定义WebSocketMessageBrokerConfigurer,一般是继承自AbstractWebSocketMessageBrokerConfigurer:
@Configuration
@EnableWebSocketMessageBroker //在 WebSocket 上启用 STOMP
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
/**
* 启用了STOMP代理中继功能:并将其目的地前缀设置为 "/topic";
* spring就能知道 所有目的地前缀为"/topic" 的消息都会发送到STOMP代理中;
*/
config.enableSimpleBroker("/topic", "/user");
/**
* 设置了应用的前缀为"app":所有目的地以"/app"打头的消息(发送消息url not连接url)
* 都会路由到带有@MessageMapping注解的方法中,而不会发布到代理队列或主题中;
*/
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/webSocket").setAllowedOrigins("*").withSockJS();
}
}
- registerStompEndpoints:注册websocket的端点地址,也就是客户端连接的地址,在上面的配置中,客户端连接的地址是:http://ip:port/项目名/websocket
- setAllowedOrigins:上面的代码中表示是所有的ip地址都能够连接,也可以对固定的地址进行过滤。
- sockjs():提供对sockjs访问的支持。
websocket一般有两种应用场景:
- 客户端订阅到服务端,这个时候服务端会处理一些客户端的信息,比如将客户端的信息注册到服务端的列表之中。
- 服务端收到消息后进行推送到客户端。
上面的配置中:
- /app:代表客户端直接发送给服务端的消息,不需要经过stomp消息代理,将由@MessageMapping的直接处理,并返回消息。
例如:客户端发送的消息:
stompClient.send("/app/webSocket/updateDevice", {}, JSON.stringify(req));
/app/websockt/send将由下面的代码来进行处理:
@MessageMapping("/webSocket/send")
public void updateDevice(SimpMessageHeaderAccessor headerAccessor, String requestContent)
throws Exception {
SubscriptionMsg msg = JSON.parseObject(requestContent, SubscriptionMsg.class);
System.out.println(msg);
}
STOMP消息代理的配置如下:
config.enableSimpleBroker("/topic", "/user");
客户端使用stompClient.subscribe("/topic/theme"),将通过STOMP订阅在这个topic的主题.
- 发送消息到单个/user通道:
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// registry.setPathMatcher(new AntPathMatcher("."));//可以已“.”来分割路径,看看类级别的@messageMapping和方法级别的@messageMapping
registry.enableSimpleBroker("/topic","/user");
registry.setUserDestinationPrefix("/user/");
registry.setApplicationDestinationPrefixes("/app");//走@messageMapping
}
@RequestMapping("/app")
@Controller
public class WebSocketController {
@Resource
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hello")
// @SendTo("/topic/hello")//会把方法的返回值广播到指定主题(“主题”这个词并不合适)
public void toTopic(SocketMessageVo msg , String name) {
System.out.println(msg.getName()+","+msg.getMsg());
this.simpMessagingTemplate.convertAndSend("/topic/hello",msg.getName()+","+msg.getMsg());
// return "消息内容:"+ msg.getName()+"--"+msg.getMsg();
}
@MessageMapping("/message")
// @SendToUser("/message")//把返回值发到指定队列(“队列”实际不是队列,而是跟上面“主题”类似的东西,只是spring在SendTo的基础上加了用户的内容而已)
public void toUser(SocketMessageVo msg ) {
System.out.println(msg.getName()+","+msg.getMsg());
this.simpMessagingTemplate.convertAndSendToUser("123","/message",msg.getName()+msg.getMsg());
}
@RequestMapping("/sendMsg")
public void sendMsg(HttpSession session){
System.out.println("测试发送消息:随机消息" +session.getId());
this.simpMessagingTemplate.convertAndSendToUser("123","/message","后台具体用户消息");
}
}
总结一下:
WebSocketConfig 中配置setApplicationDestinationPrefixes()的消息会被转发到WebSocketController 中 @MessageMapping 相应方法进行处理。@SendTo("/topic/message") 会把方法的返回值序列化为json串,然后发送到指定的主题,不用此注解,使用 simpMessagingTemplate.convertAndSend 效果相同;若为 @SendToUser("/message") 则为发送到指定的用户队列(实际队列名字为/user/用户名/原队列名),不用此注解,使用 simpMessagingTemplate.convertAndSendToUser() 效果相同;
参考文档:https://www.cnblogs.com/nevermorewang/p/7274217.html
来源:oschina
链接:https://my.oschina.net/u/2297579/blog/1924336