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:
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:
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:
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