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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40557637/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:47:55  来源:igfitidea点击:

How to return an image in Spring Boot controller and serve like a file system

javaspring-mvcspring-boot

提问by Manish Patel

I've tried the various ways given in Stackoverflow, maybe I missed something.

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

I have an Android client (whose code I can't change) which is currently getting an image like this:

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

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

Where urlis the location of the image (static resource on CDN). Now my Spring Boot API endpoint needs to behave like a file resource in the same way so that the same code can get images from the API (Spring boot version 1.3.3).

url图片的位置在哪里(CDN上的静态资源)。现在,我的 Spring Boot API 端点需要以相同的方式像文件资源一样运行,以便相同的代码可以从 API(Spring Boot 版本 1.3.3)获取图像。

So I have this:

所以我有这个:

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

Now when the Android code tries to get http://someurl/image1.jpgI get this error in my logs:

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

Resolving exception from handler [public org.springframework.http.ResponseEntity com.myproject.MyController.getImage(java.lang.String)]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

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

Same error happens when I plug http://someurl/image1.jpginto a browser.

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

Oddly enough my tests check out ok:

奇怪的是,我的测试结果正常:

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

How do I get this to behave like an image being served up in the normal way? (Note I can't change the content-type header that the android code is sending)

我如何让它表现得像以正常方式提供的图像?(请注意,我无法更改 android 代码发送的内容类型标头)

EDIT

编辑

Code after comments (set content type, take out produces):

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

@RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE)
public ResponseEntity<byte[]> 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);
}

In a browser this just seems to give a stringified junk (byte to chars i guess). In Android it doesn't error, but the image doesn't show.

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

采纳答案by Manish Patel

Finally fixed this... I had to add a ByteArrayHttpMessageConverterto my WebMvcConfigurerAdaptersubclass:

终于解决了这个问题......我不得不ByteArrayHttpMessageConverter在我的WebMvcConfigurerAdapter子类中添加一个:

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

    super.configureMessageConverters(converters);
}

回答by Roman

I believe this should work:

我相信这应该有效:

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

Notice that the content-type is set for ResponseEntity, not for HttpServletResponsedirectly.

请注意,内容类型设置为ResponseEntity,而不是HttpServletResponse直接设置。

回答by mavriksc

In case you don't know the file/mime type you can do this.... I've done this where i take an uploaded file and replace the file name with a guid and no extension and browsers / smart phones are able to load the image no issues. the second is to serve a file to be downloaded.

如果您不知道文件/mime 类型,您可以执行此操作......加载图像没有问题。第二个是提供要下载的文件。

@RestController
@RequestMapping("img")
public class ImageController {

@GetMapping("showme")
public ResponseEntity<byte[]> 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<byte[]> 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()));
}


}   

UPDATEin java 9+ you need to add compile 'com.sun.activation:javax.activation:1.2.0'to your dependencies this has also been moved or picked up by jakarta.see this post

在 Java 9+ 中更新您需要将其添加compile 'com.sun.activation:javax.activation:1.2.0'到您的依赖项中,这也已被雅加达移动或拾取。看到这个帖子

回答by devyJava

Using Apache Commons, you can do this and expose the image on an endpoint

使用 Apache Commons,您可以执行此操作并在端点上公开图像

@RequestMapping(value = "/image/{imageid}",method= RequestMethod.GET,produces = MediaType.IMAGE_JPEG_VALUE)
public @ResponseBody byte[] getImageWithMediaType(@PathVariable int imageid) throws IOException {
    InputStream in = new ByteArrayInputStream(getImage(imageid));
    return IOUtils.toByteArray(in);
    }

All images will be served at endpoint /image/{imageid}

所有图像都将在端点提供 /image/{imageid}