SSM下增加服务端WebSocket推送

本文介绍了在SSM框架下如何实现WebSocket服务端推送,包括maven依赖的引入,`spring-websocket.xml`配置文件的创建,两种不同的实现方法(MyWebSocketConfig和MyWebSocketHandler),以及MyHandshakeInterceptor拦截器的使用。此外,还提供了动态代理Nginx配置WebSocket的指导。

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


根据业务需求,许多场景下都需要用到即时推送的技术。首先当即研究了一下怎么引入该实用组件。

1.maven引入依赖

(此处用的是spring的websocket)这边会涉及到版本依赖的问题(如果版本不兼容会出现classNotDefind/方法找不到等问题),这里暂不考虑(我们项目spring引入的也是这个版本,同版本一般不会出问题)

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-websocket</artifactId>
			<version>4.3.7.RELEASE</version>
		</dependency>

2.创建一个spring-websocket.xml

(抽出来比较容易维护),并且这边涉及到了两种写法(一种被注释的,但是亲测都是可以使用的,就看你喜欢哪一种)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:websocket="http://www.springframework.org/schema/websocket"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/websocket  
       	http://www.springframework.org/schema/websocket/spring-websocket.xsd
		">
<!-- 	<bean id="myWebSocketConfig" class="com.gss.fruitmall.we.websocket.config.MyWebSocketConfig" /> -->
	<bean id="websocket" class="com.gss.fruitmall.we.websocket.handler.MyWebSocketHandler" />
	<websocket:handlers allowed-origins="*" >
		<websocket:mapping path="/websocket" handler="websocket" />
		<websocket:handshake-interceptors>
			<bean class="com.gss.fruitmall.we.websocket.interceptor.MyHandshakeInterceptor"  />
		</websocket:handshake-interceptors>
	</websocket:handlers>
</beans>

上面的xml中的 http://www.springframework.org/schema/websocket/spring-websocket.xsd 配置导致我调试了很久,因为如果使用spring-websocket-4.0.xsd,下面的那种配置没法配置allowed-origins 没有这个属性,博主纠结呀。(主要还是想两种方法都实践成功 =- = ,毕竟要理解一个东西,先能跑起来是比较有利的)

3.创建类

(两种方法使用到的类有所不同,在配置和类中都可以提现出来)

3.1方法一

MyWebSocketConfig第一种方法,作为socket配置监听,来分配处理类和拦截器

package com.gss.fruitmall.we.websocket.config;

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;

import com.gss.fruitmall.we.websocket.handler.MyWebSocketHandler;
import com.gss.fruitmall.we.websocket.interceptor.MyHandshakeInterceptor;

@Configuration
@EnableWebMvc
@EnableWebSocket
public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{

	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(getHandler(), "/websocket").setAllowedOrigins("*").addInterceptors(getInterceptor());
	}
	
	@Bean
	public MyWebSocketHandler getHandler() {
		return new MyWebSocketHandler();
	}
	
	@Bean
	public MyHandshakeInterceptor getInterceptor() {
		return new MyHandshakeInterceptor();
	}
	

}

3.2 方法二

MyWebSocketHandler 主要的消息处理类,这边只做简单处理

package com.gss.fruitmall.we.websocket.handler;

import java.io.IOException;
import java.util.ArrayList;

import org.apache.log4j.Logger;
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;

public class MyWebSocketHandler implements WebSocketHandler {

	private static final Logger log = Logger.getLogger(MyWebSocketHandler.class);

	private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>();

	// 初次链接成功执行
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		users.add(session);
	}

	// 接受消息处理消息
	public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage)
			throws Exception {
		// sendMessageToUsers(new TextMessage(webSocketMessage.getPayload() + ""));
		// sendMessageToUser(userName, new TextMessage(webSocketMessage.getPayload() +
		// ""));

	}

	public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
		if (webSocketSession.isOpen()) {
			webSocketSession.close();
		}
		users.remove(webSocketSession);
	}

	public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
		// System.out.println(webSocketSession.getAttributes().get("WEBSOCKET_USERID"));
		users.remove(webSocketSession);
	}

	public boolean supportsPartialMessages() {
		return false;
	}

	/**
	 * 给所有在线用户发送消息
	 *
	 * @param message
	 */
	public static int sendMessageToUsers(TextMessage message) {
		int senCount = 0;
		for (WebSocketSession user : users) {
			try {
				if (user.isOpen()) {
					user.sendMessage(message);
					senCount++;
				}
			} catch (IOException e) {
				e.printStackTrace();
				log.error("推送所有用户错误", e);
			}
		}
		return senCount;
	}

	/**
	 * 给某个用户发送消息,模拟给admin发信息
	 *
	 * @param userId
	 * @param message
	 */
	public static void sendMessageToUser(String userId, TextMessage message) {
		for (WebSocketSession user : users) {
			if (user.getAttributes().get("WEBSOCKET_USERID").equals(userId)) {
				try {
					if (user.isOpen()) {
						user.sendMessage(message);
					}
				} catch (IOException e) {
					e.printStackTrace();
					log.error("推送用户错误", e);
				}
				break;
			}
		}
	}
}

3.3 MyHandshakeInterceptor拦截器,可扩展
package com.gss.fruitmall.we.websocket.interceptor;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

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 me.chanjar.weixin.common.util.StringUtils;

/**
 * 拦截器
 */
public class MyHandshakeInterceptor implements HandshakeInterceptor {
	// 初次握手访问前
	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse,
			WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
		if (request instanceof ServletServerHttpRequest) {
			HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
			String userId = servletRequest.getParameter("userId");
			// 使用userId区分WebSocketHandler,以便定向发送消息
			if (StringUtils.isNotBlank(userId)) {
				map.put("WEBSOCKET_USERID", userId);
				servletRequest.getSession().setAttribute("WEBSOCKET_USERID", userId);
			}
		}
		return true;
	}

	// 初次握手访问后
	public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
			WebSocketHandler webSocketHandler, Exception e) {
	}
}

如果是xml中注释的方法,拦截器和处理类类名都需要加上@Component注解以便注入配置里面。

这种配置都是使用以下方式连接

new WebSocket("ws://域名/项目名/websocket?userId=111")

另外,附加动态代理nginx配置websocket:

只要在拦截到的location中加入:或者不懂的可以都加 ( ̄▽ ̄)"

location ~ ^/test/wefruitmall/game/ {		#这边是我拦截到需要处理的url
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "upgrade";
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值