O'Reilly Book Excerpts: Java Enterprise Best Practices
Servlet Best Practices, Part 3
In the last of this series of book excerpts on Servlet best practices from Java Enterprise Best Practices, here are some other Servlet best practices tips.
Other Servlet Tips
Here are some other things to keep in mind when working with servlets.
Use Content-Disposition to Send a File
While we're on the subject of magic header incantations, servlet developers often struggle with finding the right header combination to send a browser a file that's intended for saving rather than viewing and thus triggers a "Save As" dialog. For the solution to this problem, I have some good news and some bad news.
The bad news is that although the HTTP specification provides a mechanism for file downloads (see HTTP/1.1, Section 19.5.1), many browsers second-guess the server's directives and do what they think is best rather than what they're told. These browsers--including Microsoft Internet Explorer and Opera--look at the file extension and "sniff" the incoming content. If they see HTML or image content, they inline-display the file contents instead of offering a Save As dialog. Turns out there's no 100% reliable way to download a file across all browsers. Perhaps, with this effort, programmers are more like alchemists than magicians, trying in vain to turn lead into gold.
The good news is that the right combination of headers will download files well enough to be practical. With these special headers set, a compliant browser will open a Save As dialog, while a noncompliant browser will open the dialog for all content except HTML or image files. For these types it will display the content inline, where a user can use the menu to save the content. Example 3-9 shows the best technique for sending files.
Example 3-9: Sending a file for download
// Set the headers. res.setContentType("application/x-download"); res.setHeader("Content-Disposition", "attachment; filename=" + filename); // Send the file. OutputStream out = res.getOutputStream( ); returnFile(filename, out); // Shown earlier in the chapter
First, set the
Content-Type header to a nonstandard value such as
application/x-download. It's very important that this header is something unrecognized by browsers because browsers often try to do something special when they recognize the content type. Then set the
Content-Disposition header to the value
attachment; filename=foo, in which foo is substituted with the filename to be used by default in the Save As dialog. Finally, send the file content as bytes. The bytes can come from the filesystem or be dynamically generated.
In This Series
Servlet Best Practices, Part 1
Using these headers, the file content in the response will be saved by most browsers or, in worst cases, displayed inline where the user can save the file. There's no standard way to download multiple files in one response.
Finally, it can be useful to include the download file's name as extra path information to the servlet. The servlet can use the filename to learn which file to download, or it can ignore the extra path info. Either way, it's useful because the name appears to the browser as the name of the resource being retrieved, and browsers often use that name in the Save As dialog prompt. For example, instead of serving content from /servlet/FileDownload?fileid=5, serve it from /servlet/FileDownload/inventory.pdf?fileid=5.
Hire a UI Designer
My last piece of personal advice comes not from fellow servlet programmers, but from the users we all serve: "Please, please, please hire a user interface designer."
Here are the facts: only a handful of people can be good designers, and only a handful of people can be good Java programmers. The rare odds of one person being in both handfuls can barely be measured with an IEEE double. Therefore, the odds are you're not a good UI designer. Please hire someone who is, and spend your time hacking back-end code with the rest of us who can't tell kerning from a kernel. We back-end folks are more fun anyway, in a laugh-through-the-nose kind of way.
3. Microsoft documents Internet Explorer's deviant behavior, although I've found that reality doesn't exactly match the documentation.
4. The HTTP specification recommends setting the
application/octet-stream. Unfortunately, this causes problems with Opera 6 on Windows (which will display the raw bytes for any file whose extension it doesn't recognize) and on Internet Explorer 5.1 on the Mac (which will display inline content that would be downloaded if sent with an unrecognized type).
The O'Reilly Java Authors , each an expert in his particular field, wrote chapters on different aspects of Java enterprise development.
Return to ONJava.com.