springmvc项目中使用spring-websocket

spring-websocket,是spring对websocket的一个封装。

我更喜欢原生的javax.websocket

Web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE xml>
<web-app version="4.0"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
        	 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
        	 
      
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
		<dispatcher>REQUEST</dispatcher>
		<dispatcher>FORWARD</dispatcher>
	</filter-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:application-*.xml</param-value>
	</context-param>

	<listener>
		<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
	</listener>
	<context-param>
		<param-name>logbackConfigLocation</param-name>
		<param-value>classpath:logback.xml</param-value>
	</context-param>
	
	<welcome-file-list>
    	<welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Maven

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>io.springboot</groupId>
	<artifactId>spring-websocket</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<dependencies>
		<!-- websocket api -->
		<dependency>
			<groupId>javax.websocket</groupId>
			<artifactId>javax.websocket-api</artifactId>
			<version>1.1</version>
			<scope>provided</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.2.8.RELEASE</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-websocket -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-websocket</artifactId>
			<version>5.2.8.RELEASE</version>
		</dependency>

		<!-- Gson -->
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>2.8.6</version>
		</dependency>

		<!-- logback -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>1.7.30</version>
		</dependency>
		<dependency>
			<groupId>org.logback-extensions</groupId>
			<artifactId>logback-ext-spring</artifactId>
			<version>0.1.5</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>websocket</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<compilerArgs>
						<arg>-parameters</arg>
					</compilerArgs>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
			<!-- jetty插件 -->
			<plugin>
				<groupId>org.eclipse.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>9.4.31.v20200723</version>
				<configuration>
					<httpConnector>
						<port>80</port>
					</httpConnector>
					<webApp>
						<contextPath>/</contextPath>
					</webApp>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

配置文件

sping-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
			http://www.springframework.org/schema/beans/spring-beans.xsd 
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc.xsd
			">
	<mvc:annotation-driven></mvc:annotation-driven>
	
</beans>

application-websocket.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:websocket="http://www.springframework.org/schema/websocket"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
			http://www.springframework.org/schema/beans/spring-beans.xsd 
			http://www.springframework.org/schema/websocket
			http://www.springframework.org/schema/websocket/spring-websocket.xsd
			">

	<bean id="messageHandler" class="io.spring.websocket.MessageHandler"></bean>
	<bean id="defaultHandshakeHandler" class="org.springframework.web.socket.server.support.DefaultHandshakeHandler"></bean>

	<websocket:handlers allowed-origins="*">
		<websocket:mapping handler="messageHandler" path="/test" />
		<websocket:handshake-handler ref="defaultHandshakeHandler"/>
	</websocket:handlers>

	<bean class="org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean">
		<property name="maxTextMessageBufferSize" value="8192" />
		<property name="maxBinaryMessageBufferSize" value="8192" />
		<property name="maxSessionIdleTimeout" value="1000" />
		<property name="asyncSendTimeout" value="1000" />
	</bean>
</beans>

MessageHandler

package io.spring.websocket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

public class MessageHandler extends TextWebSocketHandler {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(MessageHandler.class);

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		LOGGER.info("新的链接:sessionId={}", session.getId());
	}

	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		LOGGER.info("收到消息:sessionId={}, content={}", session.getId(), message.getPayload());
		// 响应给客户端
		session.sendMessage(message);
	}
	
	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		LOGGER.info("链接异常:sessionId={}, message={}", session.getId(), exception.getMessage());
		exception.printStackTrace();
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
		LOGGER.info("链接断开:sessionId={}, status={}", session.getId(), closeStatus);
	}

	@Override
	public boolean supportsPartialMessages() {
		return true;  // 支持分片消息
	}
}

测试

客户端

const webSocket = new WebSocket('ws://localhost/test');
webSocket.onmessage = (e) => {
	console.log(`收到消息:${e.data}`);
}
webSocket.onopen = (e) => {
	console.log('链接打开');
	webSocket.send(JSON.stringify({message: "Hello Websocket"}));
}
webSocket.onerror = (e) => {
	console.log('链接异常');
}
webSocket.onclose = (e) => {
	console.log(`链接断开:code=${e.code}, reason=${e.reason}`);
}

日志

客户端日志

链接打开
 收到消息:{"message":"Hello Websocket"}

服务端日志

[INFO ][qtp1366811528-12][2020-08-28 16:04:59][io.spring.websocket.MessageHandler afterConnectionEstablished] ==> : 新的链接:sessionId=d918bf86-d737-40e8-1345-c548a3116379
[INFO ][qtp1366811528-15][2020-08-28 16:04:59][io.spring.websocket.MessageHandler handleTextMessage] ==> : 收到消息:sessionId=d918bf86-d737-40e8-1345-c548a3116379, content={"message":"Hello Websocket"}