Spring 4 WebSocket app
我尝试从Spring网站运行此示例:教程
除了Spring Boot部分。
Web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>sample</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </init-param> <init-param> <param-name>contextConfigLocation</param-name> <param-value> com.evgeni.websock.WebSocketConfig </param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>sample</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> |
Java配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | @Configuration @ComponentScan(basePackages = {"com.evgeni.controller"}) @EnableWebSocketMessageBroker @EnableWebMvc public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketMessageBrokerConfigurer { public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/hello").withSockJS(); } public void configureClientInboundChannel(ChannelRegistration registration) { // TODO Auto-generated method stub } public void configureClientOutboundChannel(ChannelRegistration registration) { // TODO Auto-generated method stub } public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/app"); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926); registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926); registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926); } } |
控制器:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Controller public class GreetingController { @MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception { Thread.sleep(3000); // simulated delay System.out.println(message.getName()); return new Greeting("Hello," + message.getName() +"!"); } } |
index.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> Hello WebSocket <script src="<c:url value='/js/sockjs-0.3.js'/>"> <script src="<c:url value='/js/stomp.js'/>"> <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 socket = new SockJS("<c:url value='/hello'/>"); stompClient = Stomp.over(socket); stompClient.connect('', '', function(frame) { setConnected(true); console.log('Connected: ' + frame); stompClient.subscribe("<c:url value='/topic/greetings'/>", function(greeting){ showGreeting(JSON.parse(greeting.body).content); }); }); } function disconnect() { stompClient.disconnect(); setConnected(false); console.log("Disconnected"); } function sendName() { var name = document.getElementById('name').value; stompClient.send("<c:url value='/app/hello'/>", {}, 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); } </head> <body> <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!</noscript> <button id="connect" onclick="connect();">Connect</button> <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button> <label>What is your name?</label><input type="text" id="name" /> <button id="sendName" onclick="sendName();">Send</button> <p id="response"></p> </body> </html> |
所有内容都与本教程相同,除了从web.xml和jsp中的2-3 c:url加载的conf来添加项目的根。
当我单击连接然后发送时,在浏览器控制台中,我得到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Opening Web Socket... stomp.js:122 Web Socket Opened... stomp.js:122 >>> CONNECT login: passcode: accept-version:1.1,1.0 heart-beat:10000,10000 stomp.js:122 <<< ERROR message:Illegal header\\c 'login\\c'. A header must be of the form <name>\\c<value> content-length:0 stomp.js:122 >>> SEND destination:/websock/app/hello content-length:14 {"name":"asd"} |
我认为问题在于Sock js的connect函数中
1 | stompClient.connect('', '', function(frame) {... |
我正在传递\\'\\'作为登录名和密码。
编辑:
当我将connect函数更改为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | Opening Web Socket... stomp.js:122 Web Socket Opened... stomp.js:122 >>> CONNECT login:asd passcode:asd accept-version:1.1,1.0 heart-beat:10000,10000 stomp.js:122 <<< CONNECTED heart-beat:0,0 version:1.1 stomp.js:122 connected to server undefined stomp.js:122 Connected: CONNECTED version:1.1 heart-beat:0,0 (index):23 >>> SUBSCRIBE id:sub-0 destination:/websock/topic/greetings stomp.js:122 >>> SEND destination:/websock/app/hello content-length:14 {"name":"asd"} |
但消息未传递到控制器。
该错误是错误的控制器映射。
我有:
1 2 3 | @MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception |
并在jsp中:
1 | stompClient.subscribe("<c:url value='/topic/greetings'/>", function(greeting){... |
和
1 | stompClient.send("<c:url value='/app/hello'/>", {}, JSON.stringify({ 'name': name })); |
正确的是:
1 2 | stompClient.subscribe('/topic/greetings', function(greeting){... stompClient.send('/app/hello', {}, JSON.stringify({ 'name': name })); |
c:url添加了项目的根目录,当我将其删除时,该应用程序正常运行。但是,在此处使用SockJs创建新套接字时需要c:url(根目录):
1 | var socket = new SockJS("<c:url value='/hello'/>"); |
此外,如果您不想将登录名/密码传递给服务器(因为您可能依赖于Spring安全性),则不应使用
1 | stompClient.connect('', '', function(frame) { |
但
1 | stompClient.connect({}, function(frame) { |
在这里看看:https://github.com/spring-guides/gs-messaging-stomp-websocket/issues/10