基于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 CopyOnWriteArraySet
webSocketSet = 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;
}
第一次在博客园写随写,如有问题还望指正
