我的控制器(spring4.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错误响应:
ControllerAdvice
@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 = []
但是在我的应用服务器上,尝试卸载不存在的图像时出现以下错误消息:
(编辑这是由于扩展.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测试有效?
你需要确定Spring应该如何确定响应的媒体类型。这可以通过几种方式完成:
默认情况下,Spring会查看扩展名而不是Accept标题。如果你实现@Configuration扩展的类,则可以更改此行为WebMvcConfigurerAdapter(或者由于Spring 5.0只是实现WebMvcConfigurer。你可以在其中覆盖configureContentNegotiation(ContentNegotiationConfigurer configurer)和配置ContentNegotiationConfigurer你的需求,例如,通过调用
Accept
@Configuration
WebMvcConfigurerAdapter
configureContentNegotiation(ContentNegotiationConfigurer configurer)
ContentNegotiationConfigurer
ContentNegotiationConfigurer#favorParameter ContentNegotiationConfigurer#favorPathExtension
如果你都将都设置为false,那么Spring将查看Accept标题。由于你的客户可以说Accept: image/*,application/json并处理这两个消息,因此Spring应该能够返回图像或错误JSON。
false
Accept: image/*
application/json