1.为什么引入Websocket
http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单向的,在很多场景就不适合,比如实时的推送,消息通知或者股票等信息的推送;在没有websocket之前,要解决这种问题,只能依靠ajax轮询或者长轮询,这两种方式极大的消耗资源;而websocket,只需要借助http协议进行握手,然后保持着一个websocket连接,直到客户端主动断开;相对另外的两种方式,websocket只进行一次连接,当有数据的时候再推送给浏览器,减少带宽的浪费和cpu的使用;
http,websocket等应用层协议,都是基于tcp协议来进行传输的,websocket必须依赖于一次http进行握手,握手成功之后,数据直接通过tcp传输,与http无关了;
2.springBoot对websocket支持
项目目录组织如图所示
1> 先建立一个SpringBoot项目,引入webscoket的支持;添加gradle引用
compile('org.springframework.boot:spring-boot-starter-websocket')
2>配置websocket stomp
在config目录添加配置如下
@Configuration
//注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//注册STOMP协议的节点(endpoint),并映射指定的url,这样浏览器直接通过这个地址建立websocket连接
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//这里设置的simple broker是指可以订阅的地址,也就是服务器可以发送的地址
config.enableSimpleBroker("/topic");
//这个配置的是服务器订阅消息的前缀,比如@MessageMapping("/hello-socket"),浏览器端发送消息地址就是app/hello-socket;
config.setApplicationDestinationPrefixes("/app");
}
}
然后是index.html页面,需要引入socket.js和stomp.min.js文件和一些样式文件,这个页面里面,我们需要建立socket的连接,然后通过socket发送消息给服务器端,然后接受从服务器端发送过来的socket通知,页面显示如图所示
app.js是前端的控制逻辑部分,整个项目的代码地址https://github.com/xiaoguangtouqiang/SpringbootDemo.git
简单说明下
例子中输入名字,然后通过websocket发送到后端,后端收到后,返回hello,+name,前端收到服务器的推送消息之后显示出来;看下后端代码
@RestController
public class GreetingController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hello-socket")
@SendTo("/topic/greetings")
public String greeting(@RequestParam String name) throws InterruptedException {
Thread.sleep(1000); // simulated delay
String s = "Hello, " + name + "!";
return s;
}
}
这里@MessageMapping("/hello-socket")类似于springmvc中的@RequestMapping,标识接受客户端socket的请求映射通过当前的方法来处理,@sendTo是将返回结果推送的地址,另外还有一种方式通过SimpMessagingTemplate
@RestController
public class GreetingController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hello-socket")
public void greeting(@RequestParam String name) throws InterruptedException {
Thread.sleep(1000); // simulated delay
String s = "Hello, " + name + "!";
simpMessagingTemplate.convertAndSend("/topic/greetings",s);
}
}