Date: 2005-03-02T12:20:44 Editor: DakotaJack Wiki: Apache Struts Wiki Page: StrutsUpload URL: http://wiki.apache.org/struts/StrutsUpload
no comment Change Log: ------------------------------------------------------------------------------ @@ -1,26 +1,40 @@ -== Introduction == +== Overview == -This wiki page is an attempt to open some serious dialogue on providing a multipart request API in the Struts framework that will work for the default Struts upload application as well as alternative implementations and applications. Presently alternative implementations have to forego using ActionForm because the populate method of RequestUtils necessitates using the default MultipartRequestWrapper and the default MultipartRequestHandler. +This is about Struts v1.2.6 and forward multipart requests. The following classes are suggested as a basis for allowing Struts users/developers to implement their own file upload applications. The object of suggesting these classes is to make the use of !ActionForm available to users/developers who want to do something more than the present default file upload application packaged with Struts allows but maintaining backward compatibility. -I have suggested using an alternative MultipartRequestHandler which will promote alternative ideas and have supplanted the MultipartRequestWrapper with a MultipartData interface. If the committers want to continue passing the MultipartRequestWrapper to the Action, then this can be accomplished by passing the implementation of the MultipartData interface to the MultipartRequestWrapper. +These classes, I believe, with minor revisions to the Struts framework allow this. If these classes seem remotely acceptable to those who decide such things, I will go on to code suggested changes to the framework, which really are not much. -I would strongly suggest, however, not wrapping the multipart request and getting the appropriate multipart data from the ActionForm alone. +The last three classes are example implementations of the first three interfaces and the !MultipartUtil. Any comments or suggestions are welcomed. -Below you will find suggested alternatives to the existing wrapper and handler. The suggestion is to provide two Globals fields to identify the MultipartData and MultipartRequestHandler which would be set in the mapping for whatever UploadAction subclass of Action is implemented. +=== Framework Code === -The point of all this is shown in the implementation of the MultipartRequestHandler below. As you can see, this alternative, while costing nothing, allows us to make our applications as sophisticated as we want by varying the input parameters to the handleRequest(Object []) method of the MultipartRequestHandler. In our example, we (1) pass in information with "maxFileSize" and "repositoryPath" to tell the handler what to do; (2) pass in Maps "parameterNames" and "files" as well as the "encoding" paramenter to be initialized by the handler; (3) pass in a List of monitors to be embedded in wrappers of the commons file upload package FileItem, DiskFileUpload, etc. + 1. !MultipartFile Interface + 2. !MultipartData Interface + 3. !MultipartHandler Interface + 4. !MultipartUtil Class -== Suggested Code == +=== Sample Implementation Code === -=== MultipartRequestHandler === + 1. !UploadMultipartFile Class + 2. !UploadMultipartData Class + 3. !UploadMultipartHandler Class + +== Code == + +=== MultipartFile === {{{ -public interface MultipartRequestHandler { - public void handleRequest(Object [] params) throws IOException; - public void setServlet(ActionServlet servlet); - public void setMapping(ActionMapping mapping); - public ActionServlet getServlet(); - public ActionMapping getMapping(); +public interface MultipartFile + extends Serializable { + public long getSize(); + public void setSize(long fileSize); + public String getName(); + public void setName(String fileName); + public String getContentType(); + public void setContentType(String fileContentType); + public byte[] getData(); + public InputStream getInputStream(); + public void reset(); } }}} @@ -35,6 +49,18 @@ } }}} +=== MultipartHandler === + +{{{ +public interface MultipartHandler { + public void handleRequest(Object [] params) throws IOException; + public void setServlet(ActionServlet servlet); + public void setMapping(ActionMapping mapping); + public ActionServlet getServlet(); + public ActionMapping getMapping(); +} +}}} + === MultipartUtil === {{{ @@ -60,6 +86,98 @@ } }}} +=== UploadMultipartFile === + +{{{ +public class UploadMultipartFile + implements MultipartFile { + private String fileContentType; + private String fileName; + private long fileSize; + private FileItem fi; + + public UploadMultipartFile() { + } + + public UploadMultipartFile(FileItem fi) { + this.fi = fi; + } + + public UploadMultipartFile(String fileName, + String fileContentType, + long fileSize) { + this.fileSize = -1L; + this.fileName = fileName; + this.fileContentType = fileContentType; + this.fileSize = fileSize; + } + + public long getSize() { + return fileSize; + } + + public void setSize(long fileSize) { + this.fileSize = fileSize; + } + + public String getName() { + return fileName; + } + + public void setName(String fileName) { + this.fileName = fileName; + } + + public String getContentType() { + return fileContentType; + } + + public void setContentType(String fileContentType) { + this.fileContentType = fileContentType; + } + + public byte[] getData() { + InputStream is = getInputStream(); + if(is != null) { + int i = (int)getSize(); + if(i > 0) { + byte data0[] = new byte[i]; + try { + is.read(data0); + is.close(); + } catch(IOException ioe) { } + return data0; + } else { + return null; + } + } else { + return null; + } + } + + public void reset() { + if(this.fi != null) + this.fi.delete(); + } + + public InputStream getInputStream() { + if(fi == null) { + return null; + } + + try { + return new BufferedInputStream(fi.getInputStream()); + } catch (IOException ioe) { + return null; + } + } + + public FileItem getFileItem() { + return fi; + } +} +}}} + === UploadMultipartData === {{{ @@ -82,7 +200,7 @@ parameterNames = Collections.synchronizedMap(new HashMap(89)); files = Collections.synchronizedMap(new HashMap(89)); - MultipartRequestHandler handler = new UploadMultipartRequestHandler(); + MultipartHandler handler = new UploadMultipartHandler(); Object [] objects = new Object [] { req,monitors, new Integer(fileSizeLimit), @@ -121,15 +239,15 @@ } }}} -=== UploadMultipartRequestHandler === +=== UploadMultipartHandler === {{{ -public class UploadMultipartRequestHandler - implements MultipartRequestHandler { +public class UploadMultipartHandler + implements MultipartHandler { private ActionMapping mapping; private ActionServlet servlet; - public UploadMultipartRequestHandler() { + public UploadMultipartHandler() { } public void handleRequest(Object [] params) @@ -200,7 +318,7 @@ } else { String name = fi.getName(); if(name != null) { - FormFile uf = new UploadFormFile(fi); + MultipartFile uf = new UploadMultipartFile(fi); name = name.replace('\\', '/'); int j = name.lastIndexOf("/"); @@ -208,9 +326,9 @@ name = name.substring(j + 1, name.length()); } - uf.setFileName(name); - uf.setFileContentType(fi.getContentType()); - uf.setFileSize(fi.getSize()); + uf.setName(name); + uf.setContentType(fi.getContentType()); + uf.setSize(fi.getSize()); files.put(fieldName, uf); } } @@ -232,58 +350,5 @@ public void setMapping(ActionMapping mapping) { this.mapping = mapping; } -} -}}} - - -=== FormFile === - -{{{ -public abstract class FormFile - implements Serializable { - private String fileContentType; - private String fileName; - private long fileSize; - - public FormFile(String fileName, - String fileContentType, - long fileSize) { - this.fileSize = -1L; - this.fileName = fileName; - this.fileContentType = fileContentType; - this.fileSize = fileSize; - } - - public FormFile() { - this(null, null, -1L); - } - - public long getFileSize() { - return fileSize; - } - - public void setFileSize(long fileSize) { - this.fileSize = fileSize; - } - - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } - - public String getFileContentType() { - return fileContentType; - } - - public void setFileContentType(String fileContentType) { - this.fileContentType = fileContentType; - } - - public abstract byte[] getFileData(); - public abstract InputStream getFileInputStream(); - public abstract void reset(); } }}} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]