3.3 Other Servlet Tips

I l @ ve RuBoard

Here are some other things to keep in mind when working with servlets.

3.3.1 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. [3] 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.

[3] Microsoft documents Internet Explorer's deviant behavior at http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp, although I've found that reality doesn't exactly match the documentation.

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. [4] 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.

[4] The HTTP specification recommends setting the Content-Type to 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).

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 .

3.3.2 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.

I l @ ve RuBoard

The OReilly Java Authors - JavaT Enterprise Best Practices
The OReilly Java Authors - JavaT Enterprise Best Practices
Year: 2002
Pages: 96

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net