JavaRanch Home    
 
This page:         last edited 06 March 2010         What's Changed?         Edit

Image Servlet   

Serving Multimedia Content from a JEE Web Application By Mark Hansen

A question asked many times on the Servlets and JSP forums is how to serve images and other multi-media content as a part of the response page. In every case, the developer asking the question is confused about how to combine the multi-media data bytes with the HTML markup being served by the Servlet or JSP. Any attempts to send the multimedia data with the Servlet response results in a mangled response.

The correct way to do this, as it turns out, is really pretty simple. It just requires one to picture the structure of the standard HTML page, and how this plays into the requests sent to the server and the responses it returns. For this article, we'll look at how to include images with our response page. The concepts, however, work equally well with other media types, including sound files, PDF documents, etc.

In the Beginning

To start things off, we need to imagine our response HTML page. This will be represented in our application as a JSP page. Here is our sample page, WEB-INF/jsp/view.jsp, simplified to keep it brief:


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/DTD/strict.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Example Image Servlet Application</title>
    </head>
    <body>
        <h2>Example Image Servlet Application</h2>
        <h3>Here is my image:</h3>
        <img src="${pageContext.request.contextPath}/ImageServlet?imageName=myImage" />
    </body>
</html>

If you look closely, you'll see there are really two types of content in this page. There is the HTML markup, like the <head>, <body> and <title> tags, as well as an <img> tag which references a very special URL in its src attribute. This URL references our Image Servlet. This is a special Servlet used by our application specifically for serving image data (or other multimedia content, as your application requires).

What is really going on here?

When our application serves the response page, that's really the end of that request/response cycle. The served HTML page, however, has other ideas. Because of the embedded <img> tag, another request is sent to satisfy that request. Where does that request go? To our special Image Servlet!

The serving of the image data is actually not part of our initial page at all - it's a completely separate request to our application, and will get a completely separate response. The client (browser in most cases) will take care of making this subsequent request, as well as dealing with the data served as the response.

So what does this Image Servlet look like anyway?

Surprisingly, the code for the Image Servlet is really pretty simple. It just needs to read the data from the requested content (image, music file, PDF document, etc.) and send it via the response output stream - along with setting a couple response headers. Let's look at a simple example:


package com.mehconsulting.servlets;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// The following import just gives us an example image to use for this example:
import com.mehconsulting.samples.SampleImage;

public class ImageServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    public ImageServlet() {
        super();
    }

    protected void doGet(
        HttpServletRequest request, HttpServletResponse response
        ) throws ServletExceptionIOException {
        
        // Not used in our simple example - see text.
        // String imageName = request.getParameter("imageName");
        
        // For this example, just create our input stream from our sample byte array:
        ByteArrayInputStream iStream = new ByteArrayInputStream(SampleImage.sampleImage);
        
        // Determine the length of the content data.
        // In our simple example, I can get the length from the hard-coded byte array.
        // If you're getting your imaqe from a database or file,
        // you'll need to adjust this code to do what is appropriate:
        int length = SampleImage.sampleImage.length;
        
        // Hard-coded for a GIF image - see text.
        response.setContentType("image/gif");
        response.setContentLength(length);
        
        // Get the output stream from our response object, so we
        // can write our image data to the client:
        ServletOutputStream oStream = response.getOutputStream();
        
        // Now, loop through buffer reads of our content, and send it to the client:
        byte [] buffer = new byte[1024];
        int len;
        while ((len = iStream.read(buffer)) != -1) {
            oStream.write(buffer, 0, len);
        }
        
        // Now that we've sent the image data to the client, close down all the resources:
        iStream.close();
        
        oStream.flush();
        oStream.close();
        
        // And we're done. Just let the method return at this point.
    }

    protected void doPost(
        HttpServletRequest request, HttpServletResponse response
        ) throws ServletExceptionIOException {

        // Pass through to the doPost method:
        doGet(request, response);
    }
// end of ImageServlet

A few notes about our simple example:

  • To keep this example simple, I've excluded any error checking/reporting. Left for the developer are considerations like what to do if the image data is not found, or if an IOException is received while reading and/or writing, among other potential issues. Especially important will be closing any resources we have opened. Think 'finally blocks'.

  • The imageName parameter comes from the URL encoded in the <img> tag of our View JSP page (WEB-INF/jsp/view.jsp). However, we're just hard-coding our image data, so we won't actually use the passed-in parameter. In a real application you can use the imageName parameter to find your file in a database, in the file system or wherever you like.

  • Security Caution: If you serve your images from the file system, take great care to make sure you don't serve files which the user should not be allowed to see. If you allow the Servlet to serve any file on your system, for example, a bad user could request your password file, etc.

  • If you look at the byte array the code is serving, it gets this from a helper class. This was just to keep the example simple. In a real application, you'll want to decide where the image data is coming from (file system, database, etc.) and adjust the code that get the input stream accordingly.

  • We've hard-coded the returned Content-Type header to be "image/gif". In a real application, you'll want to set the Content-Type header based on the actual content the application is returning.

As you can see, when you get down to the actual guts of the code, there's not much to see. We create an input stream for our content, then after setting a couple response headers, we just read the data from the input stream and write it to our output stream.

To provide access to our image servlet, we just need a couple additional entries in our applications web.xml file: a <servlet> entry and a <servlet-mapping> entry, shown here:


  <servlet>
    <servlet-name>ImageServlet</servlet-name>
    <servlet-class>com.mehconsulting.servlets.ImageServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>ImageServlet</servlet-name>
    <url-pattern>/ImageServlet</url-pattern>
  </servlet-mapping>

Tha, Tha, That's All Folks!

And that's all there is to it. Enjoy!

I have created a War file which contains the ready-to-deploy application as well as the source files for the Java classes and made it available here: http://www.mehconsulting.com/JavaRanch/imageServlet.war

In addition to the image servlet, this application includes a main Servlet which is set as the default page. Assuming you deploy the War file to a servlet container accessible at localhost port 8080, you can access the application using http://localhost:8080/imageServlet

Thank you and Good Night.


CategoryCodeSamples

JavaRanchContact us — Copyright © 1998-2014 Paul Wheaton