2013-04-24 11 views
12

Mam usługę odpoczynku, która wysyła błąd 404, gdy zasoby nie zostaną znalezione. Tutaj źródłem mojego kontrolera i wyjątek który wysłać HTTP 404.Spring MVC - Wyjątek uruchamiania RestTemplate, gdy wystąpi http 404

@Controller 
@RequestMapping("/site") 
public class SiteController 
{ 

    @Autowired 
    private IStoreManager storeManager; 

    @RequestMapping(value = "/stores/{pkStore}", method = RequestMethod.GET, produces = "application/json") 
    @ResponseBody 
    public StoreDto getStoreByPk(@PathVariable long pkStore) {  
     Store s = storeManager.getStore(pkStore); 
     if (null == s) { 
      throw new ResourceNotFoundException("no store with pkStore : " + pkStore); 
     } 
     return StoreDto.entityToDto(s);  

    } 
} 

@ResponseStatus(value = HttpStatus.NOT_FOUND) 
public class ResourceNotFoundException extends RuntimeException 
{  
    private static final long serialVersionUID = -6252766749487342137L;  
    public ResourceNotFoundException(String message) { 
     super(message); 
    }  
} 

Kiedy próbuję to nazwać z RestTemplate z tym kodem:

ResponseEntity<StoreDto> r = restTemplate.getForEntity(url, StoreDto.class, m); 
System.out.println(r.getStatusCode()); 
System.out.println(r.getBody()); 

otrzymuję ten wyjątek:

org.springframework.web.client.RestTemplate handleResponseError 
ATTENTION: GET request for "http://........./stores/99" resulted in 404 (Introuvable); invoking error handler 
org.springframework.web.client.HttpClientErrorException: 404 Introuvable 

Myślałem, że mogę zbadać mój obiekt responseEntity i zrobić kilka rzeczy za pomocą statusu. Ale wyjątek to uruchomienie, a moja aplikacja znika.

Czy istnieje specjalna konfiguracja dla restTemplate, aby nie wysyłać wyjątku, ale wypełnić moją ResponseEntity.

Bardzo dziękuję za pomoc.

-

Loïc

+0

są w stanie uzyskać dostęp do usługi odpoczynek przez przeglądarkę? czy to też rzuca 404? – Akshay

+0

Czy kiedykolwiek znalazłeś odpowiedź na to pytanie? – leojh

Odpowiedz

21

O ile mi wiadomo, nie można uzyskać rzeczywiste ResponseEntity, ale kod statusu i ciało (jeśli w ogóle) można otrzymać z wyjątkiem:

try { 
     ResponseEntity<StoreDto> r = restTemplate.getForEntity(url, StoreDto.class, m); 
    } 
    catch (final HttpClientErrorException e) { 
     System.out.println(e.getStatusCode()); 
     System.out.println(e.getResponseBodyAsString()); 
    } 
11

RESTTemplate jest dość niewystarczające w tym obszarze IMO. Jest to dobry blogu tutaj o tym, jak można ewentualnie wyodrębnić treść odpowiedzi, kiedy już otrzymał błąd:

http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs-resttemplate

dzień dzisiejszy nie jest wybitnym prośba JIRA że szablon daje możliwość, aby wyodrębnić ciało odpowiedź:

https://jira.spring.io/browse/SPR-10961

kłopot z odpowiedzią kucki Niedźwiedzia jest to, że trzeba by przesłuchać kod statusu wewnątrz bloku catch np jeśli chce się tylko do czynienia z 404 na

Oto, jak sobie z tym poradziłem podczas mojego ostatniego projektu. Mogą istnieć lepsze sposoby, a moje rozwiązanie w ogóle nie wyodrębnia ResponseBody.

public class ClientErrorHandler implements ResponseErrorHandler 
{ 
    @Override 
    public void handleError(ClientHttpResponse response) throws IOException 
    { 
     if (response.getStatusCode() == HttpStatus.NOT_FOUND) 
     { 
      throw new ResourceNotFoundException(); 
     } 

     // handle other possibilities, then use the catch all... 

     throw new UnexpectedHttpException(response.getStatusCode()); 
    } 

    @Override 
    public boolean hasError(ClientHttpResponse response) throws IOException 
    { 
     if ((response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR) 
     || (response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR)) 
     { 
      return true; 
     } 
     return false; 
    } 

}

ResourceNotFoundException i UnexpectedHttpException są moje własne niesprawdzonych wyjątki.

podczas tworzenia szablonu rekreacyjne:

RestTemplate template = new RestTemplate(); 
    template.setErrorHandler(new ClientErrorHandler()); 

Teraz otrzymujemy nieco schludniej skonstruować przy składaniu wniosku:

try 
    { 
     HttpEntity response = template.exchange("http://localhost:8080/mywebapp/customer/100029", 
             HttpMethod.GET, requestEntity, String.class); 
     System.out.println(response.getBody()); 
    } 
    catch (ResourceNotFoundException e) 
    { 
     System.out.println("Customer not found"); 
    } 
+0

Naprawdę nie potrzebujesz try ... catch part po ustawieniu handler'a. – eosimosu

+0

Co wypróbować ... część partii po ustawieniu programu obsługi? Wyjątek ResourceNotFoundException? Jest to mój wyjątek, nie potrzebuję go, ale chcę go. –

+0

To prawda, sens – eosimosu

0

niedawno USECASE do tego.Moje rozwiązanie:

public class MyErrorHandler implements ResponseErrorHandler { 

@Override 
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException { 
    return hasError(clientHttpResponse.getStatusCode()); 
} 

@Override 
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException { 
    HttpStatus statusCode = clientHttpResponse.getStatusCode(); 
    MediaType contentType = clientHttpResponse 
     .getHeaders() 
     .getContentType(); 
    Charset charset = contentType != null ? contentType.getCharset() : null; 
    byte[] body = FileCopyUtils.copyToByteArray(clientHttpResponse.getBody()); 

    switch (statusCode.series()) { 
     case CLIENT_ERROR: 
      throw new HttpClientErrorException(statusCode, clientHttpResponse.getStatusText(), body, charset); 
     case SERVER_ERROR: 
      throw new HttpServerErrorException(statusCode, clientHttpResponse.getStatusText(), body, charset); 
     default: 
      throw new RestClientException("Unknown status code [" + statusCode + "]"); 
    } 

} 

private boolean hasError(HttpStatus statusCode) { 
    return (statusCode.series() == HttpStatus.Series.CLIENT_ERROR || 
     statusCode.series() == HttpStatus.Series.SERVER_ERROR); 
} 
0

Można tworzyć własne RestTemplate opakowanie, które nie generują wyjątki, ale zwraca odpowiedź z otrzymanym kodem statusu. (Można również zwrócić się do organizmu, ale to by przestać być typu bezpieczny, więc w kod poniżej korpusu pozostaje po prostu null.)

/** 
* A Rest Template that doesn't throw exceptions if a method returns something other than 2xx 
*/ 
public class GracefulRestTemplate extends RestTemplate { 
    private final RestTemplate restTemplate; 

    public GracefulRestTemplate(RestTemplate restTemplate) { 
     super(restTemplate.getMessageConverters()); 
     this.restTemplate = restTemplate; 
    } 

    @Override 
    public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException { 
     return withExceptionHandling(() -> restTemplate.getForEntity(url, responseType)); 
    } 

    @Override 
    public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException { 
     return withExceptionHandling(() -> restTemplate.postForEntity(url, request, responseType)); 
    } 

    private <T> ResponseEntity<T> withExceptionHandling(Supplier<ResponseEntity<T>> action) { 
     try { 
      return action.get(); 
     } catch (HttpClientErrorException ex) { 
      return new ResponseEntity<>(ex.getStatusCode()); 
     } 
    } 
} 
Powiązane problemy