2016-04-06 4 views
1

Ich habe eine Aktion, in der ich drei parallele HTTP-Aufrufe (zu anderen Diensten), dann füge ich den Inhalt der Antworten in ein Dokument und schließlich sende ich es zurück zum Client. Dies ist ein funktionstüchtiges Beispiel des Codes:Play Framework parallele WSClient Aufrufe Fehler Management

@Inject 
WSClient wsc; 

public CompletionStage<Result> getUrlData() throws Exception { 

    List<CompletionStage<WSResponse>> stages = new ArrayList<>(); 
    stages.add(wsc.url("http://jsonplaceholder.typicode.com/posts/1").get()); 
    stages.add(wsc.url("http://jsonplaceholder.typicode.com/posts/2").get()); 
    stages.add(wsc.url("http://jsonplaceholder.typicode.com/posts/3").get()); 

    return Futures 
      .sequence(stages) 
      .thenApply(responses -> { 
       StringBuilder builder = new StringBuilder("["); 
       responses.stream().forEach(response -> builder.append(response.getBody()).append(",")); 
       builder.deleteCharAt(builder.length()-1).append("]"); 
       return ok(builder.toString()); 
      }) 
      .exceptionally(ex -> ok("{\"error\": \"An error has occurred\"}")); 

Wenn einer der Dienste nicht verfügbar ist (dieses Verhalten simulieren kann den Domain-Namen einer der URLs auf einen nicht vorhandenen modifizierenden) kehrte die Seite enthält nur die Nachricht enthalten in der Ausnahme() Teil, während ich den Inhalt der richtigen Anrufe plus die Fehlermeldung der nicht erfolgreichem Anruf zurückgeben muss. Irgendein Hinweis darauf, wie es geht?

Ich benutze Play 2.5.1.

Danke, Andrea

Antwort

1

Im Grunde wollen Sie nur die .exceptionally(..) individuell für jeden Anruf zu handhaben. So etwas sollte funktionieren:

  1. eine Funktion erstellen, die eine CompletionStage für eine einzelne URL zurückgibt, Ihre Fehler enthält Handhabung (JSON des Fehlers Rückkehr)
  2. konvertieren, dass auf eine Liste von Vervollständigungsstufen Futures.sequence passieren

Als Nebenwirkung, können Sie die JSON-Manipulation ein bisschen schöner machen, indem die Objekte programmatisch den Aufbau mit Jackson ObjectMapper.createObjectNode() und ObjectMapper.createArrayNode():

private static final ObjectMapper mapper = new ObjectMapper(); 

private CompletionStage<JsonNode> getDataFromUrl(String url) { 
    return wsc.url(url) 
      .get() 
      .thenApply(WSResponse::asJson) 
      .exceptionally(ex -> { 
       ObjectNode error = mapper.createObjectNode(); 
       error.put("error", ex.getMessage()); 
       return error; 
      }); 
} 

public CompletionStage<Result> getUrlData() throws Exception { 

    List<String> urls = new ArrayList<>(); 
    urls.add("http://jsonplaceholder.typicode.com/posts/1"); 
    urls.add("http://jsonplaceholder.typicode.com/posts/2"); 
    urls.add("http://jsonplaceholder.typicode.com/posts/3"); 

    // Convert to a list of promises 
    List<CompletionStage<JsonNode>> stages = urls 
      .stream() 
      .map(this::getDataFromUrl) 
      .collect(Collectors.toList()); 

    return Futures 
      .sequence(stages) 
      .thenApply(responses -> { 
       ArrayNode arrayNode = mapper.createArrayNode(); 
       responses.stream().forEach(arrayNode::add); 
       return ok(arrayNode); 
      }); 
} 
+0

eigentlich ist die JSON-Manipulation, die ich mache, komplexer als das Beispiel, das ich hier gepostet habe, aber der ObjectMapper ist ein sehr guter Hinweis. Vielen Dank! –