我的控制器(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);
}
以下ControllerAdvice
方法应处理不存在的文件并返回json错误响应:
@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;
}
我的JUnit测试完美无缺
(编辑这是因为扩展.bla:这也适用于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));
}
并提供以下输出:
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 = []
但是在我的appserver上,我在尝试下载非现有图像时收到以下错误消息:
(编辑这是因为扩展.jpg:在使用.jpg扩展的JUnit测试中也失败了):
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
我已在mvc配置中配置了messageconverters,如下所示:
@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;
}
我缺少什么?为什么JUnit测试有效?
答案 0 :(得分:27)
您需要决定Spring应如何确定响应的媒体类型。这可以通过几种方式完成:
默认情况下,Spring会查看扩展名而不是Accept
标头。如果您实现扩展@Configuration
的{{1}}类,则可以更改此行为。在那里,您可以覆盖WebMvcConfigurerAdapter
并根据您的需要配置配置器,例如。通过调用
configureContentNegotiation(ContentNegotiationConfigurer configurer)
如果将两者都设置为ContentNegotiationConfigurer#favorParameter
ContentNegotiationConfigurer#favorPathExtension
,那么Spring将查看false
标题。由于您的客户端可以说Accept
并处理它们,因此Spring应该能够返回图像或错误JSON。
有关更多信息和示例,请参阅有关内容协商的this Spring tutorial。
答案 1 :(得分:2)
注意您的HTTP Accept标头。 例如,如果您的控制器生成&#34; application / octet-stream&#34; (作为回应),你的Accept标题不应该是&#34; application / json&#34; (请求中):
@GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void download(HttpServletResponse response) {}