Springboot WebSocket 入门及源码

一、前言

SpringBoot + WebSocket

最早其实是在准备秋招的时候,一直想写一个小的demo学习一下,到了暑假,在写“首义生活”的时候,有一处用到了轮询,那个时候就想,有没有更好的解决方式。

二、WebSocket是什么

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信,允许服务器主动发送信息给客户端。WebSocket 协议中, 浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

三、WebSocket有什么用

  • 实现聊天室。群发、点对点。
  • 解决轮询带来的效率低下等问题。

第二点是我主要学习WebSocket的原因。在“首义生活”的项目中,有一个这样的场景:

用户访问一个页面,若未登陆,则弹出一个登陆的弹窗,有个二维码,通过微信扫一扫即可无感知无跳转登陆。(微信公众平台接口测试帐号:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login)

用户走完登陆流程之后,后台可以获取到一个唯一标识符,但是前端此时是不知道的,弹窗依旧还在,刷新依旧显示未登陆。

当时,直接采用了轮询的方式,用户走完登陆流程,获取到唯一的标识符之后,会写入到Redis,与此同时,前端只要弹窗显示了,就会一直调用查询接口,查询Redis中有没有当前用户的唯一标识,如果有,关闭弹窗,修改用户状态。

虽然能够解决问题,但还是非常不妥的。

四、贴部分代码

有两种实现方式:

  • 通过简单的配置实现
  • 基于STOMP协议实现

本文是基于第一种方式实现的,比较简单,就不过多解释了。


// com.qingchen.websocket.config.WebSocketConfig 
/** 
  * @author Created by qingchen on 2019/11/19 14:52 
  * new一个ServerEndpointExporter对象,交给Spring容器,表示开启WebSocket功能 
*/
@Configuration @EnableWebSocket public class WebSocketConfig {
	@Bean public ServerEndpointExporter serverEndpoint(){
		return new ServerEndpointExporter();
	}
}

 


// com.qingchen.websocket.config.WebSocket
/**
 * @author Created by qingchen on 2019/11/19 14:55
 * @ServerEndpoint  作用在类上  把当前类标识成一个WebSocket的服务端  这里value的配置  与  前端对应
 */
@Component
@ServerEndpoint("/websocket/{id}")
public class WebSocket {

    // 存放每个客户端对应的WebSocket对象,线程安全
    private static ConcurrentHashMap<String, WebSocket> webSocketSet = new ConcurrentHashMap<>();

    // 与某个客户端的连接,通过它来给客户端发送数据
    private Session session;

    // 用户的唯一id
    private String id = "";

    /**
     * 连接成功
     *
     * @param session
     * @param id
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("id") String id) {
        this.session = session;
        this.id = id;
        webSocketSet.put(id, this);    //加入到ConcurrentHashMap中
        System.out.println(id + "连接成功,当前在线人数为:" + webSocketSet.size());
    }

    /**
     * 退出连接
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this.id);
        System.out.println(id + "退出成功,当前在线人数为:" + webSocketSet.size());
    }

    /**
     * 群发
     *
     * @param message
     */
    public void GroupSending(String message) {
        for (String id : webSocketSet.keySet()) {
            try {
                webSocketSet.get(id).session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 指定发送
     *
     * @param id
     * @param message
     */
    public void AppointSending(String id, String message) {
        try {
            webSocketSet.get(id).session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

@Controller
@RequestMapping("/websocket")
public class SendMsgController {

    @Autowired
    private WebSocket webSocket;

    //页面请求
    @GetMapping("/link")
    public ModelAndView socket(@RequestParam("id") String id) {
        System.out.println("into!");
        ModelAndView mav=new ModelAndView("webSocket");
        mav.addObject("id", id);
        return mav;
    }

    //推送数据接口(群发)
    @ResponseBody
    @GetMapping("/groupSending")
    public String pushToWeb(@RequestParam("message") String message) {
        try {
            webSocket.GroupSending(message);
        } catch (Exception e) {
            e.printStackTrace();
            return "发送失败:"+e.getMessage();
        }
        return "发送成功";
    }

    //推送数据接口(点对点)
    @ResponseBody
    @GetMapping("/sendingToOne")
    public String pushToOne(@RequestParam("id") String id,@RequestParam("message") String message){
        try {
            webSocket.AppointSending(id, message);
        } catch (Exception e) {
            e.printStackTrace();
            return "发送失败";
        }
        return "发送成功";
    }

}

五、主要参考

简单实现:https://blog.csdn.net/moshowgame/article/details/80275084
基于STOMP协议的实现:https://url.cn/5IXXlj6

六、进阶教程

手把手搭建WebSocket多人在线聊天室:https://url.cn/5IXXlj6
【多人聊天室】WebSocket集群/分布式改造:https://url.cn/5IXXlj6
【WebSocket】实时多人答题对战游戏:https://url.cn/5IXXlj6七、总结

七、总结

学WebSocket最主要的原因,还是上边说到的,算是填了一个小坑吧。实际生活中,除了我的课设可能打算使用一下,其他情况暂时还没有遇到,所以也只简单的实现了一下。其实最终的目的还是想写一个类似于订阅-发布的这么一个小功能,所以进阶版的教程也没有再看下去了。简单搜了一下,似乎Redis可以,我还记得也有一个类似的设计模式来着,下一篇估计就是这个方向了。欢迎交流讨论。

源码

人已赞赏
Java编程语言

SpringBoot Shiro 入门及源码

2019-11-19 9:32:42

Java编程语言

Log4j2抽丝剥茧之入门及进阶

2019-12-26 20:49:43

2 条回复 A文章作者 M管理员
  1. 最后提到的应该都是观察者模式 redis那边是SUBSCRIBE和PUBLISH[aru_3]

    • 对滴,我看了一下redis的,我发现只能够群发,没法点对点

个人中心
今日签到
有新私信 私信列表
搜索