spring框架下基于websocket握手的拦截器配置(HandshakeInterceptor)

本次博客为记录小程序开发过程中遇到的问题,总结一些经验!

对于拦截器的配置,相信很多人都会碰到坑,当然遇到的坑越多,你的技能提升的越快,我觉得是对的。做项目是可以提升一个程序员的技能,考验开发能力的最好方法之一。

下面直接进入正题:

本次拦截器的配置主要是要实现在websocket握手前,对用户信息的验证及筛选。

在本系统中原先已实现了登录验证的拦截器,即判断小程序请求头中是否存在登录态信息。是则通过,不是则拦截。

同样的,如果想要在websocket握手前也达到此目的,在原先的mvc拦截器下加入是不行的,针对websocket官方有参考的接口HandshakeInterceptor,所以应该另外配置此拦截器。网上也有很多教程可以看,可以参考Java整合WebSocket实现实时推送(注解版)写的非常不错。

当然,该博客只是介绍了基本的配置,想要完成具体的配置还需完善。

 

A、

因为要区分login拦截器,我们首先应该对url进行过滤,不同的url应该去往不同的拦截器,首先在web.xml中添加<url-pattern></url-pattern>

 <!-- 前端控制器 -->
  <servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<init-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>classpath:springmvc-config.xml</param-value>
  	</init-param>
  	<load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<url-pattern>*.a</url-pattern>
  	<url-pattern>*.c</url-pattern>
  </servlet-mapping>

其中有两个<url-pattern></url-pattern>对不同的url进行过滤,程序中仅允许.a或.c结尾的url通过。

 

B、

接下来来到springmvc的配置文件下:

<!-- websocket握手 -->
	<bean id="wxsocket" class="com.yq.handler.MessageHandler"/>
	
	<websocket:handlers allowed-origins="*">
		<websocket:mapping path="/socketConnect.c" handler="wxsocket"/>
		<websocket:handshake-interceptors>
			<bean class="com.yq.interceptor.WebSocketInterceptor"/>
			
		</websocket:handshake-interceptors>
	</websocket:handlers>

添加以上配置。注解方面不是很了解,不知道行不行。

完成到这一步,在前端的wx.connectSocket下已经能够成功响应了并接入拦截器内部。

注意:

在开发中,发现很多人会遇到wss://...报错的问题,其实很简单

只需改成ws就可以了,因为wss表示的是加了SSL安全协议的请求,而开发过程中一般使用的都是本地ip。

 

C、

再来看HandshakeInterceptor具体配置

package com.yq.interceptor;

import java.util.Collection;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;

import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import com.yq.utils.RedisUtil;


/*
 * websocket连接拦截器
 */

public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor{
	
	@Autowired
	RedisUtil redisUtil;
	
	/*
	 * 握手后
	 * @see org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor#afterHandshake(org.springframework.http.server.ServerHttpRequest, org.springframework.http.server.ServerHttpResponse, org.springframework.web.socket.WebSocketHandler, java.lang.Exception)
	 */
	@Override
	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Exception ex) {
		
		System.out.println("对方正在输入...");
	}

	/*
	 * 握手前
	 * @see org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor#beforeHandshake(org.springframework.http.server.ServerHttpRequest, org.springframework.http.server.ServerHttpResponse, org.springframework.web.socket.WebSocketHandler, java.util.Map)
	 */
	@Override
	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Map<String, Object> attributes) throws Exception {
		HttpHeaders headers = request.getHeaders();
		String sessionid = headers.getFirst("sessionid");
		System.out.println("拦截器获取的sessionid"+sessionid);
		if(sessionid!=null && sessionid != "") {
			
			//检查是否存在
			if(redisUtil.isExist(sessionid)) {
				System.out.println("通过不拦截");
				response.setStatusCode(HttpStatus.OK);
				return true;
			}
			//session过期拦截
			System.out.println("拦截请求1:sessionid已过期!");
			response.setStatusCode(HttpStatus.FORBIDDEN);
			return false;
			
		}
		System.out.println("拦截请求2:sessionid为空");
		response.setStatusCode(HttpStatus.FORBIDDEN);
		
		return false;
	}

	@Override
	public Collection<String> getAttributeNames() {
		// TODO Auto-generated method stub
		return super.getAttributeNames();
	}

	@Override
	public boolean isCopyAllAttributes() {
		// TODO Auto-generated method stub
		return super.isCopyAllAttributes();
	}

	@Override
	public boolean isCopyHttpSessionId() {
		// TODO Auto-generated method stub
		return super.isCopyHttpSessionId();
	}

	@Override
	public boolean isCreateSession() {
		// TODO Auto-generated method stub
		return super.isCreateSession();
	}

	@Override
	public void setCopyAllAttributes(boolean copyAllAttributes) {
		// TODO Auto-generated method stub
		super.setCopyAllAttributes(copyAllAttributes);
	}

	@Override
	public void setCopyHttpSessionId(boolean copyHttpSessionId) {
		// TODO Auto-generated method stub
		super.setCopyHttpSessionId(copyHttpSessionId);
	}

	@Override
	public void setCreateSession(boolean createSession) {
		// TODO Auto-generated method stub
		super.setCreateSession(createSession);
	}
	
}

D、

最后来看下实际效果

 

1、第一次登录:

前端显示连接失败,是因为第一次登录不存在登录态,设置登录态30s时间。此时需要提醒用户运行登录

后台运行结果也显示了相关信息

拦截器获取的sessionid
拦截请求2:sessionid为空

2、模拟长时间未登录,登录态过期(30s):

同样的过期的用户不可以连接,需要重新登陆,此时需要提醒用户重新登录

后台运行结果,过期

拦截器获取的sessionid6574123103e869e00d24b4071f1fb6ce
拦截请求1:sessionid已过期!

3、处于登录状态

可以看到成功连接并发送信息了

后台运行结果

拦截器获取的sessionid894ca3ec8fe8507b516e659a9e4a464f
通过不拦截
对方正在输入...
。。。websocket已连接
message:有消息请接收..发送中
。。。websocket已断开连接

 

其中HttpSessionHandshakeInterceptor为官方给出的HandshakeInterceptor接口的实现类。

那么这里主要是对beforeHandshake()握手前进行拦截处理的介绍

如果大家想要了解更多的信息可以去参考该接口的源码,简单易懂。

以上就是我HandshakeInterceptor配置的全部内容,拦截逻辑上可能不是很严谨,希望大家看到的可以指点指点。

 

以下是在Spring Boot项目中整合WebSocket的步骤,包括拦截器、消息处理器和WebSocket实现类的编写: 1. 添加依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 编写WebSocket配置类 创建一个WebSocketConfig类,用于配置WebSocket相关的内容,包括注册WebSocket处理器、拦截器等。 ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Autowired private MyWebSocketHandler myWebSocketHandler; @Autowired private MyHandshakeInterceptor myHandshakeInterceptor; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myWebSocketHandler, "/websocket") .addInterceptors(myHandshakeInterceptor); } } ``` 在这个配置类中,我们注册了一个WebSocket处理器和一个握手拦截器WebSocket处理器用于处理WebSocket连接和消息,握手拦截器用于拦截WebSocket连接请求并进行一些处理。 3. 编写WebSocket处理器 创建一个WebSocket处理器类,用于处理WebSocket连接和消息。 ```java @Component public class MyWebSocketHandler extends TextWebSocketHandler { private static final Logger logger = LoggerFactory.getLogger(MyWebSocketHandler.class); private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { logger.info("WebSocket连接建立成功:{}", session.getId()); sessions.put(session.getId(), session); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { logger.info("收到消息:{}", message.getPayload()); // 处理消息 } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { logger.info("WebSocket连接关闭:{},状态:{}", session.getId(), status); sessions.remove(session.getId()); } public static void sendMessage(String sessionId, String message) throws IOException { WebSocketSession session = sessions.get(sessionId); if (session != null && session.isOpen()) { session.sendMessage(new TextMessage(message)); } } } ``` 在这个处理器类中,我们重写了WebSocket处理器的三个方法:afterConnectionEstablished、handleTextMessage和afterConnectionClosed。afterConnectionEstablished方法在WebSocket连接建立成功后被调用,handleTextMessage方法用于处理收到的消息,afterConnectionClosed方法在WebSocket连接关闭后被调用。 4. 编写握手拦截器 创建一个握手拦截器类,用于拦截WebSocket连接请求并进行一些处理。 ```java @Component public class MyHandshakeInterceptor implements HandshakeInterceptor { private static final Logger logger = LoggerFactory.getLogger(MyHandshakeInterceptor.class); @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { logger.info("WebSocket握手拦截器:beforeHandshake"); // 进行一些处理 return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { logger.info("WebSocket握手拦截器:afterHandshake"); } } ``` 在这个握手拦截器类中,我们重写了握手拦截器的两个方法:beforeHandshake和afterHandshake。beforeHandshake方法在WebSocket连接请求到达服务器端时被调用,afterHandshake方法在WebSocket连接握手成功后被调用。 5. 编写WebSocket实现类 创建一个WebSocket实现类,用于实现WebSocket的具体业务逻辑。 ```java @Controller public class MyWebSocketController { @MessageMapping("/hello") @SendTo("/topic/greetings") public String greeting(String message) throws Exception { Thread.sleep(1000); // 模拟处理时间 return "Hello, " + message + "!"; } } ``` 在这个WebSocket实现类中,我们使用了@MessageMapping注解来指定处理消息的路径,使用@SendTo注解来指定返回消息的路径。 6. 测试WebSocket连接 在客户端中,可以使用JavaScript代码来测试WebSocket连接: ```javascript var socket = new WebSocket("ws://localhost:8080/websocket"); socket.onopen = function(event) { console.log("WebSocket连接已建立"); socket.send("Hello, WebSocket!"); }; socket.onmessage = function(event) { console.log("收到消息:" + event.data); }; socket.onclose = function(event) { console.log("WebSocket连接已关闭"); }; ``` 以上就是在Spring Boot项目中整合WebSocket的步骤,包括拦截器、消息处理器和WebSocket实现类的编写。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值