用户名: 密码: [免费注册] [忘记密码]
您的位置:首页 -- JAVA技术--
文件的上传和下载
发布:    2010-03-20     返回

1,文件上传和下载的简单知识说明

 

文件上传和下载是WEB应用经常需要面对的问题,在大部分的时候用户请求的参数是在表单域输入的字符串,但如果为表单元素设置enctype="multipart/form-data"属性,则提交表单时不再以字符串方式提交请求参数,而是以二进制编码的方式提交请求,此时可以直接通过HttpServletRequestgetParameter方法无法正常获取请求参数,我们可以通过二进制流来获取请求内容--通过这种方式,就可以取得希望上传文件的内容,从而实现文件的上传。

上面的这种方式编码很麻烦,JAVA领域有两个常用的文件上传项目:Common-FileUploadCOS,我接下来会分别介绍如何使用它们,Struts2在原有的文件上传项目上进行了进一步的封装,实现更为简单。同时Struts2还提供了对文件下载支持的stream的结果类型,通过struts2的支持,可以实现非西欧字符文件名的文件下载。并可以在下载前检查用户的权限。从而通过授权控制来控制文件的下载。

2,文件上传的原理

 

表单的enctype属性指定的是表单数据的编码方式,该属性有如下3个值:

 

1application/x-www-form-urlencoded:这是默认的编码方式,它只处理表单域里的value值,采用这种编码方式的表单会将表单域的值处理成URL编码方式。

 

2multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,它把文件域指定文件的内容也封装到请求参数里。一旦设置了这种方式,就无法通过HttpServletRequest.getParameter()访求获取请求参数。

 

3text/plain:这种编码方式当表单的action属性为mailto:URL的形式时比较方便,这种方式主要适用于直接通过表单发送邮件的方式。

 

3,手动文件上传

 

1HTML页面代码如下:

 

<!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-8">

<title>Insert title here</title>

</head>

<body>

<!-- 设置表单的enctype属性为multipart/form-data -->

<form action="pro.jsp" id="form1" name="form1" enctype="multipart/form-data" method="post">

上传文件:<input type="file" name="file" /><br>

请求参数:<input type="text" name="wawa" /><br>

<input type="submit" name="dd" value="提交" />

 

</form>

</body>

</html>

 

2JAVA处理,我这里直接用JSP页面进行处理。

 

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ page import="java.io.*" %>

<%

//取得HttpServletRequestInputStream输入流

InputStream is = request.getInputStream();

//InputStream输入流为基础,建立一个BufferedReader对象

BufferedReader br = new BufferedReader(new InputStreamReader(is));

String buffer = null;

//循环读取请求内容的每一行内容

while((buffer = br.readLine()) != null){

   //如果读到的内容以-------------开始,且以--结束,表明忆到请求内容的结尾

   if(buffer.endsWith("--")&&buffer.startsWith("---------")){

    //跳出循环

    break;

   }

   //如果读到的内容以-------开始,表明开始了一个表单域

   if(buffer.startsWith("-------")){

    //如查下一行内容中有filename字符串,表明这是一个文件域

    if(br.readLine().indexOf("filename") > 1){

     //跳过两行,开始处理上传的文件内容

     br.readLine();

     br.readLine();

     //以系统时间为文件名,创建一个新文件

     File file = new File(request.getRealPath("/") + System.currentTimeMillis());

     //创建文件输出流

     PrintStream ps = new PrintStream(new FileOutputStream(file));

     //接着开始读取文件内容

     String content = null;

     while((content = br.readLine()) != null){

      //如果读取的内容以-----开始,表明开始了下一个表单域内容

      if(content.startsWith("------")){

       //跳出处理

       break;

      }

      //否则,将读到的内容输出到文件中

      ps.println(content);

     }

     //关闭输出流

     ps.flush();

     ps.close();

    }

   }

}

//关闭输入流

br.close();

 

%>

 

这里只是一个最简单的处理,我是根据HTML页面上传后的request读出的上传输入流的内容,来设计以上代码的,上传后的文件存放在WEB应用的根目录下,并且没有设置文件的后缀名。而且因为用的是Reader字符流处理上传,所以只能处理文本文件的上传。

 

4,使用框架来完成上传

 

对于JAVA应用而言,最常用的上传框架有两个:Common-FileUploadCOS,不管使用哪个上传框架,它都负责解析出HttpServletRequest请求中的所有域--不管是文件域还是普通表单域。

 

一旦通过上传框架获得了文件域对应的文件内容,我们就可以通过IO流将文件内容写入服务器的任意位置,从而完成文件上传。

 

1Common-FileUpload框架的上传

 

Common-FileUpload框架是apache的一个项目。

 

A,准备工作:首先在http://commons.apache.org/fileupload/上下载common fileupload框架,目前最新的版本是1.2.1,下面就是用的这个版本。将commons-fileupload-1.2.1\lib\commons-fileupload-1.2.1.jar文件复制到我们项目的WEB-INF\lib目录下,因为它还需要common io项目的支持,因此我们还要去http://commons.apache.org/io/这里下载common io,我用的是最新的1.4版本。将commons-io-1.4-bin\commons-io-1.4\commons-io-1.4.jar文件复制到我们项目的WEB-INF\lib目录下。

 

B,编写代码:

 

HTML页面代码不变,JSP页面的代码如下:

 

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ page import="java.io.*" %>

<%@ page import="java.util.*" %>

<%@ page import="org.apache.commons.fileupload.disk.*,org.apache.commons.fileupload.*" %>

<%@ page import="org.apache.commons.fileupload.servlet.*" %>

<%

request.setCharacterEncoding("UTF-8");

DiskFileItemFactory factory = new DiskFileItemFactory();

//设置上传工厂的限制

factory.setSizeThreshold(1024 * 1024 * 20);

factory.setRepository(new File(request.getRealPath("/")));

//创建一个上传文件的ServletFileUpload对象

ServletFileUpload upload = new ServletFileUpload(factory);

//设置最大的上传限制

upload.setSizeMax(1024 * 1024 * 20);

//处理HTTP请求,items是所有的表单项

List items = upload.parseRequest(request);

//遍历所有的表单项

for(Iterator it = items.iterator();it.hasNext();){

   FileItem item = (FileItem) it.next();

   if(item.isFormField()){

    String name = item.getFieldName();

    String value = item.getString("GBK");

    out.println("表单域的name=value对为:" + name + "=" + value);

   }else{

    //取得文件域的表单域名

    String fieldName = item.getFieldName();

    //取得文件名

    String fileName = item.getName();

    //取得文件类型

    String contentType = item.getContentType();

    out.println("表单域的name=value对为:" + fieldName + "=" + fileName);

    //以原文件名作为新的文件名

    FileOutputStream fos = new FileOutputStream(request.getRealPath("/") + fileName);

    //如果上传文件域对应文件的内容已经在内存中

    if(item.isInMemory()){

     fos.write(item.get());

    }else{

     //获取上传文件内容的输入流

     InputStream is = item.getInputStream();

     byte[] buffer = new byte[1024];

     int len;

     //读取上传文件的内容,并将其写入服务器的文件中

     while((len = is.read(buffer)) > 0){

     fos.write(buffer,0,len);

     }

     //关闭输入流和输出流

     is.close();

     fos.close();

    }

   }

}

%>

 

这里将上传文件写到WEB应用程序的根目录下,文件名跟上传文件的文件名一致。

 

从以上代码可以看到,借助common file upload框架,我们可以很容易地获取请求中的各个表单域,不管是文件域还是普通表单域。

 

2COS框架的上传

 

COS框架是oreilly下的一个小项目,该项目同样将multipart/form-data类型请求中的各种表单域解析出来,相对而言,它比Common-FiloUpload更加方便。它的核心类是MultipartParser,该类用于解析HttpServletRequest请求,取出请求中全部表单域,COSPart实例代表了所有的表单域,不管是普通表单域还是文件域都是Part实例,Part有两个子类:ParamPartFilePart,分别代表普通表单域和文件域。

 

A,准备工作:首先在http://www.servlets/cos/上下载COS框架,目前最新的版本是05NOV2002,下面就是用的这个版本。将cos-05Nov2002\lib\cos.jar文件复制到我们项目的WEB-INF\lib目录下。

 

B,编写代码:

 

HTML页面代码不变,JSP页面的代码如下:

 

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ page import="java.io.*,java.util.*" %>

<%@ page import="com.oreilly.servlet.multipart.*,com.oreilly.servlet.*" %>

 

<%

request.setCharacterEncoding("UTF-8");

//设置POST请求的内容最大字节为10M,该类用于解析HTTP请求

MultipartParser mp = new MultipartParser(request,10 * 1024 * 1024);

//所有表单域都是Part实例

Part part;

//遍历请求中的所有表单域

while((part = mp.readNextPart()) != null ){

   //取得表单域的name属性值

   String name = part.getName();

   //对于普通表单域

   if(part.isParam()){

    //取得普通表单域的值

    ParamPart paramPart = (ParamPart) part;

    String value = paramPart.getStringValue("GBK");

    out.println("普通表单域部分:<br>name=" + name + ";value=" + value + "<br>");

   }

   //对于文件域

   else if(part.isFile()){

    //获取文件上传域

    FilePart filePart = (FilePart) part;

    String fileName = filePart.getFileName();

    if(fileName != null){

     //输出文件内容

     long size = filePart.writeTo(new File(request.getRealPath("/")));

     out.println("上传文件:<br>文件域的名=" + name + ";文件名=" + fileName + "<br>");

    }else{

     //文件名为空

     out.println("file,name=" + name + " is empty!");

    }

    out.flush();

   }

}

}

%>

同时COSPart还可以获取文件的文件名,文件类型,文件大小等详细信息,具体请参考COS的参考文档。

 

5Struts2的上传

 

Struts2没有提供自己的请求解析器,它在原有的上传解析器基础上做了进一步的封装,更时一步简化了文件上传。

 

可以在struts.properties配置文件中配置struts2所使用的解析器,配置文件中的内容如下:

 

#指定使用COS的文件上传解析器

#struts.multipart.parser=cos

#指定使用Pell的文件上传解析器

#struts.multipart.parser=pell

#Struts2默认使用JakartaCommon-FileUpload的文件上传解析器

struts.multipart.parser=jakarta

 

Struts2默认使用的是jakartaCommon-FileUpload框架,Struts2对于以上三个框架都做了支持,因此如果想使用其它的框架只需要修改以上参数,并把相应的JAR包放到复制到我们项目的WEB-INF\lib目录下就可以了。

 

 

1HTML页面只需要将Formaction改成upload.action就可以了,如下

 

<form action="upload.action" id="form1" name="form1" enctype="multipart/form-data" method="post">

 

请求参数:<input type="text" name="title" /><br>

上传文件:<input type="file" name="upload" /><br>

<input type="submit" name="dd" value="提交" />

 

</form>

 

这个action的名字就是我接下来要开发的action

 

2,编写Action,源代码如下:

package com.annlee.upload;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class UploadAction extends ActionSupport {

//封装文件标题请求参数的属性

private String title;

//封装上传文件域的属性

private File upload;

//封装上传文件类型的属性

private String uploadContentType;

//封装上传文件名的属性

private String uploadFileName;

//接受依赖注入的属性

private String savePath;

//接受依赖注入的方法

public void setSavePath(String savePath) {

   this.savePath = savePath;

}

//返回上传文件的保存位置

public String getSavePath() {

   return ServletActionContext.getRequest().getRealPath(savePath);

}

//文件标题的setget方法

public String getTitle() {

   return title;

}

public void setTitle(String title) {

   this.title = title;

}

//上传文件对应文件内容的setget方法

public File getUpload() {

   return upload;

}

public void setUpload(File upload) {

   this.upload = upload;

}

//上传文件的文件类型的setget方法

public String getUploadContentType() {

   return uploadContentType;

}

public void setUploadContentType(String uploadContentType) {

   this.uploadContentType = uploadContentType;

}

//上传文件的文件名的setget方法

public String getUploadFileName() {

   return uploadFileName;

}

public void setUploadFileName(String uploadFileName) {

   this.uploadFileName = uploadFileName;

}

 

public String execute() throws Exception{

   //以服务器的文件保存地址和原文件名建立上传文件输出流

   FileOutputStream fos = new FileOutputStream(getSavePath() + "\\" + getUploadFileName());

   //以上传文件建立一个文件上传输入流

   FileInputStream fis = new FileInputStream(getUpload());

   //将上传的内容写入服务器

   byte[] buffer = new byte[1024];

   int len = 0;

   while((len = fis.read(buffer)) > 0){

    fos.write(buffer , 0 , len);

   }

   return this.SUCCESS;

 

}

}

 

说明:这个Action还包含了另外两个属性xxxFileNamexxxContentType,这个是Struts2自动装载的,此外还有一个属性savePath,这个是我通过配置文件注入的。

 

3struts.xml配置中加上以下部分:

 

        <ac tion name="upload" class="com.annlee.upload.UploadAction" >

        <param name="savePath">/</param>

            <result>/common/succ.jsp</result>

        </action>

 

savePath是我设置的参数,它的好处是可以动态存放上传的文件的位置,要注意Struts2不会自动创建目录,因此文件存放的目录必须事先已经存在。

 

4,运行:

运行后可以在后台看到文件已经上传了。

 

特别说明:如果你上传成功后,想转到静态的HTML页面或者其它的资源,则应在web.xml文件中加上以下拦截器:

 

    <!-- 配置struts2CleanUpFilter -->

<filter>

   <filter-name>struts2-cleanup</filter-name>

   <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>

</filter>

<!-- 定义Struts2CleanUp Filter的拦截器 -->

<filter-mapping>

   <filter-name>struts2-cleanup</filter-name>

   <url-pattern>/*</url-pattern>

</filter-mapping>

 

这个拦截器的作用是Struts2Sitemesh的整合。

典型客户
JAVA技术
 
友情链接: 沈阳网站建设 |  阜新网站建设 |  阜新网站 |  安全评价 |  沃尔沃配件 |  链接申请与客服联系
域信息科技提供专业的jsp空间服务,jsp空间,jsp空间租用,jsp空间购买,虚拟JSP主机,jsp主机,独享TOMCAT,JSP服务器
售前电话:400-004-4994
售后电话:400-004-4994
技术支持(7×24支持):400-004-4994 018241839456
公司地址:阜新市中华路65号新天地大厦9F
邮编:123000       传真:0418-2493388-606
经营性ICP证:辽B-2-4-20070114    ICP备案: 辽ICP备07005704号
域信息科技提供专业的jsp空间,虚拟JSP主机,jsp主机,独享TOMCAT,JSP服务器
域信息科技提供专业的jsp空间,虚拟JSP主机,jsp主机,独享TOMCAT,JSP服务器