1.前置要求和授权登录原理
2.读取自定义json配置文件信息
3.获取跳转url和回调的接口
4.使用websocket和前端建立连接
5.对接qq登录的流程
本章是写对于前端的调用
实现前端和后端的结合,利用websocket使用建立连接
完成登录的整个流程
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-websocketartifactId>
dependency>
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
package top.chenyp.qqService.controller;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
/*@ServerEndpoint注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@ServerEndpoint("/qq/{state}")
@Component
public class WsController {
//每个客户端都会有相应的session,服务端可以发送相关消息
private Session session;
//接收userID
private String state;
//J.U.C包下线程安全的类,主要用来存放每个客户端对应的webSocket连接
private static CopyOnWriteArraySet<WsController> copyOnWriteArraySet = new CopyOnWriteArraySet<WsController>();
public String getState() {
return state;
}
/**
* @Name:onOpen
* @Description:打开连接。进入页面后会自动发请求到此进行连接
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:@PathParam("userID") Integer userID
* @Return:
*/
@OnOpen
public void onOpen(Session session, @PathParam("state") String state) {
this.session = session;
this.state = state;
System.out.println(this.state);
System.out.println(this.session.getId());
copyOnWriteArraySet.add(this);
System.out.println("websocket有新的连接, 总数:"+ copyOnWriteArraySet.size());
}
/**
* @Name:onClose
* @Description:用户关闭页面,即关闭连接
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnClose
public void onClose() {
copyOnWriteArraySet.remove(this);
System.out.println("websocket连接断开, 总数:"+ copyOnWriteArraySet.size());
}
/**
* @Name:onMessage
* @Description:测试客户端发送消息,测试是否联通
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnMessage
public void onMessage(String message) {
System.out.println("websocket收到客户端发来的消息:"+message);
}
/**
* @Name:onError
* @Description:出现错误
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误:" + error.getMessage() + "; sessionId:" + session.getId());
error.printStackTrace();
}
public void sendMessage(Object object){
//遍历客户端
for (WsController webSocket : copyOnWriteArraySet) {
System.out.println("websocket广播消息:" + object.toString());
try {
//服务器主动推送
webSocket.session.getBasicRemote().sendObject(object) ;
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* @Name:sendMessage
* @Description:用于发送给客户端消息(群发)
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
public void sendMessage(String message) {
//遍历客户端
for (WsController webSocket : copyOnWriteArraySet) {
System.out.println("websocket广播消息:" + message);
try {
//服务器主动推送
webSocket.session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* @throws Exception
* @Name:sendMessage
* @Description:用于发送给指定客户端消息
* @Author:mYunYu
* @Create Date:14:47 2018/11/15
* @Parameters:
* @Return:
*/
public static void sendMessage(String state, String message) throws Exception {
Session session = null;
WsController tempWebSocket = null;
for (WsController webSocket : copyOnWriteArraySet) {
System.out.println(state);
System.out.println(webSocket.getState());
if (webSocket.getState().equals(state) ) {
tempWebSocket = webSocket;
session = webSocket.session;
break;
}
}
if (session != null) {
//服务器主动推送
tempWebSocket.session.getBasicRemote().sendText(message);
} else {
System.out.println("没有找到你指定ID的会话:{}"+ "; state:" + state);
}
}
/**
* 群发自定义消息
* */
public static void sendInfo(String message) throws IOException {
for (WsController item : copyOnWriteArraySet) {
item.sendMessage(message);
}
}
}
<template>
<div class="home">
<div style="height: 300px;">
div>
<button @click="getQQUrl">
qq登录
button>
div>
template>
<script>
import qqConf from '../utils/qqConf.json'
export default {
name: 'HomeView',
data() {
return {
socket: '',
qq_win: '',
isClose: false
}
},
created() {
},
methods: {
//建立websocket连接
init(uuid) {
// 实例化socket
this.socket = new WebSocket(qqConf.wsUrl + uuid)
// 监听socket连接
this.socket.onopen = this.open
// 监听socket错误信息
this.socket.onerror = this.error
// 监听socket消息
this.socket.onmessage = this.getMessage
// 监听socket断开连接的消息
this.socket.onclose = this.close
},
open() {
console.log("socket连接成功")
},
error() {
console.log("连接出错")
},
getMessage(message) {
console.log("收到消息");
let data = JSON.parse(message.data)
//根据获取的信息openid和userInfo
let flag = true;
//请求数据库账户信息
//1.未注册,去注册并携带param
console.log(data);
if (flag) {
this.$router.push({ path: '/about', query: {state:data.state} })
}
//2.已注册,去登录,调登录接口
if(!flag){
console.log('调登录接口');
this.$router.push({path:'/home'})
}
//例子login
this.socket.close()
this.isClose = true
},
close() {
console.log("断开连接成功");
},
getQQUrl() {
this.$axios.get(qqConf.host + "/getQQUrl").then(res => {
let url = res.data
let uuid = this.uuid()
url = url + "?state=" + uuid
console.log(uuid);
let qq_win = this.openQQLogin(url)
// this.callback(qq_win, uuid)
this.init(uuid)
this.callback(qq_win);
})
},
callback(qq_win) {
let _this = this
//轮询获取username
let TID = setTimeout(() => {
if (this.isClose) {
clearTimeout(TID);
qq_win.close()
this.socket.close()
return _this;
} else {
this.callback(qq_win)
}
}, 200);
},
openQQLogin(qqurl, iWidth, iHeight) {
if (iWidth === undefined) iWidth = 800;
if (iHeight === undefined) iHeight = 600;
// console.log(iHeight===undefined);
//window.screen.height获得屏幕的高,window.screen.width获得屏幕的宽
let iTop = (window.screen.height - 30 - iHeight) / 2; //获得窗口的垂直位置;
let iLeft = (window.screen.width - 10 - iWidth) / 2; //获得窗口的水平位置;
let qq_win = window.open(qqurl, 'newwindow', 'height=' + iHeight + ',,innerHeight=' + iHeight + ',width=' + iWidth + ',innerWidth=' + iWidth + ',top=' + iTop + ',left=' + iLeft + ',toolbar=no,menubar=no,scrollbars=auto,resizeable=no,location=no,status=no');
// window.location.href = qqurl
return qq_win
},
uuid() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
// s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
}
}
}
script>