Spring返回图像为ResponseEntity <byte []> - 图像损坏

时间:2015-07-09 09:22:58

标签: spring image base64

我正在开发一个spring 3.2.7应用程序,它通过弹出控制器将存储在数据库中的签名作为base64字符串发送回用户浏览器,弹出控制器输出字节数组ResponseEntity。

图像总是被破坏,我没有在系统的这一部分工作,因为我在svn中双重检查并且由于我正在处理的分支已经创建,因此未触及控制器。

我能够将base64字符串转换为桌面上的图像,并且我还可以在弹出步骤之前将返回浏览器的字节数组转换为图像。

下面是我的代码,这显然在之前工作,或许有一些配置更改可能会导致这个?

  @RequestMapping(value = "/submissions/signature/{type}/{id}", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<byte[]> getSignature(@PathVariable String type, @PathVariable Integer id) throws Exception {
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   String base64 = ... gets from db

   byte[] bytes = Base64.decodeBase64(base64);

    BufferedImage bi = ImageIO.read(new ByteArrayInputStream(bytes));
    ImageIO.write(bi, "png", baos);

    HttpHeaders headers = new HttpHeaders();
    headers.setLastModified(Calendar.getInstance().getTime().getTime());
    headers.setCacheControl("no-cache");
    headers.setContentType(MediaType.IMAGE_PNG);
    headers.setContentLength(baos.toByteArray().length);

    //Image as base64 string is ok in converter
    System.out.println("BASE 64 IMAGE IS: " + base64);
    //This image is created ok on desktop
    FileOutputStream fos = new FileOutputStream("C:\\Users\\p\\Desktop\\test_signature.png");
    fos.write(bytes);
    fos.close();
    //This image is created ok on desktop
    FileOutputStream fos3 = new FileOutputStream("C:\\Users\\p\\Desktop\\test_signature_baos.png");
    fos3.write(bytes);
    fos3.close();

    return new ResponseEntity<byte[]>(baos.toByteArray(), headers, HttpStatus.OK);
   }

图像在浏览器中呈现如下:

   <img id="userSignature" width="296" height="110" style="border:0px" src="/webapp/service/submissions/signature/user/${subid}" alt="User signature" />

我没有改变这个类,我被告知它确实有效,我能够从两个字节数组创建图像,它们没问题,看起来一样,我能够将签名字符串渲染为可测试,如: / p>

  <IMG SRC="data:image/png;base64, <base_64_string>" ALT=""> 

是否有人遇到类似问题或知道可能导致此问题的原因?

我现在尝试从已经创建为png的文件系统发送图像,但也失败了。

我现在已经注意到CSV文件无法在应用程序中正确下载,并且它们以相同的方式流式传输:

       @RequestMapping(value = "/results/csv", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<byte[]> getResultsInCsvFormat() throws IOException {

4 个答案:

答案 0 :(得分:2)

我已经在InputStream

的帮助下成功返回了文件内容
@RequestMapping(value = "/submissions/signature/{type}/{id}", 
                method = RequestMethod.GET)
public HttpEntity getFile(HttpServletResponse response,
                          @PathVariable String type, 
                          @PathVariable Integer id) {
    String base64 = "foo"; // get base-64 encoded string from db
    byte[] bytes = Base64.decodeBase64(base64);
    try (InputStream inputStream = new ByteArrayInputStream(bytes)) {
        StreamUtils.copy(inputStream, response.getOutputStream());
        response.setContentType(MediaType.IMAGE_PNG_VALUE);
    } catch (IOException e) {
        // handle
    }
    return new ResponseEntity(HttpStatus.OK);
}

请注意,我没有使用ResponseBody,而在我的工作版本中,我使用的是MediaType.APPLICATION_OCTET_STREAM_VALUE,而不是实际的文件内容类型。

答案 1 :(得分:0)

好的,所以我现在解决了这个问题,感谢beerbajay,他告诉我直接通过流媒体直接下载回复是正常的,而且我应该看看ByteArrayHttpMessageConverter。

事实证明我在spring配置中犯了一个错误,我在阅读spring文档后意识到这一点,该文档告诉我使用&lt; mvc:annotation-driven /&gt;时自动注册了ByteArrayHttpMessageConverter。

mvc注释驱动标记已从配置中删除,因为我认为这是做同样的事情(我认为它只需要在spring上下文中声明一次):

   <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
    </mvc:message-converters>
</mvc:annotation-driven>

看起来单独这个并不足以在应用程序中设置注释驱动,并且我已将标记添加回context.xml文件。

我不明白为什么这需要在两个地方,因为所有的xml配置都是通过相同的xml文件加载的,我认为是相同的弹簧上下文:

<import resource="config/properties.xml" />

<import resource="config/security.xml" />

<import resource="config/context.xml" />

<import resource="config/content-negotiation.xml" />

<import resource="config/rest-client.xml" />

答案 2 :(得分:0)

在Spring Boot 2.x中,对于Base64映像,可接受的解决方案对我不起作用。这是我返回Base64图像的方式:

@GetMapping(value = "/pixels/{id}", produces = MediaType.IMAGE_PNG_VALUE)
@ResponseBody
public byte[] pixelTracking(@PathVariable String id) {

    // TODO: do whatever you want here

    // return png image
    String base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII=";
    return Base64.getDecoder().decode(base64);
}

答案 3 :(得分:0)

我的解决方案是:

后端是spring boot,前端是reactjs

bug 是后端和前端的不同语法:java 使用 ("_","-") 和 web(reactjs,...) 使用 ("/","+") |
例如:“PGjQOA66-_ne-”转换为“PGjQOA66+//ne/+”

您可以在此链接中测试 base64 :https://onlinepngtools.com/convert-base64-to-png

后端代码:

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        File file = new File(path);/// path : is external directory and local directory in server
        FileInputStream imageInFile = new FileInputStream(path);
        byte imageData[] = new byte[(int) file.length()];
        imageInFile.read(imageData);
        String base64 =  encodeImage(imageData);
        /// 1. Not show if size up  300KB !!! :|
        /// 2. base64.replaceAll("_","/").replaceAll("-","+") 
        byte[] bytes = Base64.decodeBase64(base64.replaceAll("_","/").replaceAll("-","+"));
        BufferedImage bi = ImageIO.read(new ByteArrayInputStream(bytes));
        ImageIO.write(bi, "png", baos);


        HttpHeaders headers = new HttpHeaders();
        headers.setLastModified(Calendar.getInstance().getTime().getTime());
        headers.setCacheControl("no-cache");
        headers.setContentType(MediaType.IMAGE_PNG);
        headers.setContentLength(baos.toByteArray().length);
        return new ResponseEntity<byte[]>(baos.toByteArray(), headers, HttpStatus.OK);

和其他后端解决方案:

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        File file = new File(path);/// path : is external directory file and local directory file in server, or path get of database.
        FileInputStream imageInFile = new FileInputStream(path);
        byte imageData[] = new byte[(int) file.length()];
        imageInFile.read(imageData);
        /// 1. Not show if size up  300KB !!! :| i dont now!
        /// 2. base64.replaceAll("_","/").replaceAll("-","+") 
        String base64 =  encodeImage(imageData).replaceAll("_","/").replaceAll("-","+");
        return base64;

和 reactjs 代码是:

    const [imageData, setImageData] = React.useState({});
        
    setImageData(...request to backend);
    <img  src={`data:image/png;base64,${imageData}`} alt="This Is alert" />