最近玩Spring Websocket 是碰到404问题,烦死了。下面是服务端配置
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<!-- data-source-production.xml, -->
classpath:data-source.xml,
classpath:spring-action-servlet.xml,
<!-- hr-config.xml, -->
classpath:spring-quartz.xml,
<!-- classpath:config.xml, -->
classpath:app-context.xml,
classpath:config/dao-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>com.lh.hrss.sdyw.web.AppContextListener</listener-class>
</listener>
<filter>
<filter-name>characterEncodingFilter</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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>spring-action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring-action-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>spring-action</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<!--Axis2 config start-->
<!-- <servlet>
<servlet-name>AxisServlet</servlet-name>
<servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping> -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>/index.do</welcome-file>
</welcome-file-list>
<error-page>
<error-code>500</error-code>
<location>/show500.do</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/show404.do</location>
</error-page>
</web-app>
spring.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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:p="http://www.springframework.org/schema/p"
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.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.2.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd">
<context:component-scan base-package="com.lh.hrss.sdyw.web" />
<context:component-scan base-package="com.lh.sdyw.neusoft.web" />
<context:component-scan base-package="com.lh.hrss.sdyw.service" />
<context:component-scan base-package="com.lihuan.sdyw.service" />
<context:component-scan base-package="ids" />
<!-- <bean id="springContextUtil" class="com.lh.hrss.sdyw.SpringContextUtil"
lazy-init="false"></bean> -->
<bean id="tsUtil" class="com.lh.hrss.sdyw.util.TsUtil"></bean>
<bean id="velocityConfig"
class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/vm" />
<property name="configLocation">
<value>WEB-INF/config/velocity_config.properties</value>
</property>
<property name="velocityProperties">
<props>
<prop key="velocimacro.library">/common/velocity_common.vm</prop>
</props>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="suffix">
<value>.vm</value>
</property>
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="exposeSessionAttributes" value="true" />
<property name="exposeRequestAttributes" value="false" />
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- <property name="maxUploadSize" value="5000000" /> -->
</bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.lh.hrss.sdyw.web.interceptor.CommonInterceptor"></bean>
<bean class="com.lh.hrss.sdyw.web.interceptor.UserLoginProtectInterceptor"></bean>
<bean class="com.lh.hrss.sdyw.web.interceptor.BizLoginProtectInterceptor"></bean>
<bean class="com.lh.hrss.sdyw.web.interceptor.ApiInterceptor"></bean>
<!-- <bean class="com.lh.hrss.sdyw.web.interceptor.SaLoginProtectInterceptor"></bean> -->
</list>
</property>
<property name="useDefaultSuffixPattern" value="true" />
</bean>
<bean id="exceptionResolver" class="com.lihuan.common.UserExceptionHandler" />
<!-- 隐式地向 Spring 容器注册 AutowiredAnnotationBeanPostProcessor、 CommonAnnotationBeanPostProcessor、
PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor
这 4 个 BeanPostProcessor。 在配置文件中使用 context 命名空间之前, 必须在 <beans> 元素中声明 context
命名空间。 -->
<context:annotation-config />
<!-- <context:component-scan/> 配置项不但启用了对类包进行扫描 以实施注释驱动 Bean 定义的功能, 同时还启用了注释驱动自动注入的功能
(即还隐式地在内部注册了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor) -->
<!-- 缓存注解驱动 -->
<cache:annotation-driven />
<!-- <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="false"
mode="proxy"/> -->
<!-- cacheManager工厂类 -->
<bean id="cacheManagerFactory"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
<property name="shared" value="true" />
</bean>
<!-- 声明cacheManager -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="cacheManagerFactory" />
</bean>
<bean id="simpleCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManagerFactory" />
<!-- 使用缓存 关联ehcache.xml中的缓存配置 -->
<property name="cacheName" value="myCache" />
</bean>
<!-- 声明websocket -->
<websocket:handlers allowed-origins="*">
<websocket:mapping path="/webSocketServer" handler="systemWebSocketHandler"/>
<websocket:sockjs/>
</websocket:handlers>
<bean id="systemWebSocketHandler" class="com.lh.hrss.sdyw.web.test.websocket.SystemWebSocketHandler"/>
<bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
</beans>
其中红色部分为websocket配置。
服务器类SystemWebSocketHandler代码
package com.lh.hrss.sdyw.web.test.websocket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
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;
/**
* @author Administrator
*
*/
public class SystemWebSocketHandler implements WebSocketHandler {
private Logger log = Logger.getLogger(SystemWebSocketHandler.class);
private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>();;
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("ConnectionEstablished");
log.debug("ConnectionEstablished");
users.add(session);
session.sendMessage(new TextMessage("connect"));
session.sendMessage(new TextMessage("new_msg"));
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.out.println("handleMessage" + message.toString());
log.debug("handleMessage" + message.toString());
// sendMessageToUsers();
session.sendMessage(new TextMessage(new Date() + ""));
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if (session.isOpen()) {
session.close();
}
users.remove(session);
log.debug("handleTransportError" + exception.getMessage());
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
users.remove(session);
log.debug("afterConnectionClosed" + closeStatus.getReason());
}
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 给所有在线用户发送消息
*
* @param message
*/
public void sendMessageToUsers(TextMessage message) {
for (WebSocketSession user : users) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
我在客户端用socketJS进行访问连接老是出现404错误,socketJS代码我就不贴了,很简单,网上随便搜。
socketJS关键代码(还是贴吧):
function connect() {
if (!url) {
alert('Select whether to use W3C WebSocket or SockJS');
return;
}
//ws = new WebSocket('ws://192.168.10.107:8080/mspjapi/webSocketServer');/* (url.indexOf('sockjs') != -1) ?
//new SockJS(url, undefined, {protocols_whitelist: transports}) : */
ws = new SockJS('http://localhost:8080/vrobot_portal/webSocketServer');
// ws = new WebSocket('ws://localhost:8080/vrobot_portal/webSocketServer');
//console.log("http://192.168.10.107:8080/mspjapi/webSocketServer/sockjs");
ws.onopen = function () {
setConnected(true);
log('Info: connection opened.');
};
ws.onmessage = function (event) {
log('Received: ' + event.data);
};
ws.onclose = function (event) {
setConnected(false);
log('Info: connection closed.');
log(event);
};
}
function disconnect() {
if (ws != null) {
ws.close();
ws = null;
}
setConnected(false);
}
function echo() {
if (ws != null) {
var message = document.getElementById('message').value;
log('Sent: ' + message);
ws.send(message);
} else {
alert('connection not established, please connect.');
}
}
function updateUrl(urlPath) {
if (urlPath.indexOf('sockjs') != -1) {
url = urlPath;
document.getElementById('sockJsTransportSelect').style.visibility = 'visible';
}
else {
if (window.location.protocol == 'http:') {
url = 'ws://' + window.location.host + urlPath;
} else {
url = 'wss://' + window.location.host + urlPath;
}
document.getElementById('sockJsTransportSelect').style.visibility = 'hidden';
}
}
function updateTransport(transport) {
transports = (transport == 'all') ? [] : [transport];
}
function log(message) {
var console = document.getElementById('console');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(message));
console.appendChild(p);
while (console.childNodes.length > 25) {
console.removeChild(console.firstChild);
}
console.scrollTop = console.scrollHeight;
}
解决方案如下:在web.xml添加下列代码
<servlet-mapping>
<servlet-name>spring-action</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
原因就是:spring之前对
url-pattern配置的*.do和*.html才认,才会通过dispatch进行分发,而websocket注册的地址是
webSocketServer,没有后缀的,所以无法识别匹配出现404错误。