知识储备
1.什么是stomp?
我们可以类比TCP与Http协议,我们知道Http协议是基于TCP协议的,Http协议解决了 web 浏览器发起请求以及 web 服务器响应请求的细节,我们在编码时候只要关注我们要发送或接受的信息就行了,不需要关注那些细节
直接使用 WebSocket(SockJS) 就很类似于 使用 TCP 套接字来编写 web 应用;因为没有高层协议,因此就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义;
同 HTTP 在 TCP 套接字上添加 请求-响应 模型层一样,STOMP 在 WebSocket 之上提供了一个基于 帧的线路格式层,用来定义消息语义;
2.STOMP帧格式
基本格式
COMMAND header1:value1 header2:value2 Body^@
// 发送消息 SEND -- 命令类型:发送 destination:/queue/trade -- 头信息:标明了目的地 content-type:application/json -- 头信息:标明数据交换格式 content-length:44 -- 用来表示负载内容的 大小; {"action":"BUY","ticker":"MMM","shares",44}^@ -- 帧内容
项目代码
1.后台代码如下,主要的分析我都写在注释里了
package com.study.spring.websocket.config; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.converter.MessageConverter; import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler; import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; import java.util.List; /** * @author dmz * @date Create in 12:37 2019/3/30 */ @Configuration /** * 通过这个注解,开启使用STOMP来传输基于message broker * 的小心,这时的控制器支持@MessageMapping,就像@RequestMapping */ @EnableWebSocketMessageBroker public class Config implements WebSocketMessageBrokerConfigurer { /** * 注册STOMP端点,映射指定的url * 端点的作用——客户端在订阅或发布消息 到目的地址前,要连接该端点 * * @param registry */ @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/stomp"). /** * 设置允许所有域名访问 */ setAllowedOrigins("*"). /** * 许多浏览器不支持 WebSocket 协议; * SockJS 是 WebSocket 技术的一种模拟。SockJS 会 尽可能对应 WebSocket API, * 但如果 WebSocket 技术 不可用的话,就会选择另外的 通信方式协议; */ withSockJS(); } /** * 配置消息代理 * 如果不重载它的话,将会自动配置一个简单的内存消息代理,用它来处理以"/topic"为前缀的消息 * * @param registry */ @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic", "/queue"); registry.setApplicationDestinationPrefixes("/app"); //基于RabbitMQ 的STOMP消息代理 // registry.enableStompBrokerRelay("/queue", "/topic") // .setRelayHost(host) // .setRelayPort(port) // .setClientLogin(userName) // .setClientPasscode(password); } @Override public void configureWebSocketTransport(WebSocketTransportRegistration registry) { } @Override public void configureClientInboundChannel(ChannelRegistration registration) { } @Override public void configureClientOutboundChannel(ChannelRegistration registration) { } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { } @Override public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) { } @Override public boolean configureMessageConverters(List<MessageConverter> messageConverters) { return false; } }
package com.study.spring.websocket.controller; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.web.bind.annotation.RestController; /** * @author dmz * @date Create in 12:37 2019/3/30 */ @RestController public class Controller { /** * 类似于我们的@requestMapping */ @MessageMapping("/test") /** * 客户端通过app/test访问后, * 服务端会将数据发送到消息代理中 */ @SendTo("/topic/d1") public String test(String name) { return "hello webSocket," + name; } }
package com.study.spring.websocket; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class WebsocketApplication { public static void main(String[] args) { SpringApplication.run(WebsocketApplication.class, args); } }
package com.study.spring.websocket; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class WebsocketApplication { public static void main(String[] args) { SpringApplication.run(WebsocketApplication.class, args); } }
2.前端项目地址:https://github.com/daimingzhi/h5/tree/master/webSocket