2015-09-02 7 views
8

Mam następujący obrazek Pobierz metodę w moim kontroler (wiosna 4.1):HttpMediaTypeNotAcceptableException: Nie można odnaleźć dopuszczalny reprezentację w exceptionhandler

@RequestMapping(value = "/get/image/{id}/{fileName}", method=RequestMethod.GET) 
public @ResponseBody byte[] showImageOnId(@PathVariable("id") String id, @PathVariable("fileName") String fileName) { 
    setContentType(fileName); //sets contenttype based on extention of file 
    return getImage(id, fileName); 
} 

Poniższy ControllerAdvice metoda powinna obsługiwać non-istniejący plik i zwróci błąd json odpowiedź: działa

@ExceptionHandler(ResourceNotFoundException.class) 
@ResponseStatus(HttpStatus.NOT_FOUND) 
public @ResponseBody Map<String, String> handleResourceNotFoundException(ResourceNotFoundException e) { 
    Map<String, String> errorMap = new HashMap<String, String>(); 
    errorMap.put("error", e.getMessage()); 
    return errorMap; 
} 

Moje testy JUnit bezbłędne

(EDIT to ze względu na przedłużeniu .bla: to działa również na appserver):

@Test 
public void testResourceNotFound() throws Exception { 
    String fileName = "bla.bla"; 
     mvc.perform(MockMvcRequestBuilders.get("/get/image/bla/" + fileName) 
      .with(httpBasic("test", "test"))) 
      .andDo(print()) 
      .andExpect(jsonPath("$error").value(Matchers.startsWith("Resource not found"))) 
      .andExpect(status().is(404)); 
} 

i daje następujący wynik:

MockHttpServletResponse: 
      Status = 404 
    Error message = null 
     Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY], Content-Type=[application/json]} 
    Content type = application/json 
      Body = {"error":"Resource not found: bla/bla.bla"} 
    Forwarded URL = null 
    Redirected URL = null 
     Cookies = [] 

Jednak na moim appserver i pojawia się następujący komunikat o błędzie podczas próby donwload non istniejący obraz:

(EDIT to ze względu na przedłużeniu .jpg: to się nie powiedzie się również na teście JUnit z rozszerzeniem .jpg):

ERROR org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: public java.util.Map<java.lang.String, java.lang.String> nl.krocket.ocr.web.controller.ExceptionController.handleResourceNotFoundException(nl.krocket.ocr.web.backing.ResourceNotFoundException) org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

mam skonfigurowane messageconverters w moim mvc konfiguracji następująco:

@Override 
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
    converters.add(mappingJackson2HttpMessageConverter()); 
    converters.add(byteArrayHttpMessageConverter()); 
} 

@Bean 
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { 
    ObjectMapper objectMapper = new ObjectMapper(); 
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 
    //objectMapper.registerModule(new JSR310Module()); 
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
    converter.setObjectMapper(objectMapper); 
    converter.setSupportedMediaTypes(getJsonMediaTypes()); 
    return converter; 
} 

@Bean 
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() { 
    ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter(); 
    arrayHttpMessageConverter.setSupportedMediaTypes(getImageMediaTypes()); 
    return arrayHttpMessageConverter; 
} 

Czego mi brakuje? I dlaczego test JUnit działa?

+1

Zaznacz „Akceptuj” nagłówku wniosek ("rzeczywisty", do aplikatora). Czy akceptuje zarówno image/*, jak i application/json? Jeśli akceptuje tylko obraz/*, Spring nie może wygenerować komunikatu JSON, ponieważ nie byłby zgodny z tym, co akceptuje żądanie. –

+0

Mam następujące: Zaakceptuj: text/html, application/xhtml + xml, application/xml; q = 0.9, image/webp, */*; q = 0.8 –

+0

Jak mogę się zmienić? Dodaj do messageconverters ('setSupportedMediaTypes')? –

Odpowiedz

17

Musisz zdecydować, w jaki sposób typ nośnika odpowiedzi powinien zostać określony wiosną. Że można to zrobić na kilka sposobów:

  • ścieżki rozszerzenie (np /image.jpg.)
  • parametru URL (na przykład format = jpg.?)
  • nagłówek HTTP Accept (Akceptuj np. Image/jpg)

domyślnie Wiosna patrzy na przedłużenie zamiast nagłówka Accept. To zachowanie można zmienić, jeśli zaimplementujesz klasę @Configuration, która rozszerza WebMvcConfigurerAdapter. Tam możesz zastąpić configureContentNegotiation(ContentNegotiationConfigurer configurer) i skonfigurować konfiguratora do swoich potrzeb, np. wywołując

ContentNegotiationConfigurer#favorParameter 
ContentNegotiationConfigurer#favorPathExtension 

Jeśli ustawisz zarówno false, następnie Wiosna będzie wyglądać w nagłówku Accept. Ponieważ twój klient może powiedzieć Accept: image/*,application/json i obsługiwać oba, Spring powinien być w stanie zwrócić obraz lub błąd JSON.

Aby uzyskać więcej informacji i przykładów, zobacz artykuł this Spring tutorial dotyczący negocjacji treści.

+1

dzięki za tę doskonałą odpowiedź! oprócz tego usunąłem ustawienie obsługiwanych mediatypów w programach do przesyłania komunikatów i ustawienie typu zawartości w metodach kontrolera, więc wszystkie są negocjowane wiosną. jeszcze jedno: aby wyłączyć funkcję pathvariable-truncation użyj 'matcher.setUseSuffixPatternMatch (false)' w webconfig. –

+0

Twoja odpowiedź była na temat. Zmieniono na 1.9.2 i działa jak czar – MagGGG

1

Zwróć uwagę na nagłówek HTTP Accept. Na przykład, jeśli kontroler produkuje „application/octet-stream” (w odpowiedzi), Twój Zebrane nagłówka nie powinno być „application/json” (na życzenie):

@GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) 
public void download(HttpServletResponse response) {} 
+0

Co jeśli twój klient po prostu wyśle ​​'accept = */*'? – Adam

Powiązane problemy