前言 WebSocket是一种浏览器与服务器之间进行全双工的通信协议,属于应用层协议,基于Http协议。它有以下几个优点:
WebSocket可以在浏览器里使用;
支持双向通信,实时性更强;
使用很简单。
后面将用一个小例子来学习WebSocket。
创建SpringBoot工程 选择File->New Project->Spring Initializr,两次next,选择Web->Srping Web,点击finish创建,目录结构:
引入依赖 1 2 3 4 5 6 7 8 9 <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 2.0.3</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-websocket</artifactId > </dependency >
创建消息实体 对于Websocket来说,消息实体承载着服务端与客户端之间通信,需要接受者、发送者以及消息内容三个基本元素。故可构造以下实体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 package com.example.im.entity;import java.io.Serializable;public class Message implements Serializable { private String from; private String to; private int type; private String info; public Message () { } public Message (String from, String to, int type, String info) { this .from = from; this .to = to; this .type = type; this .info = info; } @Override public String toString () { return "Message{" + "from='" + from + '\'' + ", to='" + to + '\'' + ", type=" + type + ", info='" + info + '\'' + '}' ; } public String getFrom () { return from; } public void setFrom (String from) { this .from = from; } public String getTo () { return to; } public void setTo (String to) { this .to = to; } public int getType () { return type; } public void setType (int type) { this .type = type; } public String getInfo () { return info; } public void setInfo (String info) { this .info = info; } }
配置MvcConfig,注入ServerEndpointExporter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package com.example.im.testCase.config;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.CorsRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration public class WebMvcConfig implements WebMvcConfigurer { private final Logger logger = LoggerFactory.getLogger(WebMvcConfig.class); @Override public void addCorsMappings (CorsRegistry registry) { registry.addMapping("/**" ) .allowedOrigins("*" ) .allowedMethods("GET" , "POST" ,"OPTIONS" ) .allowedHeaders("*" ) .exposedHeaders("Access-Control-Allow-Headers" , "Access-Control-Allow-Methods" , "Access-Control-Allow-Origin" , "Access-Control-Max-Age" , "X-Frame-Options" ) .allowCredentials(false ) .maxAge(3600 ); } @Bean public ServerEndpointExporter serverEndpointExporter () { return new ServerEndpointExporter (); } }
创建访问路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.example.im.testCase.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;@Controller public class UserModel { @GetMapping("/websocket") public String websocket () { return "websocket" ; } }
增加Websocket控制器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package com.example.im.testCase.websocket;import com.alibaba.fastjson.JSON;import com.example.im.entity.Message;import org.springframework.stereotype.Component;import javax.websocket.*;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.concurrent.ConcurrentHashMap;@ServerEndpoint("/websocket") @Component public class UserWebsocket { private static ConcurrentHashMap<String, Session> map = new ConcurrentHashMap <>(); @OnMessage public void onMessage (String message, Session session) throws IOException { Message m = null ; try { m = JSON.parseObject(message, Message.class); }catch (Exception e){ System.out.println("Received:" + message); return ; } map.put(m.getFrom(), session); Session s = map.get(m.getTo()); if (s != null ) { s.getBasicRemote().sendText(message); }else { m.setInfo("查无此人" ); session.getBasicRemote().sendText(JSON.toJSONString(m)); } } @OnOpen public void onOpen () { System.out.println("Client connected" ); } @OnClose public void onClose () { System.out.println("Connection closed" ); } }
创建用户界面 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > 发送者:<input type ="text" id ="from" /> <br > 接收者:<input type ="text" id ="to" /> <br > 内容:<input type ="text" id ="message" /> <br > <input onclick ="sendMessage()" type ="submit" value ="发送" > <br > <span style ="white-space: pre-line;" id ="receiver" > </span > </body > <script > var ws = new WebSocket ("ws://localhost:8080/websocket" ); ws.onopen = function (evt ) { console .log ("Connection open ..." ); ws.send ("Hello WebSockets!" ); }; ws.onmessage = function (evt ) { var from = document .getElementById ("from" ).value ; var receiver = document .getElementById ("receiver" ); var receiverMsg = receiver.textContent ; var data = JSON .parse (evt.data ); console .log (data); if (from === data["from" ]) { receiverMsg += data["to" ] + ":" + data["info" ] + "\n" ; } else { receiverMsg += data["from" ] + ":" + data["info" ] + "\n" ; } receiver.textContent = receiverMsg; }; ws.onclose = function (evt ) { console .log ("Connection closed." ); }; function sendMessage ( ) { var from = document .getElementById ("from" ).value ; var to = document .getElementById ("to" ).value ; var info = document .getElementById ("message" ).value ; var receiver = document .getElementById ("receiver" ); var message = {}; message["from" ] = from ; message["to" ] = to; message["info" ] = info; ws.send (JSON .stringify (message)); var receiverMsg = receiver.textContent ; receiverMsg += from + ":" + info + "\n" ; receiver.textContent = receiverMsg; } </script > </html >
测试 启动,使用两个浏览器分别访问http://localhost:8080/websocket
总结 Websocket是一个在不可靠的通信中以较少的代价建立可靠的连接,给我们进行一些实时性比较强的开发提供了很好的解决方案。