如何在Spring Boot控制器中返回图像并像文件系统一样提供服务

我已经尝试过Stackoverflow中给出的各种方法,也许我错过了一些东西。

我有一个Android客户端(其代码我无法更改),目前正在获取如下图像:

HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.connect(); 

url是图像的位置(CDN上的静态资源)。 现在我的Spring Boot API端点需要以相同的方式表现得像文件资源,以便相同的代码可以从API获取图像(Spring引导版本1.3.3)。

所以我有这个:

 @ResponseBody @RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE, produces = MediaType.IMAGE_JPEG_VALUE) public ResponseEntity getImage(@PathVariable("id")String id) { byte[] image = imageService.getImage(id); //this just gets the data from a database return ResponseEntity.ok(image); } 

现在,当Android代码试图获取http://someurl/image1.jpg ,我的日志中出现此错误:

解决处理程序中的exception[public org.springframework.http.ResponseEntity com.myproject.MyController.getImage(java.lang.String)]:org.springframework.web.HttpMediaTypeNotAcceptableException:找不到可接受的表示

当我将http://someurl/image1.jpg插入浏览器时,会发生同样的错误。

奇怪的是,我的测试结果还可以:

 Response response = given() .pathParam("id", "image1.jpg") .when() .get("MyController/Image/{id}"); assertEquals(HttpStatus.OK.value(), response.getStatusCode()); byte[] array = response.asByteArray(); //byte array is identical to test image 

如何使其行为像正常方式提供的图像? (注意我无法更改android代码发送的内容类型标题)

编辑

评论后的代码(设置内容类型,取出produces ):

 @RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE) public ResponseEntity getImage(@PathVariable("id")String id, HttpServletResponse response) { byte[] image = imageService.getImage(id); //this just gets the data from a database response.setContentType(MediaType.IMAGE_JPEG_VALUE); return ResponseEntity.ok(image); } 

在浏览器中,这似乎只是给出了一个字符串化的垃圾(字节到字符我猜)。 在Android中它没有错误,但图像不显示。

我相信这应该有效:

 @RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET) public ResponseEntity getImage(@PathVariable("id") String id) { byte[] image = imageService.getImage(id); return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(image); } 

请注意,为ResponseEntity设置了content-type,而不是直接为HttpServletResponse设置。

最后解决了这个问题……我不得不在我的WebMvcConfigurerAdapter子类中添加一个ByteArrayHttpMessageConverter

 @Override public void configureMessageConverters(List> converters) { final ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter(); final List list = new ArrayList<>(); list.add(MediaType.IMAGE_JPEG); list.add(MediaType.APPLICATION_OCTET_STREAM); arrayHttpMessageConverter.setSupportedMediaTypes(list); converters.add(arrayHttpMessageConverter); super.configureMessageConverters(converters); } 

如果您不知道文件/ mime类型,您可以执行此操作….我已经完成了这一点,我采取上传文件并用guid替换文件名,没有扩展名,浏览器/智能手机能够加载图像没有问题。 第二个是提供要下载的文件。

 @RestController @RequestMapping("img") public class ImageController { @GetMapping("showme") public ResponseEntity getImage() throws IOException{ File img = new File("src/main/resources/static/test.jpg"); return ResponseEntity.ok().contentType(MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap().getContentType(img))).body(Files.readAllBytes(img.toPath())); } @GetMapping("thing") public ResponseEntity what() throws IOException{ File file = new File("src/main/resources/static/thing.pdf"); return ResponseEntity.ok() .header("Content-Disposition", "attachment; filename=" +file.getName()) .contentType(MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap().getContentType(file))) .body(Files.readAllBytes(file.toPath())); } }