File upload and download in Java Web Application.
最近在项目中遇到一个下载文件的老问题。之所以说是老问题,因为在以前的很多项目中都遇到过,但是当时赶进度,所以在找到解决方案后就草草了事,没有深入的研究、总结一下各种方法,实乃憾事。
既然再次遇到,就不能放过。争取在依然很紧张的项目进度中,找出一点时间总结一下Java Web Application开发中涉及到的文件上传、下载解决方案。鉴于博客是写给自己看的,加上时间紧张,所以我会持续更新,不求一气呵成。
?
Upload File through Html FORM:/html/body/form/@enctype: ENCTYPE determines how the form data is encoded. Whenever data is transmitted from one place to another, there needs to be an agreed upon means of representing that data.
FORM ENCTYPE has three different values:
So if you want to upload file through web, you have to first set form ENCTYPE to be "multipart/form-data".
Using pure Servlet:In fact, file download and upload in Java Web Application are to manage files through InputStream from HttpServletRequest and OutputStream from HttpServletResponse.
Even we can simply the development and configuration by using some framework, but anyway we should know what is the kernel for file uploading and download.
File Upload web interface:?
???????????????????? ??? ??? ??? ????headers for defeating caching to every response from
???????????????????? ??? ??? ??? ????this module.? [false]
??? ??? ??? ??? @tempDir??? ??? ????Temporary working directory to use when processing
???????????????????? ??? ??? ??? ????file uploads.
???????????????????? ??? ??? ??? ????[{Directory provided by servlet container}]
By default struts 1 provide org.apache.struts.upload.CommonsMultipartRequestHandler to process file uploading transform.?CommonsMultipartRequestHandler encapsulate apache-commons-fileupload for file uploading processing. If you want to know how?CommonsMultipartRequestHandler?manage file uploading or you want to implement your own MultipartRequestHandler, please refer to struts source code for that.
?
?
Your form should extends ActionForm and contains a FileForm named with same value as html:file/@name.
Then config your upload Action in struts-config.xml to map to this form-bean.
?
After that, we can use FormFile.getInputStream() to get file data and no need to care about file uploading processing.
File download through Struts1:Struts 1 provide DownloadAction:
org.apache.struts.actions.DownloadAction.
Here is a snapshot of org.apache.struts.actions.DownloadAction.java:
?
public abstract class DownloadAction extends BaseAction {
??? /**
???? * Process the specified HTTP request, and create the corresponding HTTP
???? * response (or forward to another web component that will create it).
???? * Return an <code>ActionForward</code> instance describing where and how
???? * control should be forwarded, or <code>null</code> if the response has
???? * already been completed.
???? *
???? * @param mapping? The ActionMapping used to select this instance.
???? * @param form???? The optional ActionForm bean for this request (if
???? *???????????????? any).
???? * @param request? The HTTP request we are processing.
???? * @param response The HTTP response we are creating.
???? * @return The forward to which control should be transferred, or
???? *???????? <code>null</code> if the response has been completed.
???? * @throws Exception if an exception occurs.
???? */
??? public ActionForward execute(ActionMapping mapping, ActionForm form,
??????? HttpServletRequest request, HttpServletResponse response)
??????? throws Exception {
??????? StreamInfo info = getStreamInfo(mapping, form, request, response);
??????? String contentType = info.getContentType();
??????? InputStream stream = info.getInputStream();
??????? try {
??????????? response.setContentType(contentType);
??????????? copy(stream, response.getOutputStream());
??????? } finally {
??????????? if (stream != null) {
??????????????? stream.close();
??????????? }
??????? }
?????? ??? // Tell Struts that we are done with the response.
??????? return null;
??? }
????
??? /**
???? * Returns the information on the file, or other stream, to be downloaded
???? * by this action. This method must be implemented by an extending class.
???? *
???? * @param mapping? The ActionMapping used to select this instance.
???? * @param form???? The optional ActionForm bean for this request (if
???? *???????????????? any).
???? * @param request? The HTTP request we are processing.
???? * @param response The HTTP response we are creating.
???? * @return The information for the file to be downloaded.
???? * @throws Exception if an exception occurs.
???? */
??? protected abstract StreamInfo getStreamInfo(ActionMapping mapping,
??????? ActionForm form, HttpServletRequest request,
??????? HttpServletResponse response)
??????? throws Exception;
????
????
??? /**
???? * Copy bytes from an <code>InputStream</code> to an
???? * <code>OutputStream</code>.
???? *
???? * @param input? The <code>InputStream</code> to read from.
???? * @param output The <code>OutputStream</code> to write to.
???? * @return the number of bytes copied
???? * @throws IOException In case of an I/O problem
???? */
??? public int copy(InputStream input, OutputStream output)
??????? throws IOException {
??????? byte[] buffer = new byte[getBufferSize()];
??????? int count = 0;
??????? int n = 0;
??????? while (-1 != (n = input.read(buffer))) {
??????????? output.write(buffer, 0, n);
??????????? count += n;
??????? }
??????? return count;
??? }
??? ......????
}
?
?
So we should define an Action that extends DownloadAction and implement method:
StreamInfo getStreamInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response);
Inside your implementation, you can read file from file system or get them from romote server, and then format it into a StreamInfo object which will be used by DownloadAction to open a InputStream.Using Struts2Struts2 vs Struts1:Since Struts2 realize webwork2 and provides different configuration as struts1. So it is more like a new MVC framework rather than upgrade of struts1. Here are some new features in struts2:
For file uploading, struts2 introduce three new parameters in Action to represent File information:
File XXX: ?? ??? ??? ??? ?represent the File to be uploaded. XXX is the value of attribute: HTML/form/file/@name.?String XXXFileName: ?? ?represent the original file name of file XXX.String XXXContentType:?represent the content type of file XXX.?If you want to upload a set of files, those three parameters should be defined as:
File[] XXX: ?? ??? ??? ??? ?represent the File to be uploaded. XXX is the value of attribute: HTML/form/file/@name. ??All the file upload form should use same file/@name definition.String[] XXXFileName: ?? ??? ?represent the original file names of file XXX.String[] XXXContentType:?? ?represent the content types of files XXX.?So you should define your own upload Action as following:
?
Because in my current project, we do not use struts2, so I do not study the source code of struts2. But anyway, we can image there is a MultipartRequestHandler which?will process file uploading and convert it into Action.XXX for us.
?
File Download through Struts2About download, we can talk about it later.
But anyway, I am always thinking that even framework provide encapsulation of complex operation for us, but the kernel should always the same: send file data through Response OutputStream.
?
Attach file management in SOAPTBD
?