7.4 Struts 2实现上传多个文件
前面介绍的都是上传一个文件,其实Struts 2也可以很方便地实现多文件上传。如果页面中有多个文件域需要实现文件上传,则只需在Action中为每个文件域指定3个属性,分别用来封装上传文件、上传文件类型、上传文件名。
7.4.1 使用数组实现上传多个文件
前面介绍的都是上传单个文件,下面来看如何实现上传多个文件。
在Action中为每个文件域指定3个属性,确实可以实现多个文件的上传,但是这样使得代码过于臃肿,而且失去了灵活性。如果以后要添加一个文件域,那就必须在Action中为其添加相应的属性。
这时可以使用数组或者List来封装所有的文件域,不过前提是这些文本域的name属性必须相同。
(1)新建一个用户输入页,添加两个文件域,其name属性都为myFile,代码如下所示。
<form action="upload.action" method="post" enctype="multipart/form-data"> <table> <tr> <td>用户名:</td> <td><input type="text" name="username" ></td> </tr> <tr> <td>上传文件1:</td> <td><input type="file" name="myFile"></td> </tr> <tr> <td>上传文件2:</td> <td><input type="file" name="myFile"></td> </tr> <tr> <td><input type="submit" value="上传"></td> <td><input type="reset"></td> </tr> </table> </form>
(2)新建业务逻辑控制器Action用来处理多文件上传。因为上面的两个文本域有相同的name属性,这样就可以使用数组类型的属性封装这两个文本域。3个数组类型的属性分别用来封装上传文件、上传文件类型、上传文件名,代码如下所示。
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; private String savePath; //获得上传文件保存目录 public String getSavePath() { return savePath; } //设置上传文件保存目录 public void setSavePath(String savePath) { this.savePath = savePath; } //获得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; } //获得username值 public String getUsername() { return username; } //设置username值 public void setUsername(String username) { this.username = username; } public String execute() throws Exception { //取得用来上传的文件数组 File[] files = getMyFile(); //循环每个上传的文件 for (int i = 0; i < files.length; i++) { //基于file[i]创建一个文件输入流 InputStream is = new FileInputStream(files[i]); // 设置上传文件目录 String uploadPath = ServletActionContext.getServletContext() .getRealPath(getSavePath()); // 设置目标文件 File toFile = new File(uploadPath, getMyFileFileName()[i]); // 输出流 OutputStream os = new FileOutputStream(toFile); //设置缓存 byte[] buffer = new byte[1024]; int length = 0; //读取file[i]文件输出到toFile文件中 while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } //关闭输入流 is.close(); //关闭输出流 os.close(); } return SUCCESS; } }
7.4.2 测试使用数组实现上传多个文件
打开用户输入页,填写用户名并选择文件进行上传,如图7.26所示。
页面跳转到结果输出页。页面中显示了用户名以及上传的文件名,如图7.27所示。
图7.26 用户输入页
图7.27 结果显示页
下面打开文件上传目录upload02,在该目录中可以看到刚才上传的文件,如图7.28所示。
这里要注意的是,通过拦截器配置的文件最大值只是针对一个文件来说。比如,配置的文件大小的最大值为50KB,虽然上传的两个文件大小加起来大于50KB,但是同样可以完成上传。
如果需要配置所有文件和的最大值,可以在“struts.xml”文件中配置struts.multipart.maxSize常量,改变其默认大小,代码如下所示。
<constant name="struts.multipart.maxSize" value="20721520"></constant>
如果其中有一个上传文件不符合要求,那么所有的文件都不会被上传。页面将跳转回用户输入页,并提示输入错误信息,如图7.29所示。如果有多个文件不符合要求,将输出多条错误信息,如图7.30所示。
图7.28 上传目录upload02
图7.29 输出错误提示信息(1)
7.4.3 使用List实现上传多个文件
图7.30 输出错误提示信息(2)
这里还可以使用List来处理多个文件的上传,这种方式和使用数组基本类似。只需要将使用数组类型封装文件域中的数组类型替换成List类型就可以了,修改代码如下所示。
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 java.util.List; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class UploadAction extends ActionSupport { // username属性用来封装用户名 private String username; // myFile属性用来封装所有上传的文件 private List<File> myFile; // myFileContentType属性用来封装所有上传文件的类型 private List<String> myFileContentType; // myFileFileName属性用来封装所有上传文件的文件名 private List<String> myFileFileName; private String savePath; //获得上传文件保存目录 public String getSavePath() { return savePath; } //设置上传文件保存目录 public void setSavePath(String savePath) { this.savePath = savePath; } //获得myFile值 public List<File> getMyFile() { return myFile; } //设置myFile值 public void setMyFile(List<File> myFile) { this.myFile = myFile; } //获得myFileContentType值 public List<String> getMyFileContentType() { return myFileContentType; } //设置myFileContentType值 public void setMyFileContentType(List<String> myFileContentType) { this.myFileContentType = myFileContentType; } //获得myFileFileName值 public List<String> getMyFileFileName() { return myFileFileName; } //设置myFileFileName值 public void setMyFileFileName(List<String> myFileFileName) { this.myFileFileName = myFileFileName; } //获得username值 public String getUsername() { return username; } //设置username值 public void setUsername(String username) { this.username = username; } public String execute() throws Exception { //取得用来上传的文件数组 List<File> files = getMyFile(); //循环每个上传的文件 for (int i = 0; i < files.size(); i++) { //基于file[i]创建一个文件输入流 InputStream is = new FileInputStream(files.get(i)); // 设置上传文件目录 String uploadPath = ServletActionContext.getServletContext() .getRealPath(getSavePath()); // 设置目标文件 File toFile = new File(uploadPath, getMyFileFileName().get(i)); // 输出流 OutputStream os = new FileOutputStream(toFile); //设置缓存 byte[] buffer = new byte[1024]; int length = 0; //读取file[i]文件输出到toFile文件中 while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } //关闭输入流 is.close(); //关闭输出流 os.close(); } return SUCCESS; } }