struts2文件的上传下载

singing 贡献于2014-01-01

作者 User  创建于2013-11-18 01:04:00   修改者User  修改于2014-01-02 02:42:00字数15662

文档摘要: 概述在开发基于Web的应用的时候,经常会碰到需要实现文件上传、下载的功能,比如编辑某个商品,需要给它上传一个图片等等。不使用Struts2的话,可以有很多种方式来实现文件上传,比如使用Apache的Common-FileUpload等。但是这些传统的方式,实现起来非常麻烦,需要写很多代码来进行控制。现在使用Struts2来实现文件上传的功能,会更加简单和方便,事实上,Struts2的文件上传功能,默认就是基于Common-FileUpload来实现的,只不过比直接使用Common-FileUpload来得更简单。
关键词:

文章内容来自Java私塾2013-12-27 struts2文件的上传下载 13.1  文件上传 13.1.1  概述 在开发基于Web的应用的时候,经常会碰到需要实现文件上传、下载的功能,比如编辑某个商品,需要给它上传一个图片等等。 不使用Struts2的话,可以有很多种方式来实现文件上传,比如使用Apache的Common-FileUpload等。但是这些传统的方式,实现起来非常麻烦,需要写很多代码来进行控制。 现在使用Struts2来实现文件上传的功能,会更加简单和方便,事实上,Struts2的文件上传功能,默认就是基于Common-FileUpload来实现的,只不过比直接使用Common-FileUpload来得更简单。 13.1.2使用Struts2实现文件上传 1:fileUpload拦截器        使用Struts2来实现文件上传,需要使用Struts2预定义的fileUpload拦截器。简要的看看在struts-default.xml中的配置,示例如下:   java代码: 查看复制到剪贴板打印 1.    2.     …   3.        4.         …   5.            7.         …   8.            9.             …   10.                11.             …   12.            13.       14.    15.       16.    更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 上面列出了struts-default.xml中跟fileUpload拦截器有关的部分。首先,Struts2有一个预定义拦截器叫fileUpload;然后,defaultStack拦截器栈引用了fileUpload拦截器;最后,struts-default包又将defaultStack拦截器声明为自己的默认拦截器引用。 因此,如果我们的包继承了struts-default包,而我们的Action类又没有声明自己的拦截器引用的话,使用的就是defaultStack拦截器栈,从而引用了fileUpload拦截器。 2:实现上传页面        如果一个表单中,包含了文件上传的表单域,则一定要把整个表单enctype属性设置为multipart/form-data。形如:   java代码: 查看复制到剪贴板打印 1. <%@ page language="java" contentType="text/html; charset=gb2312"   2.     pageEncoding="gb2312"%>   3.    5.    6.    7.    8. Insert title here   9.    10.    11.    13.     文件名称:
   14.     文件:
   15.        16.    17.    18.    在这个文件里,指定了
元素的enctype属性为multipart/form-data,还用了一个type为file的输入域,它会在页面上生成一个文件选择框。整个页面运行如下: 更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 图13.1 文件上传页面 在这个页面上文件域里面,在输入框后面多了一个“浏览”按钮,点击这个浏览按钮,就会弹出文件选择框。 3:实现文件上传Action        这个Action和其他的Action没有太多特殊之处,使用一个String属性fileName来准备接收前一个页面的fileName文本框的值,然后使用一个File属性myFile来准备接收前一个页面的myFile文件框传过来的文件的值。 在execute方法中,我们可以随意存储上传的文件,本例只是把它放到了e盘的temp目录下,并以传入的fileName作为保存的文件名。 示例代码如下:   java代码: 查看复制到剪贴板打印 1. public class UploadAction extends ActionSupport{   2.     private String fileName;   3.     private File myFile;   4.        5.     public String getFileName() {   6.         return fileName;   7.     }   8.     public void setFileName(String fileName) {   9.         this.fileName = fileName;   10.     }   11.     public File getMyFile() {   12.         return myFile;   13.     }   14.     public void setMyFile(File myFile) {   15.         this.myFile = myFile;   16.     }   17.        18.     public String execute()throws Exception{   更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 19.         //先把上传过来的文件存放到e盘temp目录下,以传入的fileName为名字   20.         OutputStream output = null;   21.         InputStream input = null;   22.         try{   23.             output = new FileOutputStream("e:/temp/"+fileName);   24.             //建立一个1k大小的缓冲区   25.             byte[] bs = new byte[1024];   26.                27.             //将上传过来的文件输出到output中   28.             input = new FileInputStream(myFile);   29.             int length = 0;   30.             //length=input.read(bs)这句话中,length=-1代表了读到文件结尾   31.             while ((length=input.read(bs))>0){   32.                 output.write(bs, 0, length);   33.             }   34.         }finally{   35.             input.close();   36.             output.close();   37.         }          38.         return SUCCESS;   39.     }   40. }   注意:如何操作上传的文件,完全是I/O的知识,为了保持实例的简单,只是采用了最简单的方式,把内容存放在一个绝对路径表示的文件里面,当然还可以将上传的文件存储在web服务器上,甚至数据库中。 4:映射这个Action        在struts.xml中对这个Action进行配置,可以看到没有任何特异之处,只是指出了Action名称和对应的实现类,以及上传之后要跳转到的页面。   java代码: 查看复制到剪贴板打印 1.    2.        3.         /fileupload/success.jsp   4.        5.    5:上传之后的页面        由于上传的文件在Action中已经被正确处理了,所以这个上传之后的页面没有任何特殊的作用,只是显示一下,表示上传成功了,示例代码如下:   更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 java代码: 查看复制到剪贴板打印 1. <%@ page language="java" contentType="text/html; charset=gb2312"   2.     pageEncoding="gb2312"%>   3. <%@taglib prefix="s" uri="/struts-tags" %>   4.    6.    7.    8.    9. Insert title here   10.    11.    12.     成功上传文件   13.    14.    运行测试一下,在文件上传页面选择要上传的文件,然后点击提交按钮,会发现文件会上传,并以我们指定的文件名称保存到我们指定的文件夹下去了。 13.1.3获取文件的更多信息 Struts2支持用更多的属性来获取有关上传文件的真实文件名和文件类型。 比如:表单中包含了一个叫xyz的文件域,也就是类似于0){   50.                 output.write(bs, 0, length);   51.             }   52.         }finally{   更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 53.             input.close();   54.             output.close();   55.         }          56.         return SUCCESS;   57.     }   58. }   运行测试一下,后台输出为:   java代码: 查看复制到剪贴板打印 1. 用户传入的文件名:aaa   2. 上传文件的真实文件名:filelist.xml   3. 上传文件的类型:text/xml   4. 这个文件的文件名是什么?upload__5ab75acc_12c5f17ac7a__8000_00000001.tmp   注意其中“这个文件的文件名是什么?”,代码写的是输出myFile这个File对象的名字,由于myFile对象封装了上传文件的内容,因而某些朋友就认为这个文件就是我们上传的文件,从而认为它的getName方法就是返回的上传的这个文件的名字。 这是错误的,这个myFile文件是Struts2在上传过程中生成的临时文件,它的内容与上传文件相同,但是名字并不相同,它的名字是由Struts2临时生成的,形如“upload__5ab75acc_12c5f17ac7a__8000_00000001.tmp”这样的。 13.1.4限制文件的大小及类型 在文件上传的时候,有可能需要对文件的大小和类型做出限制。Struts2支持直接在fileUpload拦截器上设置参数来进行限制。        在引用fileUpload拦截器的时候,可以指定三个参数(指定子元素): · allowedTypes:指定允许上传的文件的类型,如果存在多种类型,以逗号隔开。注意:这里添的不是文件的扩展名,而是对应的ContentType,如果不知道某种文件的ContentType可以先上传一下试试,在后台输出ContentType来。 · maximumSize:指定允许上传的文件的最大字节数。 · allowedExtensions:指定允许上传的文件的扩展名。 如果上传的文件不满足以上的参数指定的条件,则会跳转到一个叫input的上,一般input都会指回到提交之前的页面,也就是文件上传页面。 参数非常简单,但是配置比较怪异,fileUpload拦截器虽然在defaultStack拦截器栈上已经引用了,但是还可以在defaultStack拦截器栈之前再引用一次,然后在这次引用上指定参数,示例代码如下:   java代码: 查看复制到剪贴板打印 1.    2.        更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 3.            4.             text/plain   5.             1000   6.            7.            8.            9.         /fileupload/fileupload.jsp   10.         /fileupload/success.jsp   11.        12.    观察以上的元素,要额外注意两点: · 这个Action应该先引用fileUpload拦截器,然后引用defaultStack拦截器栈。 · 这个Action中还要有一个叫input的,以备上传不成功时,Struts2跳转到提交前的页面。 还要稍微修改一下login.jsp,来显示不满足限制条件时的错误信息。只需要在合适的地方加上来显示错误信息即可。形如:   java代码: 查看复制到剪贴板打印 1. <%@ page language="java" contentType="text/html; charset=gb2312"   2.     pageEncoding="gb2312"%>   3.    5.    6.    7.    8. Insert title here   9.    10.    11. <%@taglib prefix="s" uri="/struts-tags" %>   12.    13.    15.     文件名称:
   16.     文件:
   17.        18.    19.    20.    运行修改之后的文件上传功能,如果上传非txt文件,运行结果如下: 更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 图13.2 fileUpload拦截器限制文件上传类型        如果上传大于1000字节的txt文件,运行结果如下: 图13.3 fileUpload拦截器限制文件上传大小 13.1.5上传超大的文件 Struts2在实现文件上传的时候,还有一个小问题,那就是默认上传文件的大小是不能超过2097152字节的。这个配置在struts2-core-2.1.8.1.jar文件里面,“\org\apache\struts2”文件夹下的default.properties文件里面,配置如下:   java代码: 查看复制到剪贴板打印 更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 1. struts.multipart.maxSize=2097152   先来测试一下,看看是不是有这个问题。到文件上传页面,选择一个超过上述字节数的文件来上传看看,点击提交按钮,后台输出错误,示例如下:   java代码: 查看复制到剪贴板打印 1. org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (3402567) exceeds the configured maximum (2097152)   2.     at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.(FileUploadBase.java:914)   3.     ......   注意上面加粗的那句话,明确告诉我们,上传的文件大小为3402567,大于配置的最大值2097152字节。        那么该怎么办呢?        方法很简单,只要覆盖这个默认设置就可以了,有两种方式,一种是在Struts.properties里面配置,另外一种就是在struts.xml里面配置。这里就以在struts.xml来配置为例,只要在struts.xml中加入如下的常量定义,示例代码如下:   java代码: 查看复制到剪贴板打印 1.    设置上传文件的最大值为大约10M。再次测试运行看看,应该就可以正常上传了。 13.1.6在一个表单中上传多个文件 在实际开发中,经常会碰到需要在一个表单中上传多个文件的情况,比如为某文档添加附件,就可能要求在一个表单上添加多个附件。 对于在一个表单中上传多个文件的功能,使用Struts2也能轻松实现。只需要在提交页面上添加同名的多个文件输入域,然后在Action中对应使用File类型的数组去接收这些参数即可。        比如上面的示例,可以把上传文件页面改为:   java代码: 查看复制到剪贴板打印 1. <%@ page language="java" contentType="text/html; charset=gb2312"   2.     pageEncoding="gb2312"%>   3.    5.    6.    7.    8. Insert title here   9.    10.    11. <%@taglib prefix="s" uri="/struts-tags" %>   12.    13.    15.     文件:
   16.     文件:
   17.     文件:
   18.     文件:
   19.        20.    21.    22.    上例中,
表单中有多个同名的file输入域myFile。        在Action中,只要使用数组或List来操作就可以了,这里以数组为例来修改Action,示例代码如下:   java代码: 查看复制到剪贴板打印 1. public class UploadAction extends ActionSupport{   2.     private File[] myFile;   3.     private String[] myFileFileName;   4.     public File[] getMyFile() {   5.         return myFile;   6.     }   7.     public void setMyFile(File[] myFile) {   8.         this.myFile = myFile;   9.     }   10.     public String[] getMyFileFileName() {   11.         return myFileFileName;   12.     }   13.     public void setMyFileFileName(String[] myFileFileName) {   14.         this.myFileFileName = myFileFileName;   15.     }   16.        17.     public String execute()throws Exception{   更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 18.         //把上传过来的文件存放到e盘temp目录下,以真实的文件名作为名字   19.         OutputStream output = null;   20.         InputStream input = null;   21.         try{   22.             for(int i=0;i0){   32.                     output.write(bs, 0, length);   33.                 }   34.             }   35.         }finally{   36.             input.close();   37.             output.close();   38.         }          39.         return SUCCESS;   40.     }   41. }   然后就可以去运行测试了,看看上面的实现是不是真的能同时上传多个文件。但是要提醒一点,如果想要上传不同类型的文件,记得把前面示例的时候,在struts.xml中所作的限制设定去掉。 13.2  文件下载 13.2.1概述 前面学习了文件上传的实现,接下来看看如何实现文件下载的功能。实现文件下载功能的方式也很多,这里只具体看看如何使用Struts2来实现文件下载。 使用Struts2来实现文件下载,会用到它的stream类型的Result,这种Result最终会返回一个InputStream,只需要让这个InputStream能读到用户想要下载的文件即可。 13.2.2 stream结果类型 先来回忆一下stream的结果类型出现在struts-default.xml中的配置,示例如下:   java代码: 查看复制到剪贴板打印 1.       2.           更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 3.         ...   4.               5.     ...   6.           7. ...   8.       既然stream是struts-default包中声明的一种内置结果类型,因而只要我们的包继承自struts-default包就可以使用这种结果类型了。 13.2.3实现文件下载的Action 使用stream类型作为Result的Action和普通的Action有很大的不同,它不需要execute方法;而是需要一个公有的,返回InputStream的getInputStream方法,这个方法用来返回文件的内容。示例代码如下: java代码: 查看复制到剪贴板打印 1. public class DownloadAction extends ActionSupport{   2.     public InputStream getInputStream() throws Exception{   3.         File file = new File("e:/temp/测试.doc");   4.         return new FileInputStream(file);   5.     }   6. }   在上面示例中,仅是简单的返回一个读取绝对路径下的文件的输入流。 13.2.4在struts.xml中配置Action 在struts.xml中,需要配置这个Action的后继页面为一个stream类型的Result。 java代码: 查看复制到剪贴板打印 1.    2.        3.            4.             attachment;filename="test.doc"   5.            6.        7.    更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 上面配置中,元素只有一个子元素,其类型为stream;但是元素有一个子元素指定了contentDisposition的值为attachment;filename="test.doc",这指明了在访问这个Result的时候,会弹出一个下载框,其中的默认文件名为test.doc。        stream类型的结果共可以指定7个参数: · contentType:下载文件的类型。 · contentLength:下载文件的长度,用于浏览器的进度条显示。 · contentDisposition:指定文件下载的默认名字,如果不指定则使用Action名.action。 · inputName:Action中用于返回InputStream的get方法的名字,默认为inputStream,因此,我们的Action中定义了getInputStream的方法。 · bufferSize:缓冲区大小,默认为1k。 · allowCaching:是否允许浏览器进行缓存。 · contentCharSet:HTTP响应头信息中的编码方式。 在以上7个参数中,最常用的是使用contentDisposition来指定默认的文件下载名,其他的使用默认即可。 13.2.5制作下载页面 现在还需要制作一个页面,在这个页面设置一个超链接,链接到下载的Action,示例代码如下:   java代码: 查看复制到剪贴板打印 1. <%@ page language="java" contentType="text/html; charset=gb2312"   2.     pageEncoding="gb2312"%>   3.    5.    6.    7.    8. Insert title here   9.    10.    11.     下载文件   12.    13.    测试运行一下,访问这个页面,点击上面的“下载文件”链接,就会弹出如下保存对话框,其默认文件名就是在struts.xml中配置的test.doc。 更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 图13.4 跳转到downloadAction后弹出的文件下载对话框 13.2.6难道只能在配置文件中写死文件名吗? 看到这里,可能有朋友会想:难道下载的文件名只能在配置文件struts.xml中写死吗?肯定不是的,首先把对应的配置信息去掉,看看Struts2是否能自适应文件名   java代码: 查看复制到剪贴板打印 1.    2.        3.                            4.            5.        6.    再次运行,弹出的文件对话框的下载文件名居然直接是“downloadAction.action”,就是action的名称,如下图所示: 更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 图13.5 跳转到downloadAction后弹出的文件下载对话框 看起来不设置contentDisposition属性这条路走不通。那么该怎么做才能让下载显示的文件名称不是写死的呢?        有两种解决的方式。一种就是在Action中提供一个返回文件名称的方法,然后在配置文件中引用这个变量;另外一种方法干脆就去掉配置文件中关于contentDisposition的配置,而直接在Action中提供一个getContentDisposition的方法。        接下来分别看看示例。 1:第一种实现方式        也就是在Action中提供一个返回文件名称的方法,然后在配置文件中引用这个变量,这一个实现方式。此时Action的实现,示例代码如下:   java代码: 查看复制到剪贴板打印 1. public class DownloadAction extends ActionSupport{   2.     public String getDownLoadFileName(){   3.         return "test.doc";   4.     }   5.     public InputStream getInputStream() throws Exception{   6.         File file = new File("e:/temp/测试.doc");   7.         return new FileInputStream(file);   8.     }   9. }   在这个Action的实现里面,并没有属性,而直接提供的getDownLoadFileName方法,这是因为OGNL对应访问的就是getter方法。        相应在struts.xml中的配置,示例如下:   更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 java代码: 查看复制到剪贴板打印 1.    2.        3.            4.             attachment;filename=${downLoadFileName}   5.            6.        7.    去运行测试看看,这是否能正确设置下载显示的文件名。 2:第二种实现方式        就是干脆就去掉配置文件中关于contentDisposition的配置,而直接在Action中提供一个getContentDisposition的方法,这样的一种方法。        此时Action的实现,示例代码如下:   java代码: 查看复制到剪贴板打印 1. public class DownloadAction extends ActionSupport{   2.     public String getContentDisposition(){   3.         return "attachment;filename=\"test3.doc\"";   4.     }   5.     public InputStream getInputStream() throws Exception{   6.         File file = new File("e:/temp/测试.doc");   7.         return new FileInputStream(file);   8.     }   9. }          相应在struts.xml中的配置,示例如下:   java代码: 查看复制到剪贴板打印 1.    2.        3.            更多内容在‘java私塾官网’ 文章内容来自Java私塾2013-12-27 4.            5.        6.    去运行测试看看,这种方式能不能正确设置下载显示的文件名。 13.2.7处理中文文件名 前面的示例,下载显示的都是英文文件名,那么如何让下载显示的是中文的文件名呢?        方法也很简单,就是在Action里面动态设置文件名称的时候,对其按照“ISO8859-1”进行编码,就可以了。        此时的Action,示例代码如下:   java代码: 查看复制到剪贴板打印 1. public class DownloadAction extends ActionSupport{   2.     public String getContentDisposition() throws UnsupportedEncodingException{   3.         String s = new String("测试".getBytes(),"ISO8859-1");   4.         return "attachment;filename=\""+s+".doc\"";   5.     }   6.     public InputStream getInputStream() throws Exception{   7.         File file = new File("e:/temp/测试.doc");   8.         return new FileInputStream(file);   9.     }   10. }   去运行测试看看,应该能正确显示中文的名称了,运行如下图所示: 图13.6  下载提示页面显示中文文件名 私塾在线网站原创《研磨struts2》系列 更多内容在‘java私塾官网’

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 3 金币 [ 分享文档获得金币 ] 1 人已下载

下载文档