基于WebSocket实现简单的扫码登录
WebSocket是一种在单个TCP连接上进行全双工通信的协议。 WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
因为是第一次接触,所以画了一个简单的流程图
上代码
- 导包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> </dependency>
2.开启spring支持
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
@Component @ServerEndpoint(value = "/websocket") public class WebSocketWxLogin { //用来存放每个连接对应的WebSocketWxLogin对象,适用于同时与多个客户端通信 public static CopyOnWriteArraySetwebSocketSet = new CopyOnWriteArraySet (); //其中Key为连接唯一标识 public static ConcurrentHashMap webSocketMap = new ConcurrentHashMap (); private Session session; /** * 建立连接成功调用的方法 */ @OnOpen public void onOpen(Session session)throws IOException { this.session = session; //我这里使用时间戳作为唯一id long l = System.currentTimeMillis(); String str = l+""; String sessionId = TripleDES.encode(str); webSocketSet.add(this); webSocketMap.put(sessionId,this); Map map = new HashMap(); map.put("code",400); map.put("msg","获取成功!"); map.put("sessionId",sessionId); String s = JSONObject.toJSONString(map); session.getBasicRemote().sendText(s); } /** * 关闭连接调用的方法 */ @OnClose public void onClose(Session closeSession){ System.out.println(session); webSocketMap.remove(session); webSocketSet.remove(this); } /** * 向用户推送消息 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } }
3.登录接口
@PostMapping("login") @ApiOperation(value = "扫码登录", notes = "扫码登录") private Object login(String sessionId) { Assert.notNull(sessionId,"缺少参数"); WebSocketWxLogin o1 = WebSocketWxLogin.webSocketMap.get(sessionId); Assert.notNull(o1,"二维码已过期"); Assert.notNull(getUser(),"未登录!"); String token = getRequest().getSession().getId(); redisUtil.set(String.format(RedisParam.KEY_MOBILE_USER_LOGIN, token), getUser(), RedisParam.LOGIN_EXPIRE_TIME); Map map = new HashMap(); map.put("code",401); map.put("msg","登录成功!"); map.put("token",token); String s = JSONObject.toJSONString(map); try { o1.sendLogin(s); }catch (Exception e){ return RespEntity.errorResp("登录失败!"); } return RespEntity.successResp("登录成功!",token); }
4.JS代码
<script type="text/javascript"> var websocket = new WebSocket("ws:127.0.0.1:8009/websocket"); //ws:服务器+端口/后端的端点 //接收到消息的回调方法 websocket.onmessage = function (event) { console.log(event.data); } //连接关闭的回调方法 websocket.onclose = function () { console.log("WebSocket连接关闭"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,确保断开时关闭连接 window.onbeforeunload = function () { closeSocket(); } //关闭WebSocket连接 function closeSocket() { websocket.close(); } </script>
如果线上使用了nginx,则需要在nginx配置文件里添加
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
这个写在server里
location /ws/ { proxy_pass http://127.0.0.1:8008/; proxy_read_timeout 600; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; }
第一次在博客园写随写,如有问题还望指正