Java程序员从笨鸟到菜鸟之(七十一)细谈struts2(十三)struts2实现文件上传和下载详解

长平狐 发布于 2012/11/12 11:42
阅读 544
收藏 0

       

           文件上传和文件下载是我们在web应用程序中常用的两个功能,在java中,实现这两种功能的方式也有很多种,其中struts2就给我们提供了一种算是比较简单的方式吧,下面我们就一起来看一下,首先我们来看文件上传:


 文件上传

         文件上传我们首先应该注意的是在上传页面的表单,这个表单也是有讲究的,由于我们提交表单的数据中有文件上传,所以这个表单的所使用的编码类型就不能是原来的了,在这里我们应该使用的编码方式是multipart/form-data并且数据提交方式要用post方式,下面我们具体来看一下:

Form.jsp

<form action="StudentAction!addStu" target="mainFrame" onsubmit="javascript:window.close()" method="post" 
enctype="multipart/form-data">
<table class="ta" width="200px">
<td>姓名</td>
<td><input type="text" name="stu.name" value="${request.stu_info.name }"/></td>
</tr>
<tr bgColor="#6fdd0">
<td>上传头像</td>
<td><input type="file" name="file" />
      	 </td>
</tr>
<tr bgColor="#6fdd0">
<td colspan="2"><input type="submit"  value="提交" class="buStyle"/>     <input type="reset"  value="重置" class="buStyle"/></td>
</tr>
</table>
</form>

     OK,看完表单以后我们就要来看一下action里面是怎么来接收这些数据的,其实也很简单,直接在action中定义三个变量,这三个变量分别是文件、文件名,还有文件类型,如下:

private File file;
private String fileFileName;
private String fileContentType;

        这三个变量的名字是有讲究的,不是随便命名就OK了,其中file这个变量名要和表单中文件的name要相同,fileFileName这个也是固定的,起名格式就是name+FileName,同样fileContentType也是如此,命名规则是name+ContentType,只有你按照命名规则来定义变量,struts2才能把文件上传相关信息收集起来。Ok,看完了变量设置,下面我们来看一下怎么struts2是怎么把文件上传到我们指定的位置的。那我们就先上代码,让代码帮我们来理解:

String root = ServletActionContext.getRequest().getRealPath("/upload");
try{
InputStream is = new FileInputStream(file);
// 创建一个文件,路径为root,文件名叫fileFileName
//自定义文件名	fileFileName="111"+fileFileName.substring(fileFileName.lastIndexOf("."));
File destFile = new File(root, fileFileName);
// 开始上传
OutputStream os = new FileOutputStream(destFile);
byte[] buffer = new byte[50000];
int length = 0;
// enctype="multipart/form-data"
while (-1 != (length = is.read(buffer))) {
os.write(buffer, 0, length);
}

      我们可以看到,就是简单的几行代码,其实并不难,他主要就是利用了IO流来实现的文件上传。单文件上传实现以后,多文件上传实现起来就不难了。


多文件上传

与单文件上传相似,Struts 2实现多文件上传也很简单。你可以使用多个<s:file />绑定Action的数组或列表。

< s:form action ="doMultipleUploadUsingList" method ="POST" enctype ="multipart/form-data" > 
    < s:file label ="File (1)" name ="upload" /> 
    < s:file label ="File (2)" name ="upload" /> 
    < s:file label ="FIle (3)" name ="upload" /> 
    < s:submit /> 
</ s:form >


如果你希望绑定到数组,Action的代码应类似:

   

  private File[] uploads;
     private String[] uploadFileNames;
     private String[] uploadContentTypes;

     public File[] getUpload() { return this .uploads; } 
     public void setUpload(File[] upload) { this .uploads = upload; } 
 
     public String[] getUploadFileName() { return this .uploadFileNames; } 
     public void setUploadFileName(String[] uploadFileName) { this .uploadFileNames = uploadFileName; } 
 
     public String[] getUploadContentType() { return this .uploadContentTypes; } 
     public void setUploadContentType(String[] uploadContentType) { this .uploadContentTypes = uploadContentType; }

如果你想绑定到列表,则应类似:


     

private List < File > uploads = new ArrayList < File > ();
     private List < String > uploadFileNames = new ArrayList < String > ();
     private List < String > uploadContentTypes = new ArrayList < String > ();

     public List < File > getUpload() {
         return this .uploads;
    } 
     public void setUpload(List < File > uploads) {
         this .uploads = uploads;
    } 
 
     public List < String > getUploadFileName() {
         return this .uploadFileNames;
    } 
     public void setUploadFileName(List < String > uploadFileNames) {
         this .uploadFileNames = uploadFileNames;
    } 
 
     public List < String > getUploadContentType() {
         return this .uploadContentTypes;
    } 
     public void setUploadContentType(List < String > contentTypes) {
         this .uploadContentTypes = contentTypes;
    }

    收集好数据之后,文件上传步骤就和上面单文件的一样了。在这就不重复了。好了,文件上传占时先说到这,下一步我们来看一下文件下载。

文件下载

          Struts 2中对文件下载做了直接的支持,相比起自己辛辛苦苦的设置种种HTTP头来说,现在实现文件下载无疑要简便的多。说起文件下载,最直接的方式恐怕是直接写一个超链接,让地址等于被下载的文件,例如:<a href=file1.zip> 下载file1.zip</a> ,之后用户在浏览器里面点击这个链接,就可以进行下载了。但是它有一些缺陷,例如如果地址是一个图片,那么浏览器会直接打开它,而不是显示保存文件的对话框。再比如如果文件名是中文的,它会显示一堆URL编码过的文件名例如%3457...。而假设你企图这样下载文件:http://localhost:8080/struts2/download/java程序员由笨鸟到菜鸟.doc ,Tomcat会告诉你一个文件找不到的404错误:HTTP Status 404 - /struts2hello/download/ϵͳ˵Ã÷.doc 。 所以在此我们就要用到struts 给我们提供的文件下载了。下面我们就一起来看一下struts2给我们提供的文件下载:

其实struts2提供给我们的文件下载已经非常简单化了,编写一个普通的Action就可以了,只需要提供一个返回InputStream流的方法,该输入流代表了被下载文件的入口,这个方法用来给被下载的数据提供输入流,意思是从这个流读出来,再写到浏览器那边供下载。这个方法需要由开发人员自己来编写,只需要返回值为InputStream即可 。首先我们来看一下jsp页面:

 <body>  
    <h1>文件下载</h1>  
    <!-- 下载链接 -->  
    <s:a action="down.action">download</s:a>  
  </body>  


页面很简单,就一下下载的链接,然后这个链接链接到我们的action中,下一步我们来看一下我们的action的编写:

public class DownAction extends ActionSupport {
     private static final long serialVersionUID = 1L;
    private String inputPath;
    public String getInputPath() {
        return inputPath;
    }
    public void setInputPath(String inputPath) {
        this.inputPath = inputPath;
    }
    /*
     * 下载用的Action应该返回一个InputStream实例,该方法对应在result里的inputName属性为
     * getDownloadFile
     */
    public InputStream getDownloadFile()
    {
        return ServletActionContext.getServletContext().getResourceAsStream(
        "/upload/Struts2.txt");
    }
    public String execute() throws Exception
    {
return SUCCESS;
}
}


下面我们在来看一下struts.xml的配置:

       

 <action name="down" class="cn.csdn.hr.up.action.DownAction">
            <!-- 配置结果类型为stream的结果 -->
            <result name="success" type="stream">
                <!-- 指定被下载文件的文件类型 -->
                <param name="contentType">text/plain </param>
                <!-- 指定下载文件的文件位置 -->
                <param name="contentDisposition">attachment;filename="Struts2.txt"</param>
                <param name="inputName">downloadFile</param>
            </result>
        </action>

这个action特殊的地方在于result的类型是一个流(stream ),配置stream类型的结果时,因为无需指定实际的显示的物理资源,所以无需指定location 属性,只需要指定inputName 属性,该属性指向被下载文件的来源,对应着Action类中的某个属性,类型为InputStream。下面则列出了和下载有关的一些参数列表:

参数说明

contentType

内容类型,和互联网MIME标准中的规定类型一致,例如text/plain代表纯文本,text/xml表示XMLimage/gif代表GIF图片,image/jpeg代表JPG图片

inputName

下载文件的来源流,对应着action类中某个类型为Inputstream的属性名,例如取值为inputStream 的属性需要编写getInputStream()方法

contentDisposition

文件下载的处理方式,包括内联(inline)和附件(attachment)两种方式,而附件方式会弹出文件保存对话框,否则浏览器会尝试直接显示文件。取值为:attachment;filename="struts2.txt" ,表示文件下载的时候保存的名字应为struts2.txt 。如果直接写filename="struts2.txt" ,那么默认情况是代表inline ,浏览器会尝试自动打开它,等价于这样的写法:inline; filename="struts2.txt"

bufferSize

下载缓冲区的大小

在这里面,contentType 属性和contentDisposition 分别对应着HTTP响应中的头Content-Type 和Content-disposition 头


当然,在很多的时候我们一般都不是把文件名写死在xml配置当中的,我们一般会在action中定义一个变量downfilename,储存这个文件名,然后再xml配置:

 <param name="contentDisposition">attachment;filename="${downloadFileName}"</param>

我们经常在中文下载中,出现文件名乱码的问题,这个问题是很多人都常见的,具体的很好的解决方法也没有,但我以前用的时候尝试着给他重新编码,这样可以解决大部分时候的中文下载乱码问题,但有时候也不行的。具体重新编码就是:

downFileName = new String(downFileName.getBytes(), "ISO8859-1");    

    好了,struts2文件上传和下载就简单介绍到这,文章中有什么不对或者错误的地方,欢迎大家指正。


原文链接:http://blog.csdn.net/csh624366188/article/details/7645224
加载中
0
隋济远
隋济远

请教个问题:

JS代码:

var K = new XMLHttpRequest()

K.open("POST", "file_uploadFile?fileSize=288", true);

K.setRequestHeader("Content-Type""multipart/form-data; boundary=" +

"------multipartformboundary"+ (new Date).getTime());

var G = new FormData();

G.append("file", E.getFile());

K.send(G);

Action中:

private File file;

private String fileFileName;

private String fileContentType;

调试FileUploadInterceptor时,发现:fileParameterNames.hasMoreElements()返回false

导致Action中的File file为null,不知道是什么原因?


返回顶部
顶部