Images won't load if they are of high size

后端 未结 1 505
轮回少年
轮回少年 2020-12-20 10:19

I am storing images in DB using MEDIUMBLOB. When I try to load image through a servlet, I am able to see those images. However if the image size is big (1 MB or more), I can

相关标签:
1条回答
  • 2020-12-20 10:57

    The way how you measured the image's length is wrong. You're basically converting the image bytes to human readable characters (in an unintelligible sequence, but that aside) and then calculating the amount of characters. This is not right. You need to calculate the amount of raw and unconverted bytes instead. One character is not necessarily represented by only one byte, but it can be represented by more than one byte.

    There are 2 ways to solve your problem:

    1. Use ResultSet#getBytes() instead.

      byte[] content = resultSet.getBytes("content");
      // ...
      response.setContentLength(content.length);
      response.getOutputStream().write(content);
      

      Please note that this is memory hogging as every byte of a byte[] basically accumulates one byte of Java's memory.

    2. Select the BLOB length in the query as well. How to do that depends on the DB used. In MySQL, you can use the LENGTH() function for this.

      SELECT content, LENGTH(content) AS contentLength FROM image WHERE id = ?
      

      Which you then process as follows:

      InputStream content = resultSet.getBinaryStream("content");
      int contentLength = resultSet.getInt("contentLength");
      // ...
      response.setContentLength(contentLength);
      SomeUtil.streamByBuffer(content, response.getOutputStream());
      

      (wherein the process is not taken place through a byte[] of full image's length)


    Update: after all, the request on the image seemed to have invoked the MyFacesExtensionsFilter which is apparently overzealously buffering the response without properly flushing it when the chain.doFilter() returns. This filter is according the mapping rules only invoked when the FacesServlet is invoked. But this shouldn't have happened. The image request should only have invoked the image servlet, not also the faces servlet.

    According the mapping rules, the FacesServlet is invoked on /faces/* while your image servlet is mapped on /DisplayImage. The <img src> as you've there is relative to the current request URL, so it ultimately ends up to be /faces/DisplayImage which will first invoke the FacesServlet and then the DisplayImage servlet. This is wrong.

    You should change the JSF code accordingly so that the <img src> ultimately becomes domain-relative so that it invokes only the /DisplayImage servlet.

    <img src="/contextpath/DisplayImage?mainID=drawing" />
    

    You can achieve this by just using the leading slash in <h:graphicImage>. It will auto-prepend the context path.

    <h:graphicImage value="/DisplayImage?mainID=drawing" />
    
    0 讨论(0)
提交回复
热议问题