1. 程式人生 > >spring websocket實現

spring websocket實現

注:需spring4.0及以上版本。

步驟:

1、匯入jar包(maven方式)

<!-- Spring websocket -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>4.3.10.RELEASE</version>
</dependency>

2、編寫WebSocketConfig類,用於配置websocket

package com.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{

	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		//允許連線的域;只能以http或https開頭
		String[] allowsOrigins = {"https://www.xxx.com"};
		//WebIM WebSocket通道
		registry.addHandler(WebSocketHandler(), "/websocket").addInterceptors(WebScoketInterceptor());
	}
	@Bean
	public WebSocketHandler WebSocketHandler() {
		return WebSocketHandler();
	}
	@Bean
	public WebScoketInterceptor WebScoketInterceptor() {
		return new WebScoketInterceptor();
	}
}

也可用spring的配置檔案:

檔案頭部新增websocket的xsd檔案:

xmlns:websocket="http://www.springframework.org/schema/websocket"
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd
<!-- websocket處理器 -->
<bean id="websocket" class="com.websocket.WebSocketHandler"></bean>
<websocket:handlers>
	<websocket:mapping path="/websocket" handler="websocket"></websocket:mapping>
	<!-- websocket攔截器 -->
	<websocket:handshake-interceptors>
		<bean class="com.websocket.WebScoketInterceptor"/>
	</websocket:handshake-interceptors>
</websocket:handlers>

3、編寫WebScoketInterceptor,攔截器的作用是將此連線與使用者對應

package com.websocket;

import java.util.Map;
import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

public class WebScoketInterceptor implements HandshakeInterceptor{

	@Override
	public void afterHandshake(ServerHttpRequest httpRequest, ServerHttpResponse httpResponse, WebSocketHandler handler, Exception e) {
		
	}

	@Override
	public boolean beforeHandshake(ServerHttpRequest httpRequest, ServerHttpResponse httpResponse, WebSocketHandler handler,
			Map<String, Object> map) throws Exception {
		ServletServerHttpRequest request = (ServletServerHttpRequest) httpRequest;
		//獲取httpSession拿到此連結對應的使用者,websocket中可以拿到http協議對應的httpSession
		HttpSession session = request.getServletRequest().getSession();
		if (session != null) {
			map.put("userId", session.getAttribute("userId"));
		}
		return true;
	}
}

4、編寫WebSocketHandler,繼承自AbstractWebSocketHandler,提供了建立連線,關閉連線,連線發生錯誤等回撥方法,用於實現自己的業務邏輯

package com.websocket;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
/**
 * websocket處理器
 * @author Administrator
 *
 */
public class WebSocketHandler extends AbstractWebSocketHandler {
	private static final Map<Integer, WebSocketSession> wsUserMap = new HashMap<Integer, WebSocketSession>();
	/**
	 * 處理前端傳送的文字資訊
	 * @throws IOException
	 */
	@Override
	public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		Integer userId = getUserIdBySession(session);
		System.out.println("收到userId為:" + userId + "的使用者發的訊息" + message.toString());
		//給使用者回覆一條訊息
//		session.sendMessage(new TextMessage("reply msg:" + message.getPayload()));
	}
	/**
	 * 成功建立連線
	 */
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		Integer userId = getUserIdBySession(session);
		wsUserMap.put(userId, session);
		super.afterConnectionEstablished(session);
		System.out.println("使用者id為" + userId + "的使用者建立連線");
	}
	/**
	 * 關閉連線
	 */
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		Integer userId = getUserIdBySession(session);
		wsUserMap.remove(userId);
		super.afterConnectionClosed(session, status);
		System.out.println("使用者id為" + userId + "的使用者關閉了連線");
	}
	/**
	 * 連線發生錯誤
	 */
	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		exception.printStackTrace();
		Integer userId = getUserIdBySession(session);
		wsUserMap.remove(userId);
		super.handleTransportError(session, exception);
	}
	/**
	 * 給某個使用者傳送訊息
	 */
	public static boolean sendMessageToUser(Integer userId,Integer toUserId, TextMessage message) {
		WebSocketSession tosession = wsUserMap.get(toUserId);
		if (tosession != null && tosession.isOpen()) {
			try {
				tosession.sendMessage(new TextMessage("{" + userId + ":" + message.getPayload()+ "}"));
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}
			return true;
		} else {
			return false;
		}
	}
	/**
	 * 給全部使用者傳送訊息
	 */
	public static void sendMessageToAllUser(TextMessage message) {
		Set<Integer> userSet = wsUserMap.keySet();
		for (Integer i : userSet) {
			WebSocketSession session = wsUserMap.get(i);
			if (session != null && !session.isOpen()) {
				try {
					session.sendMessage(message);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	private Integer getUserIdBySession(WebSocketSession session) {
		Integer userId = (Integer) session.getAttributes().get("userId");
		return userId;
	}
}

5、配置SpringWebSocketConfig了配置類隨spring容器啟動,此步驟為使用WebSocketConfig類做配置是使用,用spring配置檔案做websocket的配置時可省略。

<!-- websocket配置掃描 -->
<context:component-scan base-package="com.websocket"/>

6、建立controller,僅簡單測試。

package com.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.socket.TextMessage;

import com.websocket.WebSocketHandler;

@Controller
public class WebSocketController {
	//模擬登入
	@RequestMapping("login")
	public void login(HttpServletRequest request, HttpServletResponse response) {
		int userId = Integer.parseInt(request.getParameter("userId"));
		HttpSession session = request.getSession();
		session.setAttribute("userId", userId);
	}
	//使用者給另一使用者傳送訊息
	@RequestMapping("sendMessageToUser")
	public void sendMessageToUser(HttpServletRequest request, HttpServletResponse response) {
		int toUserId = Integer.parseInt(request.getParameter("toUserId"));
		int userId = Integer.parseInt(request.getParameter("userId"));
		CharSequence message = request.getParameter("message");
		TextMessage mess = new TextMessage(message);
		WebSocketHandler.sendMessageToUser(userId, toUserId, mess);
	}
	//給當前所有線上使用者傳送訊息
	
}

7、客戶端程式碼(建立連線部分)

var ws;
function websocketTest() {
	ws = new WebSocket("ws://localhost:8080/websocketTest/websocket");
	ws.open = function() {
		console.log("open");
	}
	ws.onclose = function() {
		console.log("onclose");
	}
	ws.onmessage = function(evt) {
		console.log(evt);
		alert(evt.data);
	};
}