sockjs.js: 浏览器JavaScript库,它提供了一个相似于网络的对象。SockJS提供了一个连贯的、跨浏览器的Javascript API,它在浏览器和web服务器之间建立了一个低延迟、全双工、跨域通讯通道。html
STOMP:简单(流)文本定向消息协议,它提供了一个可互操做的链接格式,容许STOMP客户端与任意STOMP消息代理(Broker)进行交互。有点像TCP和HTTP之间的关系,在websocket的通讯中,有了STOMP协议后,客户端和服务端可以以更友好的方式进行交流。若是没有提供第三方的STOMP代理,好比Rabbitmq等,那么使用的就是spring容器本身提供的STOMP代理。web
可以使用sock.js创建websocket的客户端链接。websocket可使用STOMP协议做为传输的协议。spring
样例代码以下:json
@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(); } }
上面的配置中:跨域
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的主题.websocket
@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() 效果相同;网络
参考文档:http://www.javashuo.com/article/p-fiuuyxpu-ed.htmlsession