本篇文章主要介绍如何利用struts2进行文件的上传及下载,同时给出我在编写同时所遇到的一些问题的解决方案。
文件上传
前端页面
1 <!-- 引入struts标签 --> 2 <%@taglib prefix="s" uri="/struts-tags"%> 3 4 <!-- 5 使用struts中的<s:file></s:file>标签来选择文件。 6 设置name属性,则提交后将传递后给后台一个name属性值(upload)的文件类型的文件。 7 同时,将随同传递该文件的名字(uploadFileName)及文件类型(uploadContentType) 8 表单中增加编码格式(enctype)为multipart/form-data 9 --> 10 <form action="upload" enctype="multipart/form-data" method="post"> 11 <s:file name="upload" label="Select File"/> 12 <button type="submit">Submit</button> 13 </form>
struts.xml
1 <!-- 指定上传的文件暂时保存的位置 --> 2 <constant name="struts.multipart.saveDir" value="/tmp"/> 3 <package name="default" extends="struts-default"> 4 <!-- 上传文件action --> 5 <action name="home"> 6 <result>/WEB-INF/content/home.jsp</result> 7 </action> 8 <action name="upload" class="com.wsy.action.UploadAction"> 9 <!-- 引入拦截器 --> 10 <interceptor-ref name="fileUpload"> 11 <!-- 文件允许类型,可自行搜索查表,未指定则为默认所有类型 --> 12 <param name="allowedTypes">image/jpeg,image/gif,text/plain</param> 13 <!-- 文件最大大小 --> 14 <param name="maximumSize">1024*1024</param> 15 </interceptor-ref> 16 <!-- 一定要引入defaultStack,否则将无法提交数据至后台 --> 17 <interceptor-ref name="defaultStack"></interceptor-ref> 18 <!-- 上传成功,返回首页 --> 19 <result type="redirect">home.action</result> 20 <!-- 上传不成功,设置input逻辑视图,进入报错页面 --> 21 <result name="input">/WEB-INF/content/error.jsp</result> 22 </action> 23 </package>
文件上传action
1 package com.wsy.action; 2 3 import java.io.*; 4 5 import org.apache.struts2.ServletActionContext; 6 7 import com.opensymphony.xwork2.ActionSupport; 8 9 public class UploadAction extends ActionSupport { 10 private File upload; // 上传的文件 11 private String uploadContentType; // 上传的文件的类型 12 private String uploadFileName; // 上传的文件的名字 13 14 public File getUpload() { 15 return upload; 16 } 17 18 public void setUpload(File upload) { 19 this.upload = upload; 20 } 21 22 public String getUploadContentType() { 23 return uploadContentType; 24 } 25 26 public void setUploadContentType(String uploadContentType) { 27 this.uploadContentType = uploadContentType; 28 } 29 30 public String getUploadFileName() { 31 return uploadFileName; 32 } 33 34 public void setUploadFileName(String uploadFileName) { 35 this.uploadFileName = uploadFileName; 36 } 37 38 @Override 39 public String execute() throws Exception 40 { 41 String path = ServletActionContext.getServletContext().getRealPath("/WEB-INF/uploadFiles"); 42 File file = new File(path); 43 // 创建文件保存文件夹 44 if (!file.exists()) 45 file.mkdirs(); 46 FileOutputStream fos = new FileOutputStream(path + File.separator + getUploadFileName()); 47 FileInputStream fis = new FileInputStream(getUpload()); 48 byte[] buffer = new byte[1024]; 49 int len = 0; 50 while ((len = fis.read(buffer)) > 0) { 51 fos.write(buffer , 0 , len); 52 } 53 fis.close(); 54 fos.close(); 55 return SUCCESS; 56 } 57 }
原理:Struts2文件上传通过将HTTP上传的数据先保存到临时文件夹(本文中为/tmp),然后使用fileUpload拦截器将文件绑定到Action的实例中,从而就能够以本地文件方式的操作浏览器上传的文件,将其保存到服务器下的特定位置。
文件下载
前端页面
1 <ol> 2 <% 3 String[] filelist = (String[])request.getSession().getAttribute("filelist"); 4 if (filelist != null) { 5 for (int i = 0; i < filelist.length; i++) { 6 %> 7 <li><a href="download.action?filename=<%=filelist[i]%>"><%=filelist[i]%></a></li> 8 <% 9 } 10 } else { 11 %> 12 <li>无文件</li> 13 <% } %> 14 </ol>
struts.xml
1 <package name="download" extends="struts-default"> 2 <!-- 下载文件action --> 3 <action name="download" class="com.wsy.action.DownloadAction"> 4 <result name="success" type="stream"> 5 <param name="contentType">image/jpeg,image/gif,text/plain</param> 6 <!-- 获取输入流,根据值调用相应的get方法 --> 7 <param name="inputName">targetFile</param> 8 <!-- 9 contentDisposition是文件下载的处理方式,包括内联(inline)和附件(attachment),默认是inline。 10 使用附件时这样配置:attachment;filename="文件名" 。 11 --> 12 <param name="contentDisposition">attachment;filename="${filename}"</param> 13 <param name="bufferSizbe">1024*1024</param> 14 </result> 15 </action> 16 </package>
文件下载action
1 package com.wsy.action; 2 3 import java.io.InputStream; 4 5 import org.apache.struts2.ServletActionContext; 6 import com.opensymphony.xwork2.ActionSupport; 7 8 public class DownloadAction extends ActionSupport { 9 private String filename; 10 11 public String getFilename() { 12 return filename; 13 } 14 15 public void setFilename(String filename) { 16 this.filename = filename; 17 } 18 19 public InputStream getTargetFile() throws Exception { 20 InputStream in = ServletActionContext.getServletContext().getResourceAsStream("/WEB-INF/uploadFiles/" + this.getFilename()); 21 return in; 22 } 23 24 public String execute() throws Exception { 25 return SUCCESS; 26 } 27 }
原理:同Servlet和HTTP协议时的文件下载。
出现的问题
1 上传文件时,
严重: Exception occurred during processing request: /Users/apple/Documents/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Union/WEB-INF/uploadFiles/acm.txt (No such file or directory) java.io.FileNotFoundException: /Users/apple/Documents/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Union/WEB-INF/uploadFiles/acm.txt (No such file or directory)
原因:设置放在uploadFiles文件夹下,但uploadFiles文件夹不存在,所以抛出文件不存在异常。
解决方案:在上传文件的action创建文件输出流之前,先检测该文件夹是否存在,若不存在则创建。
2 下载文件时,
严重: Exception occurred during processing request: Can not find a java.io.InputStream with the name [targetFile] in the invocation stack. Check the <param name="inputName"> tag specified for this action. java.lang.IllegalArgumentException: Can not find a java.io.InputStream with the name [targetFile] in the invocation stack. Check the <param name="inputName"> tag specified for this action.
原因:
(1)struts.xml中返回中的inputName的值与action中的方法名不对应。
(2)文件为不允许类型或超出文件设定大小。
(3)action中创建文件输入流时传入的路径错误。
(4)文件名中含有中文字符,则导致无法创建文件输入流。
解决方案:
针对(1)~(3),仔细检查。
针对(4),在setFilename()方法返回时对文件名进行处理,
1 public void setFilename(String filename) throws UnsupportedEncodingException { 2 this.filename = new String(filename.getBytes("ISO8859-1"), "utf-8"); 3 }
而做了如上处理后,虽然没有异常被抛出,但发现在下载含中文字符的文件时,下载的文件的文件名仍然时乱码。
所以就在Action中另添加一个方法。
1 public String getDownloadFilename() throws UnsupportedEncodingException { 2 return new String(filename.getBytes(), "ISO9959-1"); 3 }
并将struts.xml中result中的contentDisposition的值改为对象的值。
1 <param name="contentDisposition">attachment;filename="${downloadFilename}"</param>
以上即为全部内容,欢迎提出问题和建议!