2013-12-23 11 views
6

Ich habe versucht, dieses Beispiel aus der Feder Website auszuführen: tutorial mit Ausnahme des Frühlings-Boot-Teil.Spring 4 WebSocket App

Web.xml

<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 Config:

@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); 
     } 

} 

Controller:

@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

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<!DOCTYPE html> 
<html> 
<head> 
    <title>Hello WebSocket</title> 
    <script src="<c:url value='/js/sockjs-0.3.js'/>"></script> 
    <script src="<c:url value='/js/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 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); 
     } 
    </script> 
</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!</h2></noscript> 
<div> 
    <div> 
     <button id="connect" onclick="connect();">Connect</button> 
     <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button> 
    </div> 
    <div id="conversationDiv"> 
     <label>What is your name?</label><input type="text" id="name" /> 
     <button id="sendName" onclick="sendName();">Send</button> 
     <p id="response"></p> 
    </div> 
</div> 
</body> 
</html> 

Everithing ist das gleiche wie das Tutorial, nur dass das conf i aus der Datei web.xml und 2-3 c: url in das jsp geladen wurde, um das root des Projekts hinzuzufügen.

Wenn ich die connect klicken und dann senden, in der Browser-Konsole erhalte ich:

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"} 

Ich denke, dass th problm js in der Verbindungsfunktion der Socke ist

stompClient.connect('', '', function(frame) {... 

Ich bin Passing '' für Login und Passwort.

Edit: Wenn ich die Verbindungsfunktion zu stompClient.connect('random', 'random', die Antwort in der Konsole ändern ist:

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"} 

aber die Nachricht nicht an den Controller geliefert.

+0

sind Sie ausführbare jar mit s und eingebetteter Kater, wie in diesem Artikel? oder etwas anderes? – eis

+0

Ich verwende Tomcat 7.0.47 von STS. Wie kann ich checken, wenn es Websocket Unterstützung hat? –

+0

hat nur meine Frage geändert, tut mir leid :) So sind Sie es eingebettet oder Bereitstellung auf externe Instanz? – eis

Antwort

7

Der Fehler war falsch Controller-Mapping. ich habe:

@MessageMapping("/hello") 
    @SendTo("/topic/greetings") 
    public Greeting greeting(HelloMessage message) throws Exception 

und in der jsp:

stompClient.subscribe("<c:url value='/topic/greetings'/>", function(greeting){... 

und

stompClient.send("<c:url value='/app/hello'/>", {}, JSON.stringify({ 'name': name })); 

die richtigen sind:

stompClient.subscribe('/topic/greetings', function(greeting){... 
stompClient.send('/app/hello', {}, JSON.stringify({ 'name': name })); 

Die c: url fügt die Wurzel von dem Projekt, als ich es entfernte die a pp arbeitete. Allerdings c: url (die Wurzel) wird rquired, wenn neue Buchse mit SockJs schaffen hier:

var socket = new SockJS("<c:url value='/hello'/>"); 
+0

Ich hatte das gleiche Problem aufgrund der URL-Zuordnung. Der Pfad für den Anwendungskontext wird nur benötigt, wenn Sie eine neue SockJS-Instanz erstellen. Verwenden Sie anschließend zum Abonnieren einfach die URL-Zuordnung. Implizit wird es dem Kontextpfad zugeordnet. @Evgeni Danke für die tolle Antwort. – LahiruBandara

1

Auch wenn Sie nicht Login/Passwort an den Server übergeben werden soll (wie Sie auf Frühling Sicherheit verlassen könnte), dann Sie shouldn‘ t Verwendung

stompClient.connect('', '', function(frame) { 

sondern

stompClient.connect({}, function(frame) { 

Werfen Sie einen Blick hier: https://github.com/spring-guides/gs-messaging-stomp-websocket/issues/10

+0

Diese Methode funktioniert aus irgendeinem Grund nicht für mich. Es versucht, das leere Objekt als "login: [Object object]" - Header zu übergeben und der Passcode ist meine Funktion. – InfernalRapture

Verwandte Themen