Writing image to servlet response with best performance

For best performance and efficiency, don’t put the entire content in byte[]. Each byte eats, yes, one byte from Java’s memory. Imagine 100 concurrent users which requests 10 images of each 100KB, that’s already 100MB of Java memory eaten away.

Get the image as an InputStream from the DB using ResultSet#getBinaryStream(), wrap it in an BufferedInputStream and write it to the OutputStream of the response wrapped in an BufferedOutputStream through a small byte[] buffer.

Assuming that you select images by the database key as identifier, use this in your HTML:

<img src="https://stackoverflow.com/questions/2979758/images/123">

Create a Servlet class which is mapped in web.xml on an url-pattern of /images/* and implement its doGet() method as follows.:

Long imageId = Long.valueOf(request.getPathInfo().substring(1)); // 123
Image image = imageDAO.find(imageId); // Get Image from DB.
// Image class is just a Javabean with the following properties:
// private String filename;
// private Long length;
// private InputStream content;

response.setHeader("Content-Type", getServletContext().getMimeType(image.getFilename()));
response.setHeader("Content-Length", String.valueOf(image.getLength()));
response.setHeader("Content-Disposition", "inline; filename=\"" + image.getFilename() + "\"");

BufferedInputStream input = null;
BufferedOutputStream output = null;

try {
    input = new BufferedInputStream(image.getContent());
    output = new BufferedOutputStream(response.getOutputStream());
    byte[] buffer = new byte[8192];
    for (int length = 0; (length = input.read(buffer)) > 0) {
        output.write(buffer, 0, length);
    }
} finally {
    if (output != null) try { output.close(); } catch (IOException logOrIgnore) {}
    if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
}

In the ImageDAO#find() you can use ResultSet#getBinaryStream() to get the image as an InputStream from the database.

Leave a Comment