SSM框架整合WebSocket实现消息推送长连接,WebSocket实现扫码登录

使用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("登&nbsp;&nbsp;&nbsp;&nbsp;录");
		})
	}
}

以上就是我写的websocket扫码登录了,长连接也实现了
我没有把所有的页面代码放上来,但是文字已经说明了使用,看不懂我就没有办法咯
本人使用的框架是:
Spring + Spring MVC + Mybatis + Sql server + Layui

上一篇:利用错误重定向来防止未备案的恶意攻击


下一篇:ocx链接错误 Project : error PRJ0050: 未能注册输出。请尝试启用“每个用户的重定向”,或者用提升的权限从命令提示窗