使用SSM框架整合WebSocket
pom.xml中引入依赖
<!-- WebSocket配置-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
Java中
复制过去稍微改一下自己需要的东西就好了,这里的‘大数据’推送可以不管
不用在xml中配置也可以直接使用,使用时记得把过滤器的拦截放行‘/webSocket’请求
package com.websocket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
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 net.sf.json.JSONObject;
@ServerEndpoint("/webSocket/{type}/{uuid}")
public class WebSocket {
private static int onlineCount = 0; //本来用统计在线人数的
private static Map<String, WebSocket> loginMap = new ConcurrentHashMap<String, WebSocket>(); // 饿汉式
private static List<Map<String, WebSocket>> clients = null; // 懒汉式
public Session session;
public String userName;
public String uuid;
public static long timeCount = 0;
/**
* 打开连接
* @param type
* @param username
* @param session
* @throws IOException
*/
@OnOpen
public void onOpen(@PathParam("type") String type,@PathParam("uuid") String uuid, Session session) throws IOException {
this.userName = type;
this.uuid = uuid;
this.session = session;
if(type != null) {
if(type.equals("login")) {// 登录
loginMap.put(uuid, this);
}else{
if(clients == null) {// 大数据
synchronized (WebSocket.class) {
if(clients == null) {
clients = new ArrayList<Map<String, WebSocket>>();
}
}
}
Map<String, WebSocket> clien = new ConcurrentHashMap<String, WebSocket>();
clien.put(uuid, this);
clients.add(clien);
}
}
//addOnlineCount();//本来用统计在线人数的
}
/**
* 删除
* @throws IOException
*/
@OnClose
public void onClose() throws IOException {
if(userName != null && userName.equals("login")) {// 登录
if(loginMap != null) {
loginMap.remove(uuid);
}
}else {
if(clients != null) {
for(int i=0; i< clients.size(); i++) { // 大数据
Map<String, WebSocket> clien = clients.get(i);
for (WebSocket item : clien.values()) {
if(item.session.equals(session))
clients.remove(i);
}
}
}
}
//subOnlineCount(); //本来用统计在线人数的
}
/**
* 错误信息
*/
@OnError
public void one rror(Session session, Throwable error) {
error.printStackTrace();
}
/**
* 接收数据
* @param jsonTo
* @throws IOException
*/
@OnMessage
public static void onMessage(String message) throws IOException {
JSONObject jsonTo = JSONObject.fromObject(message);
String mes = (String) jsonTo.get("message");
String type = (String) jsonTo.get("type");
String to = (String) jsonTo.get("To");
if(type != null) {
if(type.equals("login")){// 登录
sendMessageLoginTo(mes, to);
}else if(type.equals("data")) {// 大数据
sendMessage(mes, to);
}
}
}
/**
* 发给指定-登录
* @param message
* @param To
* @param mark
* @throws IOException
*/
public static void sendMessageLoginTo(String message, String To) throws IOException {
//session.getBasicRemote().sendText(message); // 同步
//session.getAsyncRemote().sendText(message); // 异步
if (loginMap != null) {
for (WebSocket item : loginMap.values()) {
if (item.userName.equals(To) )
item.session.getAsyncRemote().sendText(message);
}
}
}
/**
* 发给指定-大数据
* @param message
* @param To
* @param mark
* @throws IOException
*/
public static void sendMessage(String message, String to) throws IOException {
if (clients != null) { // 大数据
for(int i=0; i< clients.size(); i++) {// 这里(循环中套了个循环判断,用了线程加自带的异步推送)
new WebSocketThread(i,clients, to, message).start();// 这里写到另一个类上了参考下面两个(暂时不用)的就好
}
}
// 说明:如果多个消息推送使用同一个session推送消息,socket多线程冲突
// 报错:webSocket多线程推送出错,报错信息为The remote endpoint was in state [TEXT_PARTIAL_WRITING]
// 建议使用:Thread.sleep(100); 根据同一个session判断(自己写咯)
}
/**
* 发给指定-大数据(暂时不用)
* @param message
* @param To
* @param mark
* @throws IOException
*/
public static void sendMessageTo(String message, String to) throws IOException {
if (clients != null) { // 大数据
for(int i=0; i< clients.size(); i++) {
Map<String, WebSocket> clien = clients.get(i);
for (WebSocket item : clien.values()) {
if (item.uuid.equals(to) )
item.session.getAsyncRemote().sendText(message);
}
}
}
}
/**
* 发给全部 -大数据(暂时不用)
* @param message
* @throws IOException
*/
public static void sendMessageAll(String message) throws IOException {
for(int i=0; i< clients.size(); i++) {
Map<String, WebSocket> clien = clients.get(i);
for (WebSocket item : clien.values()) {
item.session.getAsyncRemote().sendText(message);
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocket.onlineCount--;
}
public static synchronized Map<String, WebSocket> getLoginMap() {
return loginMap;
}
public static synchronized List<Map<String, WebSocket>> getClients() {
return clients;
}
}
JS中
websocket是html5自带的协议
这里的二维码生成方式和路径参数我就不写了
我是使用了UUID传到手机确认的,UUID是我存放到后台Java中的键值对标识
var websocket = null;
var host = document.location.host;
var judgeTemp = 0;
var temp_uuid;
// 其他地方调用初始化websocket连接
function openWebSorket(uuid){// uuid 是生成的二维码参数传到手机,然后确认登录后传回来后台对应推送的
temp_uuid = uuid;
createWebSorket(uuid);
}
function createWebSorket(uuid){
try{
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window) {
websocket = new WebSocket('ws://' + host + '/securityIntelligence/webSocket/login/'+uuid);
initEventHandle();
} else {
alert('当前浏览器无法使用扫码登录');
}
}catch(err){
loadTemp++;
if(loadTemp == 5){// 重连5 次不行就重新刷新浏览器
window.location.reload();
}
console.log(err)
console.log(err.message);
setTimeout(function(){
createWebSorket(uuid);// 由于网络问题可能无法连接(两秒后重新连接)
}, 2000)
}
}
function initEventHandle(){
//连接发生错误的回调方法
websocket.onerror = function() {
judgeTemp = 1;
console.log('扫码登录连接失败');
};
//连接成功建立的回调方法
websocket.onopen = function() {
console.log('扫码登录连接成功');
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
console.log('扫码回馈消息');
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function() {
console.log('扫码登录连接关闭');
if(judgeTemp != 1){
createWebSorket(temp_uuid);
}
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
judgeTemp = 1;
closeWebSocket();
}
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
/**
* 手机端确定登录后页面登录跳转主页
* @returns
*/
function setMessageInnerHTML(data){
judgeTemp = 1;
if(tempNum == 0){// tempNum 全局的防止重复点击登录用的,这里直接拿过来的不改了
tempNum = 1;
$('#submit').addClass('layui-btn-disabled');
$('#submit').html("正在登录中...");
$.post(systemPath+"login/login", {},function(data) {// 这里参数和推送的自己定义
layer.msg(data.msg,{"zIndex":9999999999,"offset":"15%"})
if (data.success) {// 登录成功了
closeWebSocket();
window.location.href = systemPath+"page/main";
}
tempNum = 0;
$('#submit').removeClass('layui-btn-disabled');
$('#submit').html("登 录");
})
}
}
以上就是我写的websocket扫码登录了,长连接也实现了
我没有把所有的页面代码放上来,但是文字已经说明了使用,看不懂我就没有办法咯
本人使用的框架是:
Spring + Spring MVC + Mybatis + Sql server + Layui