程序员人生 网站导航

Struts2学习(八)—文件上传和下载

栏目:综合技术时间:2016-08-11 08:43:16

在做B/S系统时,通常会触及到上传文件和下载文件,在没接struts2框架之前,我们都是使用apache下面的commons子项目的FileUpload组件来进行文件的上传,但是那样做的话,代码看起来比较繁琐,而且不灵活,在学习了struts2后,struts2为文件上传下载提供了更好的实现机制,在这里我分别就单文件上传和多文件上传的实现进行1下讲授,这里
我们使用的struts2 web项目所导入的jar包中的**commons-fileupload⑴.3.1.jar
commons-io⑵.2.jar**是struts2实现上传下载所使用的类库

struts2单文件上传

原理

  • 确保 HTML设置了 enctype和指定了1个活多个 file type input.

jsp页面表单的书写格式

<form name="myForm" enctype="multipart/form-data"> <input type="file" name="myDoc" value="Browse ..." /> <input type="submit" /> </form>
  • 确保 Action提供1个或多个 fileUpload 只读(mutator )方法, 并且方法名t与 file type input名称相干.
public void setMyDoc(File myDoc) public void setMyDocContentType(String contentType) public void setMyDocFileName(String filename)
  • Action 可能提供相干联的访问器方法 .
public File getMyDoc() public String getMyDocContentType() public String getMyDocFileName()

示例

首先是1个jsp文件上传页面,这个比较简单,就是1个表单,里面有个文件上传框

<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF⑻"> <title>Insert title here</title> </head> <body> <!--在进行文件上传时,表单提交方式1定要是post的方式,由于文件上传时2进制文件可能会很大,还有就是enctype属性,这个属性1定要写成multipart/form-data,   不然就会以2进制文本上传到服务器端--> <form action="upload" method="post" enctype="multipart/form-data"> 上传文件:<input name="photo" type="file"><br> <input type="submit"> </form> </body> </html>

接下来是FileUploadAction部份代码,由于struts2对上传和下载都提供了很好的实习机制,所以在action这段我们只需要写很少的代码就行:
FileUploadAction.java

package com.lgh.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.UUID; import org.apache.commons.io.IOUtils; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import sun.nio.ch.IOUtil; public class FileUploadAction extends ActionSupport { private static final long serialVersionUID = 1L; private File photo; private String photoContentType; private String photoFileName; @Override public String execute() throws Exception { InputStream is = new FileInputStream(photo); String path = ServletActionContext.getServletContext().getRealPath("/upload"); String ext = photoFileName.substring(photoFileName.lastIndexOf(".")+1); System.out.println(ext); String filePath = path+"/"+UUID.randomUUID()+"."+ext; OutputStream os = new FileOutputStream(filePath); System.out.println(path); IOUtils.copy(is, os); os.close(); is.close(); return super.execute(); } public File getPhoto() { return photo; } public void setPhoto(File photo) { this.photo = photo; } public String getPhotoContentType() { return photoContentType; } public void setPhotoContentType(String photoContentType) { this.photoContentType = photoContentType; } public String getPhotoFileName() { return photoFileName; } public void setPhotoFileName(String photoFileName) { this.photoFileName = photoFileName; } }

上传成功的页面

<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <%@ taglib uri="/struts-tags" prefix="s" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF⑻"> <title>Insert title here</title> </head> <body> <s:debug></s:debug> </body> </html>

action配置

<action name="upload*" class="com.lgh.struts2.action.FileUpload{1}Action" method="execute"> <result name="success">/upload_sucess.jsp</result> </action>

测试
这里写图片描述
提交落后入上传文件夹中:
这里写图片描述

处理多个文件

当通过1个表单上传多个文件, 文件用数组来表示.

原理 

给定:

<form name="myForm" enctype="multipart/form-data"> <input type="file" name="myDoc" value="Browse File A ..." /> <input type="file" name="myDoc" value="Browse File B ..." /> <input type="file" name="myDoc" value="Browse File C ..." /> <input type="submit" /> </form>

Action 类定义了文件处理方法,这些方法接收数组参数.

public void setMyDoc(File[] myDocs) public void setMyDocContentType(String[] contentTypes) public void setMyDocFileName(String[] fileNames)

通过迭代数组来处理多个文件上传.

示例

fileuploadMuti.jsp

<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF⑻"> <title>Insert title here</title> </head> <body> <form action="uploadMuti" method="post" enctype="multipart/form-data"> 上传文件:<input name="photo" type="file"><br> 上传文件:<input name="photo" type="file"><br> <input type="submit"> </form> </body> </html>

FileUploadMutiAction.java

package com.lgh.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.UUID; import org.apache.commons.io.IOUtils; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import sun.nio.ch.IOUtil; public class FileUploadMutiAction extends ActionSupport { private static final long serialVersionUID = 1L; private File[] photo; private String[] photoContentType; private String[] photoFileName; @Override public String execute() throws Exception { for (int i = 0; i < photo.length; i++) { InputStream is = new FileInputStream(photo[i]); String path = ServletActionContext.getServletContext().getRealPath("/upload"); String ext = photoFileName[i].substring(photoFileName[i].lastIndexOf(".")+1); System.out.println(ext); String filePath = path+"/"+UUID.randomUUID()+"."+ext; OutputStream os = new FileOutputStream(filePath); System.out.println(path); IOUtils.copy(is, os); os.close(); is.close(); } return super.execute(); } public File[] getPhoto() { return photo; } public void setPhoto(File[] photo) { this.photo = photo; } public String[] getPhotoContentType() { return photoContentType; } public void setPhotoContentType(String[] photoContentType) { this.photoContentType = photoContentType; } public String[] getPhotoFileName() { return photoFileName; } public void setPhotoFileName(String[] photoFileName) { this.photoFileName = photoFileName; } }

action配置:

<action name="upload*" class="com.lgh.struts2.action.FileUpload{1}Action" method="execute"> <result name="success">/upload_sucess.jsp</result> </action>

测试:
这里写图片描述
提交后
这里写图片描述

额外信息

属性 默许值
struts.multipart.parser 使用Commons FileUpload 框架
struts.multipart.saveDir 容器定义的javax.servlet.context.tempdir
设置上传文件的最大值
struts.multipart.maxSize 大约2M

文件下载

参数

文件上传后我们还需要将其下载下来,其实struts2的文件下载原理很简单,就是定义1个输入流,然后将文件写到输入流里面就行,关键配置还是在struts.xml这个配置文件里配置以下参数:

  • contentType - 告知阅读器的流的 mime-type (默许 = text/plain).

  • contentLength - 按字节计算的流长度(阅读器显示进度条).

  • contentDisposition -内容的 disposition 头值来指定文件的名称 (默许 = inline, 值通常是 attachment;filename=”document.pdf”.

  • inputName - the name of the InputStream property from the chained action (默许 = inputStream).

  • bufferSize - 从输入往输出拷贝时缓存的大小 (默许 = 1024).

  • allowCaching -如果设置为 ‘false’ 将设置头 ‘Pragma’ 和 ‘Cache-Control’为’no-cahce’, 并禁止客户端缓存该内容. (默许= true)

  • contentCharSet -如果设置为字符串, ‘;charset=value’ 将添加到 content-type 头. 如果为1个表达式, 将使用计算的结果. 如果没有设置, 将不添加字符编码到头
    这些参数通过提供与参数名字相同的 getter 方法来设置到你的 Action. 例如, 你可以提供1个 getContentType() 方法来覆盖当前action的参数.

示例-固定下载

准备的文件:
这里写图片描述
文件下载不需要jsp页面,我们先配置action,这类方式是把下载文件写死的方式,不可用任意下载:

<action name="download" class="com.lgh.struts2.action.FileDownloadAction" method="execute"> <result name="success" type="stream"> <param name="contentType">image/jpeg</param> <param name="inputName">is</param> <param name="contentDisposition">attachment;filename="123.jpg"</param> <param name="bufferSize">1024</param> </result> </action>

action类:
FileDownloadAction.java

package com.lgh.struts2.action; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class FileDownloadAction extends ActionSupport { private static final long serialVersionUID = 1L; public InputStream getIs() throws FileNotFoundException{ //文件下载时我们需要1个输入流来读取文件,其他的输出struts2会帮我们创建 return new FileInputStream(ServletActionContext. getServletContext().getRealPath("/download")+"/123.jpg"); } }

测试:
这里写图片描述
经测试下载成功

示例-任意下载

有时候我们的下载其实不固定格式,比如txt和jpg是两种不同的格式,123.txt和456.txt下载文件的名字也不相同,这时候我们的struts2.xml中的action配置就不能写死了,我们需要使它能根据传递过来的文件名不同动态的生成1些配置参数的值:
比如:通过OGNL表达式从文件下载action类中通过get方法得到值

<action name="downloadX" class="com.lgh.struts2.action.FileDownloadXAction" method="execute"> <result name="success" type="stream"> <param name="contentType">${contentType}</param> <param name="inputName">is</param> <param name="contentDisposition">attachment;filename="${f}"</param> <param name="bufferSize">1024</param> </result> </action>

这时候我们就要在相应的action类中创建get方法了
FileDownloadXAction.java

package com.lgh.struts2.action; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class FileDownloadXAction extends ActionSupport { private static final long serialVersionUID = 1L; private String f; private String contentType; public InputStream getIs() throws FileNotFoundException{ System.out.println(ServletActionContext.getServletContext().getMimeType(f)); return new FileInputStream(ServletActionContext. getServletContext().getRealPath("/download")+"/"+f); } public String getF() throws UnsupportedEncodingException { return f; } public void setF(String f) { /* * 在 tomcat7 中从get要求获得参数是若包括中文, * 则会发现中文乱码现象 * 由于阅读器传送来的数据是以utf⑻编码的,在服务器tomcat则以iso⑻859⑴解码 * 产生了乱码,下面代码可以解决该问题 * new String(f.getBytes("ISO⑻859⑴"),"UTF⑻"); * */ this.f = f; } public String getContentType() { System.out.println(f); System.out.println(ServletActionContext.getServletContext().getMimeType(f)); return ServletActionContext.getServletContext().getMimeType(f); } }

测试
下载文件名非中文的
这里写图片描述
成功没有问题
下载中文名字文件
火狐阅读器:
这里写图片描述
谷歌阅读器:
这里写图片描述
这里写图片描述
我们看到在下载中文的文件时,文件名都出现了毛病
这是由于:阅读器在响应头中不允许中文存在 我们下载时必须content-disposition头中设置1些下载信息这时候如果我们要下载的文件包括中文,那末我们就必须进行编码
修改getF()方法:

public String getF() throws UnsupportedEncodingException { /* * 阅读器在响应头中不允许中文存在 * 我们下载时必须在content-disposition头中设置1些下载信息 * 这时候如果我们要下载的文件包括中文,那末我们就必须进行编码 *设置 URLEncoder.encode(name, "utf⑻") 对ie 谷歌 已可以了, *但是对火狐依然有1些问题 *;filename*=utf-8''"+ URLEncoder.encode(name, "utf-8") *用于就解决火狐阅读器的问题 *我们在struts2.xml通过配置的方式也能够到达以下功能 * */ /* * 这时候我们不使用struts2框架下载时所需要设置的响应头 * response.setHeader("content-disposition", "attachment;filename=\""+ URLEncoder.encode(name, "utf⑻")+"\";filename*=utf⑻''"+ URLEncoder.encode(name, "utf⑻")); * */ return URLEncoder.encode(f, "utf⑻"); }

测试:
这里写图片描述
这里写图片描述
火狐阅读器测试:
这里写图片描述
解决
但是对火狐依然有1些问题
不使用框架则以下代码 用于就解决火狐阅读器的问题
;filename*=utf⑻””+ URLEncoder.encode(name, “utf⑻”)
我们在struts2.xml通过配置的方式也能够到达以下功能
这里写图片描述
这时候问题解决了:
这里写图片描述

总结

总的来讲,struts2提供的文件上传下载机制简化了我们很多代码,我们可以在以后的项目中使用该机制,一样我们也能够使用FileUpload组件来进行文件的上传,这个都是因个人爱好决定!

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐