|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 5
The doFilter() method examines the request content type, and should it be a multipart/form-data request, wraps the request with a MultipartWrapper. The wrapper code looks like this:
package com.oreilly.servlet;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class MultipartWrapper extends HttpServletRequestWrapper {
MultipartRequest mreq = null;
public MultipartWrapper(HttpServletRequest req, String dir)
throws IOException {
super(req);
mreq = new MultipartRequest(req, dir);
}
// Methods to replace HSR methods
public Enumeration getParameterNames() {
return mreq.getParameterNames();
}
public String getParameter(String name) {
return mreq.getParameter(name);
}
public String[] getParameterValues(String name) {
return mreq.getParameterValues(name);
}
public Map getParameterMap() {
Map map = new HashMap();
Enumeration enum = getParameterNames();
while (enum.hasMoreElements()) {
String name = (String) enum.nextElement();
map.put(name, mreq.getParameterValues(name));
}
return map;
}
// Methods only in MultipartRequest
public Enumeration getFileNames() {
return mreq.getFileNames();
}
public String getFilesystemName(String name) {
return mreq.getFilesystemName(name);
}
public String getContentType(String name) {
return mreq.getContentType(name);
}
public File getFile(String name) {
return mreq.getFile(name);
}
}The wrapper constructs a com.oreilly.servlet.MultipartRequestobject to handle the upload parsing and overrides the getParameter() family of methods to use the MultipartRequest rather than the raw request to read parameter values. The wrapper also defines various getFile() methods so that a servlet receiving this wrapped request can call additional methods to handle the uploaded files.
The web.xml deployment descriptor adds the filter like this:
<
filter>
<filter-name>multipartFilter</filter-name>
<filter-class>com.oreilly.servlet.MultipartFilter</filter-class>
<!--
<init-param>
<param-name>uploadDir</param-name>
<param-value>/tmp</param-value>
</init-param>
-->
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>
uploadTest
</servlet-name>
<servlet-class>
UploadTest
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
uploadTest
</servlet-name>
<url-pattern>
/uploadTest
</url-pattern>
</servlet-mapping>The UploadTest servlet looks like this:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.oreilly.servlet.*;
public class UploadTest extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<HTML>");
out.println("<HEAD><TITLE>UploadTest</TITLE></HEAD>");
out.println("<BODY>");
out.println("<H1>UploadTest</H1>");
// Parameters can now be read the same way for both
// application/x-www-form-urlencoded and multipart/form-data requests!
out.println("<H3>Request Parameters:</H3><PRE>");
Enumeration enum = req.getParameterNames();
while (enum.hasMoreElements()) {
String name = (String) enum.nextElement();
String values[] = req.getParameterValues(name);
if (values != null) {
for (int i = 0; i < values.length; i++) {
out.println(name + " (" + i + "): " + values[i]);
}
}
}
out.println("</PRE>");
// Files can be read if the request class is MultipartWrapper
// Init params to MultipartWrapper control the upload handling
if (req instanceof MultipartWrapper) {
try {
// Cast the request to a MultipartWrapper
MultipartWrapper multi = (MultipartWrapper) req;
// Show which files we received
out.println("<H3>Files:</H3>");
out.println("<PRE>");
Enumeration files = multi.getFileNames();
while (files.hasMoreElements()) {
String name = (String)files.nextElement();
String filename = multi.getFilesystemName(name);
String type = multi.getContentType(name);
File f = multi.getFile(name);
out.println("name: " + name);
out.println("filename: " + filename);
out.println("type: " + type);
if (f != null) {
out.println("length: " + f.length());
}
out.println();
}
out.println("</PRE>");
}
catch (Exception e) {
out.println("<PRE>");
e.printStackTrace(out);
out.println("</PRE>");
}
}
out.println("</BODY></HTML>");
}
}The first half of the servlet shows how the filter exposes parameter data without any change to the receiving servlet. The
second half shows how a servlet can downcase the request to a MultipartWrapperin order to expose the additional file-access methods.
An example HTML form to drive this servlet is shown here:
< FORM ACTION="uploadTest" ENCTYPE="multipart/form-data" METHOD=POST> What is your name? <INPUT TYPE=TEXT NAME=submitter> <BR> What is your age? <INPUT TYPE=TEXT NAME=age> <BR> Which file do you want to upload? <INPUT TYPE=FILE NAME=file1> <BR> Any other file to upload? <INPUT TYPE=FILE NAME=file2> <BR> <INPUT TYPE=SUBMIT> </FORM>
Here's some possible output:
UploadTest Request Parameters: submitter (0): Jason age (0): 28 Files: name: file1 filename: 4008b21.tif type: application/octet-stream length: 39396 name: file2 filename: null type: null
Some of you may wonder what assurance we have that the MultipartWrapperset by the filter will be directly exposed to the follow-on servlet. In the specification Public Draft #2 and in Tomcat 4.0
beta 5, there is no guarantee. In fact, if you try to access the servlet as /servlet/UploadTest, you'll notice the filtering doesn't work quite right, because the invoker handling /servlet wraps the MultipartWrapperwith its own Tomcat-specific wrapper. This allows the parameters to be parsed correctly, but the file access methods won't
be directly exposed. In discussing this issue with the Servlet API expert group, we've decided that the servlet container
shouldn't do further wrapping beyond the filter's wrapper. The servlet specification will be updated to make that clear. Later
betas of Tomcat 4.0 will comply with the clarified rules. A short-term workaround is to use the getRequest()method in the request wrapper to "walk up" the request to find the shadowed multipart wrapper.
Download the WAR file for this filter at http://www.javaworld.com/jw-06-2001/Filters/mulitpart.war.
Servlet filters provide a powerful ability to control request processing and response generation, providing new functionality to servlets without large amounts of servlet coding. I hope these filters have shown you some of what is possible to do with filters, and taught you some tricks about how to make the most effective use of the new filter mechanism.
My thanks to the authors of these filters and to the people who suggested useful filters to write about: Amy Roh, Criag McClanahan, Serge Knystautas, and the folks at OpenSymphony.
Read more about Enterprise Java in JavaWorld's Enterprise Java section.