【0】README
1)本文旨在给出 stomp 连接错误: Whoops! Lost connection to http://localhost:8080/spring13/stomp 的解决方法;you can also refer to this link http://stackoverflow.com/questions/29247956/whoops-lost-connection-to-undefined-connection-lost-just-after-the-connection.
2)解决问题后,文末给出了 STOMP client 的配置 和 springmvc 支持STOMP 的配置 ;
【1】错误 和 解决方法
1)error info
2)solution: 添加 jackson 的jar 包 到spring 项目中 即可。
【2】STOMP client 和 STOMP server(springmvc 配置以支持STOMP)
【2.1】STOMP client(websockjs.jsp)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>
<html lang="zh-CN">
<head>
<title>Hello WebSocket</title>
<script src="<c:url value="/resources/sockjs-1.1.1.js" />"></script>
<script src="<c:url value="/resources/stomp.js" />"></script>
<script type="text/javascript">
var stompClient = null;
function setConnected(connected) {
document.getElementById('connect').disabled = connected;
document.getElementById('disconnect').disabled = !connected;
document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
document.getElementById('response').innerHTML = '';
}
function connect() {
var url = "<c:url value='/stomp' />";
var sock = new SockJS(url); // 创建 SockJS 连接;SockJS 可以接收相对url;
var stomp = Stomp.over(sock); // 创建 STOMP 客户端,显然,它们是一层一层封装的.
var payload = JSON.stringify({ 'name': 'tangrong' });
stomp.connect({}, function(frame) { // 连接 STOMP 端点;
setConnected(true);
console.log('Connected: ' + frame);
stomp.subscribe('/topic/response', function(calResult){
showResult(JSON.parse(calResult.body).content);
});
});
}
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
var name = document.getElementById('name').value;
stompClient.send("/app/stomp", {}, JSON.stringify({ 'name': name }));
}
function showGreeting(message) {
var response = document.getElementById('response');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(message));
response.appendChild(p);
}
</script>
</head>
<body οnlοad="disconnect()">
<noscript>
<h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being enabled. Please enable
Javascript and reload this page!
</h2>
</noscript>
<div>
<div>
<button id="connect" οnclick="connect();">Connect</button>
<button id="disconnect" disabled="disabled" οnclick="disconnect();">Disconnect</button>
</div>
<div id="conversationDiv">
<label>What is your name?</label><input type="text" id="name" />
<button id="sendName" οnclick="sendName();">Send</button>
<p id="response"></p>
</div>
</div>
</body>
</html>
【2.2】STOMP server(springmvc 配置以支持STOMP)
1)WebConfig.java
package com.spring.spittr.web;
import java.io.IOException;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
@Configuration
@ComponentScan(basePackages = { "com.spring.spittr.web" })
@EnableWebMvc
@Import({WebSocketConfig.class}) // 引入 WebSocketConfig 的配置,下面声明了。
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tiles = new TilesConfigurer();
tiles.setDefinitions(new String[] { "/WEB-INF/layout/tiles.xml" });
tiles.setCheckRefresh(true);
return tiles;
}
// config processing for static resources.
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// InternalResourceViewResolver
@Bean
public ViewResolver viewResolver1() {
TilesViewResolver resolver = new TilesViewResolver();
return resolver;
}
@Bean
public ViewResolver viewResolver2() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
return resolver;
}
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
@Bean
public MultipartResolver multipartResolver() throws IOException {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setUploadTempDir(new FileSystemResource("/WEB-INF/tmp/spittr/uploads"));
multipartResolver.setMaxUploadSize(2097152);
multipartResolver.setMaxInMemorySize(0);
return multipartResolver;
}
}
2)WebSocketConfig.java
package com.spring.spittr.web;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue");
config.setApplicationDestinationPrefixes("/app");
// 应用程序以 /app 为前缀,而 代理目的地以 /topic 为前缀.
// js.url = "/spring13/app/hello" -> @MessageMapping("/hello") 注释的方法.
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp").withSockJS();
// 在网页上我们就可以通过这个链接 /server/app/hello 来和服务器的WebSocket连接
}
}
3)GreetingController.java
package com.spring.spittr.web;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import com.spring.pojo.Greeting;
import com.spring.pojo.HelloMessage;
@Controller
public class GreetingController {
@MessageMapping("/stomp")
@SendTo("/topic/response")
public Greeting greeting(HelloMessage message) throws Exception {
System.out.println("receiving " + message);
System.out.println("connecting successfully.");
return new Greeting("Hello, " + message.getName() + "!");
}
}
4)SpitterWebInitializer.java
package com.spring.spittr.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.spring.spittr.web.WebConfig;
import com.spring.spittr.web.WebSocketConfig;
public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/", "*.js", "*.css", "*.jpg", "*.png", "/app/*", "*.map" };
} // 特别注意,这里配置不拦截的url。特别是 "/app/*"
}