问题
I have the following image download method in my controller (Spring 4.1):
@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);
}
The following ControllerAdvice
method should handle a non-existing file and return a json error response:
@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;
}
My JUnit test works flawless
(EDIT this is because of extention .bla : this also works on 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));
}
and gives the following output:
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 = []
However on my appserver i get the following error message when trying to donwload non existing image:
(EDIT this is because of extention .jpg : this also fails on JUnit test with .jpg extention):
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
I have configured messageconverters in my mvc configuration as follows:
@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;
}
What am i missing? And why is the JUnit test working?
回答1:
You need to decide how the media type of the response should be determined by Spring. That can be done in several ways:
- path extension (eg. /image.jpg)
- URL parameter (eg. ?format=jpg)
- HTTP Accept header (eg. Accept: image/jpg)
By default, Spring looks at the extension rather than the Accept
header. This behaviour can be changed if you implement a @Configuration
class that extends WebMvcConfigurerAdapter (or since Spring 5.0 simply implement WebMvcConfigurer. There you can override configureContentNegotiation(ContentNegotiationConfigurer configurer) and configure the ContentNegotiationConfigurer to your needs, eg. by calling
ContentNegotiationConfigurer#favorParameter
ContentNegotiationConfigurer#favorPathExtension
If you set both to false
, then Spring will look at the Accept
header. Since your client can say Accept: image/*,application/json
and handle both, Spring should be able to return either the image or the error JSON.
See this Spring tutorial on content negotiation for more information and examples.
回答2:
Pay attention to your HTTP Accept header. For example, if your controller produces "application/octet-stream" (in response), your Accept header should NOT be "application/json" (in request):
@GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void download(HttpServletResponse response) {}
来源:https://stackoverflow.com/questions/32351142/httpmediatypenotacceptableexception-could-not-find-acceptable-representation-in