【WebSocket】Spring4.3+WebSocket+Tomcat8.5实现即时消息推送

本文详细介绍WebSocket客户端和服务端的实现过程,包括配置、拦截器、处理器及会话管理工具的代码示例,帮助读者掌握WebSocket的实践应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WebSocket客户端:

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title>WebSocketDemo</title>
	</head>

	<body>
		<P id="message">暂无消息<br/></P>
	</body>
	<script type="text/javascript">
		var websocket = null;
		//判断当前浏览器是否支持WebSocket,使用ws或者wss协议访问服务端
		if("WebSocket" in window) {
			websocket = new WebSocket("ws://localhost:8080/demo/websocket")
			alert("浏览器支持WebSocket");
		} else {
			alert("浏览器不支持支持WebSocket");
		}
		//连接发生错误的回调方法
		websocket.onerror = function() {  
			alert("WebSocket连接发生错误")
			setMessageInnerHTML("WebSocket连接发生错误");
		};
		//连接成功建立的回调方法 
		websocket.onopen = function() {  
			alert("WebSocket连接成功")
			setMessageInnerHTML("WebSocket连接成功");
			//发送消息
			websocket.send("hello server");
		}

		//接收到消息的回调方法 
		websocket.onmessage = function(event) {
			alert("后台响应消息:" + event.data);  
			setMessageInnerHTML(event.data);  
			websocket.close();    
		}
		//连接关闭的回调方法 
		websocket.onclose = function() {
			setMessageInnerHTML("WebSocket连接关闭");
		}
		//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 
		window.onbeforeunload = function() {
			closeWebSocket();
		}
		//关闭WebSocket连接 
		function closeWebSocket() {
			websocket.close();
		}
		//将消息显示在网页上
		function setMessageInnerHTML(innerHTML) {
			document.getElementById('message').innerHTML += innerHTML + '<br/>';
		}
	</script>

</html>

WebSocket服务端:

  • WebSocket配置(注解方式):

package com.demo.websocket.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import com.demo.websocket.handler.CustomWebSocketHandler;
import com.demo.websocket.intercepter.WebSocketHandshakeIntercept;

@Configuration
@EnableWebSocket
@EnableWebMvc
public class WebSocketConfig implements WebSocketConfigurer {
	/**
	 * 将 WebSocket 处理器添加到注册中心
	 */
	public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
		webSocketHandlerRegistry.addHandler(getWebSocketHandler(), "/websocket")
				.addInterceptors(new WebSocketHandshakeIntercept()).setAllowedOrigins("*");
	}

	/**
	 * 获取WebSocket处理器,可以根据业务需要自定义处理器
	 */
	@Bean
	public WebSocketHandler getWebSocketHandler() {
		return new CustomWebSocketHandler();
	}

	/**
	 * 调整处理异常的优先级
	 */
	@Bean
	public HandlerExceptionResolver handlerExceptionResolver() {
		List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<HandlerExceptionResolver>();
		HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
		composite.setOrder(10);
		composite.setExceptionResolvers(exceptionResolvers);
		return composite;
	}

}
  • WebSocket拦截器:

package com.demo.websocket.intercepter;

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;

import com.demo.websocket.util.WebSocketSessionUtils;

public class WebSocketHandshakeIntercept implements HandshakeInterceptor {
	/**
	 * 设置sessionId
	 */
	@Override
	public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
			WebSocketHandler webSocketHandler, Map<String, Object> attributes) throws Exception {
		HttpSession session = getSession(serverHttpRequest);
		if (session != null) {
			String sessionId = (String) session.getAttribute("sessionId");
			if (sessionId == null) {
				sessionId = WebSocketSessionUtils.getUUID();
			}
			attributes.put("sessionId", sessionId);
		}
		return true;
	}

	@Override
	public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
			WebSocketHandler webSocketHandler, Exception exception) {
	}

	private HttpSession getSession(ServerHttpRequest serverHttpRequest) {
		if (serverHttpRequest instanceof ServletServerHttpRequest) {
			ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) serverHttpRequest;
			return servletServerHttpRequest.getServletRequest().getSession(true);
		}
		return null;
	}
}
  • WebSocket处理器:

package com.demo.websocket.handler;

import java.util.concurrent.TimeUnit;

import org.apache.commons.collections.MapUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

import com.demo.websocket.util.WebSocketSessionUtils;

public class CustomWebSocketHandler implements WebSocketHandler {
	/**
	 * 建立连接之后的操作
	 */
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		String sessionId = MapUtils.getString(session.getAttributes(), "sessionId");
		WebSocketSessionUtils.add(sessionId, session);
	}

	/**
	 * 异常处理
	 */
	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		String sessionId = MapUtils.getString(session.getAttributes(), "sessionId");
		WebSocketSessionUtils.remove(sessionId);
	}

	/**
	 * 关闭连接之后的操作
	 */
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		String sessionId = MapUtils.getString(session.getAttributes(), "sessionId");
		WebSocketSessionUtils.remove(sessionId);
	}

	/**
	 * 处理消息
	 */
	@Override
	public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
		if (message instanceof TextMessage) {
			// 获取前端发送的消息
			String msg = message.getPayload().toString();
			System.out.println("已收到消息:" + msg);
			String sessionId = MapUtils.getString(session.getAttributes(), "sessionId");
			// 等待10s,模拟后台处理消息
			TimeUnit.SECONDS.sleep(10);
			if (WebSocketSessionUtils.exists(sessionId)) {
				// 如果存在此sessionId,则向其发送应答消息
				WebSocketSessionUtils.sendMessage(sessionId, "hello client");
			}
		}
	}

	/**
	 * 是否处理分片消息
	 */
	@Override
	public boolean supportsPartialMessages() {
		return false;
	}

}
  • WebSocket会话管理工具:

package com.demo.websocket.util;

import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

public class WebSocketSessionUtils {
	/**
	 * session缓存
	 */
	private static Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

	/**
	 * 保存连接
	 */
	public static void add(String sessionId, WebSocketSession session) {
		sessions.put(sessionId, session);
	}

	/**
	 * 获取连接
	 */
	public static WebSocketSession get(String sessionId) {
		return sessions.get(sessionId);
	}

	/**
	 * 移除连接
	 */
	public static void remove(String sessionId) {
		sessions.remove(sessionId);
	}

	/**
	 * 清空连接
	 */
	public static void clear() {
		sessions.clear();
	}

	/**
	 * 获取连接数
	 */
	public static int getconnections() {
		return sessions.size();
	}

	/**
	 * 是否存在
	 */
	public static boolean exists(String sessionId) {
		if (sessions.containsKey(sessionId)) {
			return true;
		}
		return false;
	}

	/**
	 * 发送消息到客户端
	 */
	public static void sendMessage(String sessionId, String message) {
		if (sessionId == null || !exists(sessionId)) {
			throw new NullPointerException(sessionId);
		}
		WebSocketSession session = get(sessionId);
		try {
			session.sendMessage(new TextMessage(message));
		} catch (IOException e) {
			remove(sessionId);
			e.printStackTrace();
		}
	}

	/**
	 * 获得UUID
	 */
	public static String getUUID() {
		return UUID.randomUUID().toString().replaceAll("-", "");
	}
}

依赖配置:

		<!-- spring相关包 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
            <version>4.3.18.RELEASE</version>
		</dependency>
 		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-websocket</artifactId>
            <version>4.3.18.RELEASE</version>
		</dependency>

注意:

  1. 如果使用Nginx代理服务器,需要在配置文件中添加超时配置
location / {
            proxy_read_timeout 3600s;
        }

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值