2015-12-21 8 views
5

का उपयोग कर आने वाली एसएसई घटनाओं की सदस्यता कैसे ले सकता हूं मैंने एक वसंत RestController लिखा है जो SseEmitter (सर्वर से भेजे गए ईवेंट के लिए) देता है, और प्रत्येक ईवेंट के लिए हैटओएएस लिंक जोड़ता है। यहाँ इस नियंत्रक का एक सरलीकृत लेकिन काम कर उदाहरण है:मैं वसंत

package hello; 

import java.util.concurrent.atomic.AtomicInteger; 
import org.springframework.hateoas.ResourceSupport; 
import com.fasterxml.jackson.annotation.JsonCreator; 
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 
import com.fasterxml.jackson.annotation.JsonProperty; 

@JsonIgnoreProperties(ignoreUnknown = true) 
public class Greeting extends ResourceSupport { 

    private final String content; 
    private final static AtomicInteger idProvider = new AtomicInteger(); 
    private int greetingId; 
    private Status status; 

    enum Status { 
     ENQUEUED, 
     PROCESSING, 
     COMPLETE; 
    } 

    @JsonCreator 
    public Greeting(@JsonProperty("content") final String content) { 
     this.greetingId = idProvider.addAndGet(1); 
     this.status = Status.ENQUEUED; 
     this.content = content; 
    } 

    public Status getStatus() { 
     return this.status; 
    } 

    protected void setStatus(final Status status) { 
     this.status = status; 
    } 

    public int getGreetingId() { 
     return this.greetingId; 
    } 

    public String getContent() { 
     return this.content; 
    } 

    @Override 
    public String toString() { 
     return "Greeting{id='" + this.greetingId + "', status='" + this.status + "' content='" + this.content + "', " + super.toString() + "}"; 
    } 

    public void incrementStatus() { 
     switch (this.status) { 
      case ENQUEUED: 
       this.status = Status.PROCESSING; 
       break; 
      case PROCESSING: 
       this.status = Status.COMPLETE; 
       break; 
      default: 
       break; 
     } 
    } 
} 

इस कोड को पूरी तरह से काम करता है:

package hello; 

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 
import hello.Greeting.Status; 
import java.io.IOException; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestParam; 
import org.springframework.web.bind.annotation.RestController; 
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; 
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 

@RestController 
public class GreetingController { 

    private static final Logger log = LoggerFactory.getLogger(GreetingController.class); 

    private static final String template = "Hello, %s!"; 

    class GreetingRequestHandler implements Runnable { 

     private ResponseBodyEmitter emitter; 
     private Greeting greeting; 

     public GreetingRequestHandler(final ResponseBodyEmitter emitter, final Greeting greeting) { 
      this.emitter = emitter; 
      this.greeting = greeting; 
     } 

     @Override 
     public void run() { 
      try { 
       log.info(this.greeting.toString()); 
       this.emitter.send(this.greeting); 
       Thread.sleep(5000); 
       if (Status.COMPLETE.equals(this.greeting.getStatus())) { 
        this.emitter.complete(); 
       } else { 
        this.greeting.incrementStatus(); 
        new Thread(new GreetingRequestHandler(this.emitter, this.greeting)).start(); 
       } 
      } catch (IOException | InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    @RequestMapping(path = "/greeting") 
    public SseEmitter greeting(@RequestParam(value = "name", defaultValue = "World") final String name) { 
     SseEmitter emitter = new SseEmitter(); 
     Greeting greeting = new Greeting(String.format(template, name)); 
     greeting.add(linkTo(methodOn(GreetingController.class).greeting(name)).withSelfRel()); 
     new Thread(new GreetingRequestHandler(emitter, greeting)).start(); 
     log.info("returning emitter"); 
     return emitter; 
    } 
} 

Greeting वर्ग निम्नलिखित है। यदि मैं एक वेब ब्राउज़र का उपयोग कर आरईएसटी सेवा तक पहुंचने का प्रयास करता हूं, तो मुझे सही सामग्री और लिंक के साथ आने वाली घटनाएं दिखाई देती हैं।

परिणाम (पिछले एक 5 सेकंड के बाद प्रदर्शित होने वाले सभी घटना) की तरह दिखता है:

data:{"content":"Hello, Kraal!","greetingId":8,"status":"ENQUEUED","_links":{"self":{"href":"http://localhost:8080/greeting?name=Kraal"}}} 
data:{"content":"Hello, Kraal!","greetingId":8,"status":"PROCESSING","_links":{"self":{"href":"http://localhost:8080/greeting?name=Kraal"}}} 
data:{"content":"Hello, Kraal!","greetingId":8,"status":"COMPLETE","_links":{"self":{"href":"http://localhost:8080/greeting?name=Kraal"}}} 

अब मैं इस बाकी सेवा को कॉल और एक अन्य स्प्रिंग आवेदन से इन घटनाओं पढ़ने की जरूरत है ... लेकिन मुझे कोई राशि वसंत का उपयोग कर क्लाइंट कोड लिखने के लिए सुराग। यह RestTemplate तुल्यकालिक ग्राहक साइड HTTP पहुँच के लिए डिज़ाइन किया गया है के रूप में काम नहीं करता है ...

ObjectMapper mapper = new ObjectMapper(); 
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 
    mapper.registerModule(new Jackson2HalModule()); 

    // required for HATEOAS 
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
    converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json")); 
    converter.setObjectMapper(mapper); 

    // required in order to be able to read serialized objects 
    MappingJackson2HttpMessageConverter converter2 = new MappingJackson2HttpMessageConverter(); 
    converter2.setSupportedMediaTypes(MediaType.parseMediaTypes("application/octet-stream")); 
    converter2.setObjectMapper(mapper); 

    // required to understand SSE events 
    MappingJackson2HttpMessageConverter converter3 = new MappingJackson2HttpMessageConverter(); 
    converter3.setSupportedMediaTypes(MediaType.parseMediaTypes("text/event-stream")); 

    List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>(); 
    converters.add(converter); 
    converters.add(converter2); 
    converters.add(converter3); 

    // probably wrong template 
    RestTemplate restTemplate = new RestTemplate(); 
    restTemplate = new RestTemplate(converters); 
    // this does not work as I receive events and no a single object 
    Greeting greeting = restTemplate.getForObject("http://localhost:8080/greeting/?name=Kraal", Greeting.class); 
    log.info(greeting.toString()); 

त्रुटि संदेश मैं मिलता है:

Caused by: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'data': was expecting ('true', 'false' or 'null') 

दरअसल प्रत्येक घटना एक SSE घटना है और "डेटा के साथ शुरू होता : "...

तो सवाल हैं:

  • जैक्सन के साथ एसएसई मैप करने में सक्षम होने के लिए ऑब्जेक्टमैपर मॉड्यूल को क्या रजिस्टर करना चाहिए?
  • मैं वसंत का उपयोग कर आने वाली एसएसई घटनाओं (पर्यवेक्षक पैटर्न) की सदस्यता कैसे ले सकता हूं?

अग्रिम धन्यवाद।

साइड नोट: जैसा कि मैं स्प्रिंग का उपयोग करके इसे करने में संघर्ष कर रहा हूं, मैंने जर्सी एसएसई समर्थन का उपयोग करके इसे करने की कोशिश की। जर्सी का उपयोग करते हुए मैं घटनाओं प्राप्त की उम्मीद के रूप में है, लेकिन फिर मैं उन्हें एक Greeting वर्ग में ढाला नहीं कर सकते हैं (एक ही कारण के लिए ऊपर के रूप में मुझे लगता है कि जो है कि मैं सही कनवर्टर मॉड्यूल नहीं है।):

Client client = ClientBuilder.newBuilder().register(converter).register(SseFeature.class).build(); 
WebTarget target = client.target("http://localhost:8080/greeting/?name=Kraal"); 
EventInput eventInput = target.request().get(EventInput.class); 
while (!eventInput.isClosed()) { 
    final InboundEvent inboundEvent = eventInput.read(); 
    if (inboundEvent == null) { 
     // connection has been closed 
     break; 
    } 
    // this works fine and prints out events as they are incoming 
    System.out.println(inboundEvent.readData(String.class)); 
    // but this doesn't as no proper way to deserialize the 
    // class with HATEOAS links can be found 
    // Greeting greeting = inboundEvent.readData(Greeting.class); 
    // System.out.println(greeting.toString()); 
} 
+0

सर्वर से भेजे गए इवेंट ब्राउज़र संचार करने के लिए सर्वर के लिए डिजाइन किए गए थे। आपकी स्थिति सर्वर संचार के लिए सर्वर की अधिक मांग करती है। मेरे आवेदन में, मैंने रेडिस द्वारा प्रदान की गई एक पब उप संदेश कतार का उपयोग किया (लेकिन आप किसी अन्य का उपयोग कर सकते हैं)। विचार यह है कि किसी भी वसंत अनुप्रयोग कतार में प्रकाशित कर सकते हैं और इसके लिए सदस्यता लेने वाले सभी एप्लिकेशन संदेश प्राप्त करेंगे। देखें कि यह https://spring.io/guides/gs/messaging-redis/ –

उत्तर

0

documentation

प्रति के रूप में आप उपयोग कर सकते हैं मेरे विचार में inboundEvent.readData(Class<T> type)

+0

दस्तावेज़ लिंक टूटा हुआ है – xetra11

+0

कृपया इस https://jersey.github.io/apidocs/2.26/jersey/org/glassfish/ का उपयोग करें जर्सी/मीडिया/SSE/InboundEvent.html –