7.2 基于Struts 2完成文件上传
前面介绍了如何通过Common-FileUpload框架和COS框架来实现文件上传。Struts 2并没有提供上传组件,而是通过调用这些上传框架来实现的上传。Struts 2对于这些上传框架进行了进一步封装,从而更加简化了文件上传。
7.2.1 配置上传解析器
前面分别通过Common-FileUpload框架和COS框架实现了文件上传,下面来看如何基于Struts 2来完成文件上传。
前面提到过Struts 2并没有提供上传组件,而是通过调用这些上传框架来实现的上传,那么如何在Struts 2中配置这些上传框架呢?
首先打开导入“struts2-core-2.0.11.1.jar”库文件,找到org.apache.struts2包下的default.properties资源文件,代码如下所示。在该资源文件中给出了许多的Struts 2的默认配置,其中可以看到Struts 2默认使用jakarta作为其文件上传的解析器,代码如下所示。
### Parser to handle HTTP POST requests, encoded using the MIME-type multipart/form-data # struts.multipart.parser=cos # struts.multipart.parser=pell struts.multipart.parser=jakarta
其实jakarta是指Common-FileUpload框架。因为Common-FileUpload项目属于jakarta的子项目。如果在Struts 2项目中使用Common-FileUpload框架来上传文件,只需将“commons-fileupload-1.2.1.jar”库文件以及“commons-io-1.4.jar”库文件复制到Web应用中的WEB-INF下的lib目录中。
如果希望使用COS框架来上传文件,只需“cos.jar”库文件复制到Web应用中的WEB-INF下的lib目录中,然后修改struts.multipart.parser常量值。常量值修改分两种方法,一种是在struts.properties中修改,另一种是在“struts.xml”文件中修改。
❑ 在struts.properties中修改,指定struts.multipart.parser常量值为cos,代码如下。
struts.multipart.parser=cos
❑ 在struts.xml文件中修改,指定struts.multipart.parser常量值为cos,代码如下。
<constant name="struts.multipart.parser" value="cos"></constant>
在Struts 2中使用这两种上传框架没有什么不同,Struts 2已经在这两个上传框架之上再封装了一层,这种封装完全取消了两种框架上传时的区别。
这时如果需要替换上传框架,只需修改struts.multipart.parser常量值,指定使用的上传框架即可。
7.2.2 实现文件上传Action
下面来看如何基于Struts 2完成单个文件上传。首先创建用户输入页,该页面仅仅包含一个表单,用来输入用户名以及选择用来上传的文件,表单提交到upload.action,代码如下所示。
<%@ page language="java" pageEncoding="gb2312"%> <html> <head> <title>文件上传</title> </head> <center> <h1>Struts 2完成上传</h1> <form action="upload.action" method="post" enctype="multipart/form-data"> <table> <tr> <td>用户名:</td> <td><input type="text" name="username" ></td> </tr> <tr> <td>上传文件:</td> <td><input type="file" name="myFile"></td> </tr> <tr> <td><input type="submit" value="上传"></td> <td><input type="reset"></td> </tr> </table> </form> </center> <body> </body> </html>
Struts 2的文件上传是通过文件上传拦截器来完成的。在“struts-default.xml”配置文件中找到文件上传拦截器的配置,代码如下所示。
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
在org.apache.struts2.interceptor包中找到文件上传拦截器FileUploadInterceptor。打开FileUploadInterceptor类,首先来看这样一段注释。
* <ul> * * <li>[File Name] : File - the actual File</li> * * <li>[File Name]ContentType : String - the content type of the file</li> * * <li>[File Name]FileName : String - the actual name of the file uploaded (not the HTML name)</li> * * </ul>
这段注释用来说明如何在Action中配置其属性。其中File Name属性类型为File,表示用户上传的文件。[File Name]ContentType属性封装上传文件的类型,[File Name]FileName属性封装上传文件的文件名。这里的Fiel Name就是指用户提交表单中的文件域的name属性。
在Action中属性一般都是与提交的参数相对应的,这里并没有提交FileNameContentType和File NameFileName参数。这就要归功于FileUploadInterceptor文件上传拦截器了,查看FileUploadInterceptor类中的这段代码。
if (acceptFile(files[index], contentType[index], inputName, validation, ac.getLocale())) { parameters.put(inputName, files); parameters.put(inputName + "ContentType", contentType); parameters.put(inputName + "FileName", fileName); }
通过FileUploadInterceptor拦截器添加相应的参数。拦截器已经做了很多的工作,所以使得开发变得非常简单。下面来完成文件上传Action,代码如下所示。
package net.hncu.struts2.action; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class UploadAction extends ActionSupport { // username属性用来封装用户名 private String username; // myFile属性用来封装上传的文件 private File myFile; // myFileContentType属性用来封装上传文件的类型 private String myFileContentType; // myFileFileName属性用来封装上传文件的文件名 private String myFileFileName; //获得username值 public String getUsername() { return username; } //设置username值 public void setUsername(String username) { this.username = username; } //获得myFile值 public File getMyFile() { return myFile; } //设置myFile值 public void setMyFile(File myFile) { this.myFile = myFile; } //获得myFileContentType值 public String getMyFileContentType() { return myFileContentType; } //设置myFileContentType值 public void setMyFileContentType(String myFileContentType) { this.myFileContentType = myFileContentType; } //获得myFileFileName值 public String getMyFileFileName() { return myFileFileName; } //设置myFileFileName值 public void setMyFileFileName(String myFileFileName) { this.myFileFileName = myFileFileName; } public String execute() throws Exception { //基于myFile创建一个文件输入流 InputStream is = new FileInputStream(myFile); // 设置上传文件目录 String uploadPath = ServletActionContext.getServletContext() .getRealPath("/upload"); // 设置目标文件 File toFile = new File(uploadPath, this.getMyFileFileName()); // 创建一个输出流 OutputStream os = new FileOutputStream(toFile); //设置缓存 byte[] buffer = new byte[1024]; int length = 0; //读取myFile文件输出到toFile文件中 while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } //关闭输入流 is.close(); //关闭输出流 os.close(); return SUCCESS; } }
7.2.3 配置文件上传Action
在“struts.xml”文件中配置文件上传Action。定义upload的Action,指定其实现类为net.hncu. struts2.action.UploadAction。为了使其能够接受中文参数值,设置参数编码为gb2312,代码如下所示。
<? xml version="1.0" encoding="UTF-8" ? > <! DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <! -- struts为配置文件根元素--> <struts> <! -- 设置参数编码 --> <constant name="struts.i18n.encoding" value="gb2312"></constant> <! -- Action必须放在指定的包名空间中--> <package name="struts2" extends="struts-default"> <! -- 定义upload的Action,其实现类为net.hncu.struts2.action.UploadAction--> <action name="upload" class="net.hncu.struts2.action.UploadAction"> <! -- 定义处理结果与视图资源之间的关系--> <result name="success">/result.jsp</result> <result name="input">/upload.jsp</result> </action> </package> </struts>
7.2.4 测试文件上传
打开用户输入页,填写用户名并选择文件进行上传,如图7.19所示。
页面跳转到结果输出页。页面中显示了用户名以及上传的文件名,如图7.20所示。
下面打开文件上传目录upload,在该目录中可以看到刚才上传的文件,如图7.21所示。
现在基于Struts 2完成了文件上传,但是还有以下问题没有解决。
❑ 文件保存目录问题:在Action中配置文件目录,修改起来比较麻烦。
❑ 文件大小以及类型问题:上传文件大小以及类型没有限制。
❑ 错误提示问题:如果上传不符合配置的文件应该提示其错误信息。
图7.19 用户输入页
图7.20 结果输出页
图7.21 上传目录upload