什么是WebSocket?

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

话不多说,马上进入干货时刻。

maven依赖

SpringBoot2.0对WebSocket的支持简直太棒了,直接就有包可以引入

<dependency>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-starter-websocket</artifactId>  </dependency> 

WebSocketConfig

启用WebSocket的支持也是很简单,几句代码搞定

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/** * 开启WebSocket支持 * @author zhengkai */@Configuration  public class WebSocketConfig {      @Bean      public ServerEndpointExporter serverEndpointExporter() {          return new ServerEndpointExporter();      }  } 

WebSocketServer

因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller直接@ServerEndpoint("/websocket")、@Component启用即可,然后在里面实现@OnOpen,@onClose,@onMessage等方法

import java.io.IOException;import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;import org.springframework.stereotype.Component;import cn.hutool.log.Log;import cn.hutool.log.LogFactory;import lombok.extern.slf4j.Slf4j;@ServerEndpoint("/websocket/{sid}")@Componentpublic class WebSocketServer {        static Log log=LogFactory.get(WebSocketServer.class);    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。    private static int onlineCount = 0;    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();    //与某个客户端的连接会话,需要通过它来给客户端发送数据    private Session session;    //接收sid    private String sid="";    /**     * 连接建立成功调用的方法*/    @OnOpen    public void onOpen(Session session,@PathParam("sid") String sid) {        this.session = session;        webSocketSet.add(this);     //加入set中        addOnlineCount();           //在线数加1        log.info("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());        this.sid=sid;        try {             sendMessage("连接成功");        } catch (IOException e) {            log.error("websocket IO异常");        }    }    /**     * 连接关闭调用的方法     */    @OnClose    public void onClose() {        webSocketSet.remove(this);  //从set中删除        subOnlineCount();           //在线数减1        log.info("有一连接关闭!当前在线人数为" + getOnlineCount());    }    /**     * 收到客户端消息后调用的方法     *     * @param message 客户端发送过来的消息*/    @OnMessage    public void onMessage(String message, Session session) {        log.info("收到来自窗口"+sid+"的信息:"+message);        //群发消息        for (WebSocketServer item : webSocketSet) {            try {                item.sendMessage(message);            } catch (IOException e) {                e.printStackTrace();            }        }    }    /**     *      * @param session     * @param error     */    @OnError    public void onError(Session session, Throwable error) {        log.error("发生错误");        error.printStackTrace();    }    /**     * 实现服务器主动推送     */    public void sendMessage(String message) throws IOException {        this.session.getBasicRemote().sendText(message);    }    /**     * 群发自定义消息     * */    public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {        log.info("推送消息到窗口"+sid+",推送内容:"+message);        for (WebSocketServer item : webSocketSet) {            try {                //这里可以设定只推送给这个sid的,为null则全部推送                if(sid==null) {                    item.sendMessage(message);                }else if(item.sid.equals(sid)){                    item.sendMessage(message);                }            } catch (IOException e) {                continue;            }        }    }    public static synchronized int getOnlineCount() {        return onlineCount;    }    public static synchronized void addOnlineCount() {        WebSocketServer.onlineCount++;    }    public static synchronized void subOnlineCount() {        WebSocketServer.onlineCount--;    }}

消息推送

至于推送新信息,可以再自己的Controller写个方法调WebSocketServer.sendInfo();即可

@Controller@RequestMapping("/checkcenter")public class CheckCenterController {    //页面请求    @GetMapping("/socket/{cid}")    public ModelAndView socket(@PathVariable String cid) {        ModelAndView mav=new ModelAndView("/socket");        mav.addObject("cid", cid);        return mav;    }    //推送数据接口    @ResponseBody    @RequestMapping("/socket/push/{cid}")    public ApiReturnObject pushToWeb(@PathVariable String cid,String message) {          try {            WebSocketServer.sendInfo(message,cid);        } catch (IOException e) {            e.printStackTrace();            return ApiReturnUtil.error(cid+"#"+e.getMessage());        }          return ApiReturnUtil.success(cid);    } } 

前端页面

在页面用js代码调用socket,当然,太古老的浏览器是不行的,一般新的浏览器或者谷歌浏览器是没问题的。

<!DOCTYPE HTML><html>   <head>   <meta charset="utf-8">   <title>菜鸟教程(runoob.com)</title>          <script type="text/javascript">         function WebSocketTest()         {            if ("WebSocket" in window)            {               alert("您的浏览器支持 WebSocket!");                              // 打开一个 web socket               var ws = new WebSocket("ws://127.0.0.1:8080/websocket/1212");                               ws.onopen = function()               {                  // Web Socket 已连接上,使用 send() 方法发送数据                  ws.send("发送数据");                  alert("数据发送中...");               };                               ws.onmessage = function (evt)                {                   var received_msg = evt.data;                  alert(received_msg)                  alert("数据已接收...");               };                               ws.onclose = function()               {                   // 关闭 websocket                  alert("连接已关闭...");                };            }                        else            {               // 浏览器不支持 WebSocket               alert("您的浏览器不支持 WebSocket!");            }         }      </script>           </head>   <body>         <div id="sse">         <a href="javascript:WebSocketTest()">运行 WebSocket</a>      </div>         </body></html>

运行

1、启动springboot项目。

2、直接打开页面test.html,点击链接

3、服务端发送消息:

http://localhost:8080/checkcenter/socket/push/1212?message=xxxx