Servlet相关文件上传下载类总结

来源:互联网 发布:北京达内java 编辑:程序博客网 时间:2024/05/17 05:10

Servlet文件上传

Servlet 可以与 HTML form 标签一起使用,来允许用户上传文件到服务器。上传的文件可以是文本文件或图像文件或任何文档。
本文使用到的文件有:

  • upload.jsp : 文件上传表单。
  • message.jsp : 上传成功后跳转页面。
  • UploadServlet.java : 上传处理 Servlet。
    需要引入的 jar 文件:commons-fileupload-1.3.2、commons-io-2.5.jar。

下面的 HTML 代码创建了一个文件上传表单。以下几点需要注意:

  • 表单 method 属性应该设置为 POST 方法,不能使用 GET 方法。
  • 表单 enctype 属性应该设置为 multipart/form-data.
  • 表单 action 属性应该设置为在后端服务器上处理文件上传的 Servlet 文件。下面的实例使用了 UploadServlet Servlet 来上传文件。
  • 上传单个文件,您应该使用单个带有属性 type=”file” 的

实现步骤

  • 1、创建DiskFileItemFactory对象,设置缓冲区大小和临时文件目录
  • 2、使用DiskFileItemFactory 对象创建ServletFileUpload对象,并设置上传文件的大小限制。
  • 3、调用ServletFileUpload.parseRequest方法解析request对象,得到一个保存了所有上传内容的List对象。
  • 4、对list进行迭代,每迭代一个FileItem对象,调用其isFormField方法判断是否是上传文件
  • 为普通表单字段,则调用getFieldName、getString方法得到字段名和字段值
  • 为上传文件,则调用getInputStream方法得到数据输入流,从而读取上传数据。

ServletContext类

WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。

ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。

由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。

1.多个Servlet通过ServletContext对象实现数据共享。

在InitServlet的Service方法中利用ServletContext对象存入需要共享的数据

/*获取ServletContext对象*/  ServletContext context = this.getServletContext();   //存入共享的数据    context.setAttribute("name", "haha"); 

在其它的Servlet中利用ServletContext对象获取共享的数据

/*获取ServletContext对象*/  ServletContext context = this.getServletContext();   //获取共享的数据   String name = context.getAttribute("name");   System.out.println("共享的内容值是:"+name);  

2.获取WEB应用的初始化参数。

在web.xml文件中配置需要初始化的参数信息。

<web-app>    <context-param>   <param-name>url</param-name>   <param-value>jdbc:MySQL://localhost:3306/4g</param-value>    </context-param>   <context-param>    <param-name>password</param-name>    <param-value>1314qr</param-value>    </context-param>    <context-param>     <param-name>user</param-name>     <param-value>root</param-value>     </context-param>   </web-app>  

在DemoServlet的doPost方法中测试获取初始化参数的步骤如下:

/*获取ServletContext对象*/   ServletContext context = this.getServletContext();   /*获取初始化参数*/  //获取指定名称的初始化参数   String url = context.getInitParameter("url");  //获取web.xml文件中所有的初始化应用参数           Enumeration<String> enumer = context.getInitParameterNames();   while(enumer.hasMoreElements()){   String name = enumer.nextElement();    String value = context.getInitParameter(name);    System.out.println(name+"=========="+value);       }   

2.实现Servlet的转发:

在测试的Servlet中实现转发的步骤如下:

/*要利用ServletContext对象实现转发获取对象*/  ServletContext context = this.getServletContext();    //在request对象中存入name属性    request.setAttribute("name", "haha");    /*根据转发的地址获取 RequestDispatcher对象*/  RequestDispatcher  rd  = context.getRequestDispatcher("/index.jsp");   //调用转发方法 以下采用任意方法即可    rd.forward(request, response);     //rd.include(request, response);   

注意:forward与include的区别

forward方法是把请求的内容转发到另外的一个servlet.而include是把另一个servlet处理过后的内容拿过来.

(forward方法调用后在响应中的没有提交的内容被自动消除。将请求转发给其他的Servlet后,由

被调用的Servlet负责对请求做出响应,而原先Servlet的执行则终止。      

include方法使原先的Servlet和转发到的Servlet都可以输出响应信息,即原先的Servlet还可以继续输出响应信息)

3.利用ServletContext对象读取资源文件。

读取资源文件(properties文件(属性文件))的三种方式

配置的properties的内容如下:

url=jdbc:mysql://localhost:3306/3g ; user=root;password=root;  

获取实现的代码如下:

/*获取ServletContext对象*/  ServletContext context = this.getServletContext();     //第一种方式    URL url = context.getResource("WEB-INF/classes/db.properties");   InputStream is =  url.openStream();   

//第二种方式

 /*读取db.properties文件*/  String path =context.getRealPath("WEB-INF/classes/db.properties");    /*根据文件的路径 构建文件对象*/  File file = new File(path);    /*根据file文件对象 创建输入流*/  InputStream is = new FileInputStream(file);   

//第三种方式

InputStream is = context.getResourceAsStream("WEB-INF/classes/db.properties ");    

以三种方式任意一种可以:

/解析properties的文件/

 Properties prop = new Properties();    //从输入流中读取属性列表(键和元素对)。     prop.load(is);     Set<String> set = prop.stringPropertyNames();      //遍历set集合      Iterator<String> it = set.iterator();      while(it.hasNext()){          String key = it.next();          String value = prop.getProperty(key);          System.out.println(key+"-----"+value);             }   

DiskFileItemFactory类

DiskFIleItemFactory是FileItem对象的工厂,常用方法如下:

  • public void setSize Threshold(int sizeThresshold):设置内存缓冲区的大小,默认值为10k。当上传文件大于缓冲区大小,fileupload组件使用临时文件缓存上传文件。由于Java虚拟机默认可以使用的内存空间是有限的,超出限制会抛出“java.lang.OutOfMemory”错误。如果上传文件很大,在内存中将无法临时保存该文件内容,Apache文件上传组件转而采用临时文件来保存这些数据;如果上传的文件很小,保存在内存中将会达到更快的效应。
  • public void setRepository(Java.io.File repository) :指定临时文件目录,默认值为System.getProperty(“Java.io.tmpdir”).
  • public DiskFileItemFactory(int sizeThreshold,java.io.File repository) :构造函数采用参数指定临界值和系统临时文件夹构造文件项工厂对象。
  • boolean isMultipartContent(HttpServletRequest request) :判断上传表单是否为multipart/form-data类型
  • List parseRequest(HttpServletRequest request):解析request对象,并把表单中的每一个输入项包装成一个fileItem 对象,并返回一个保存了所有FileItem的list集合。
  • setFileSizeMax(long fileSizeMax) :设置上传文件的最大值
  • setSizeMax(long sizeMax) :设置上传文件总量的最大值
  • setHeaderEncoding(java.lang.String encoding) :设置编码格式
  • setProgressListener(ProgressListener pListener)

ServletFileUpload类

该类是文件上传的核心类,在使用ServletFileUpload对象解析请求时要设置DiskFileItemFactory对象属性sizeThreshold(临界值)和repository(临时目录),所以实现文件上传之前,先构造好DiskFileItemFactory的实例对象,通过ServletFileUpload对象的构造方法或者FileItemFactory()方法设置ServletFileUpload对象的FileItemFactory对象。

构造方法:

  • public ServletFileUpload()

    构造一个未初始化的实例,需要在解析请求之前先调用setFileItemFactory()方法设置 fileItemFactory属性。

  • public ServletFileUpload(FileItemFactory fileItemFactory)

    构造一个实例,并根据参数指定的FileItemFactory 对象,设置 fileItemFactory属性。

ServletFileUpload类常用方法:

  • 1) public void setSizeMax(long sizeMax)

    setSizeMax方法继承自FileUploadBase类,用于设置请求消息实体内容(即所有上传数据)的最大尺寸限制,以防止客户端恶意上传超大文件来浪费服务器端的存储空间。其参数是以字节为单位的long型数字。
    在请求解析的过程中,如果请求消息体内容的大小超过了setSizeMax方法的设置值,将会抛出FileUploadBase内部定义的SizeLimitExceededException异常(FileUploadException的子类)。该方法有一个对应的读方法:public long getSizeMax()方法。

  • 2) public void setFileSizeMax(long fileSizeMax)

    setFileSizeMax方法继承自FileUploadBase类,用于设置单个上传文件的最大尺寸限制,以防止客户端恶意上传超大文件来浪费服务器端的存储空间。其参数是以字节为单位的long型数字。该方法有一个对应的读方法:public long geFileSizeMax()方法。
    在请求解析的过程中,如果单个上传文件的大小超过了setFileSizeMax方法的设置值,将会抛出FileUploadBase内部定义的FileSizeLimitExceededException异常(FileUploadException的子类)。

  • 3) public List parseRequest(javax.servlet.http.HttpServletRequest req)

    parseRequest 方法是ServletFileUpload类的重要方法,它是对HTTP请求消息体内容进行解析的入口方法。它解析出FORM表单中的每个的数据,并将它们分别包装成独立的FileItem对象,然后将这些FileItem对象加入进一个List类型的集合对象中返回。
    该方法抛出FileUploadException异常来处理诸如文件尺寸过大、请求消息中的实体内容的类型不是“multipart/form-data”、IO异常、请求消息体长度信息丢失等各种异常。每一种异常都是FileUploadException的一个子类型。

  • 4) public FileItemIterator getItemIterator(HttpServletRequest request)

    getItemIterator方法和parseRequest 方法基本相同。但是getItemIterator方法返回的是一个迭代器,该迭代器中保存的不是FileItem对象,而是FileItemStream 对象,如果你希望进一步提高新能,你可以采用getItemIterator方法,直接获得每一个文件项的数据输入流,做底层处理;如果性能不是问题,你希望代码简单,则采用parseRequest方法即可。

  • 5) public stiatc boolean isMultipartContent(HttpServletRequest req)

    isMultipartContent方法方法用于判断请求消息中的内容是否是“multipart/form-data”类型,是则返回true,否则返回false。isMultipartContent方法是一个静态方法,不用创建ServletFileUpload类的实例对象即可被调用。

  • 6) getFileItemFactory()和setFileItemFactory(FileItemFactory)

    方法继承自FileUpload类,用于设置和读取fileItemFactory属性。

  • 7) public void setProgressListener(ProgressListener pListener)

    设置文件上传进度监听器。该方法有一个对应的读取方法:ProgressListener getProgressListener()。

  • 8) public void setHeaderEncoding()

    在文件上传请求的消息体中,除了普通表单域的值是文本内容以外,文件上传字段中的文件路径名也是文本,在内存中保存的是它们的某种字符集编码的字节数组,Apache文件上传组件在读取这些内容时,必须知道它们所采用的字符集编码,才能将它们转换成正确的字符文本返回。
    setHeaderEncoding方法继承自FileUploadBase类,用于设置上面提到的字符编码。如果没有设置,则对应的读方法getHeaderEncoding()方法返回null,将采用HttpServletRequest设置的字符编码,如果HttpServletRequest的字符编码也为null,则采用系统默认字符编码。可以通过一下语句获得系统默认字符编码:
    System.getProperty(“file.encoding”));

File.separate

为了跨平台考虑,文件写法如下所示:

//windows写法File file = new File("C:\tmp\test.txt");//linux写法File file new File("/tmp/test.txt");//跨平台写法File myFile = new File("C:"+File.separate+"tmp"+File.separate+File.seaprate+"test.txt");
  • separatorChar为系统默认名称分隔符,此字段被初始化为包含file.seprate值得第一个字符,在Unix系统为“/”,在windows系统为“\”。
  • pathsepratorChar为系统路径分隔符,此字段被初始化为包含path.seprate值得第一个字符,在Unix系统为“:”,在windows系统为“;”。

具体操作

1、设置文件上传的MEMORY_THRESHOLD(内存临界值)、MAX_FILE_SIZE(最大上传文件值)、MAX_REEQUEST_SIZE(最大请求值)。

private static final int MEMORY_THRESHOLD = 1024*1024*3;private static final int MAX_FILE_SIZE = 1024*1024*40;private static final int MAX_REQUEST_SIZE = 1024*1024*50

2、 设置文件上传服务器的临时目录

DiskFileItemFactory factory = new DiskFileItemFatory();factory.setRepository(MEMRORY_THRESHOLD);//设置临时存储目录factory.setRepository(new File(System.getProperty("java.io.tmpdir")));ServletFileUpload upload = new ServletFileUpload(factory);//设置最大单文件值upload.setFileSizeMax(MAX_FILE_SIZE);//设置最大请求值(文件和表单数据)upload.setSizeMax(MAX_REQUEST_SIZE);//设置编码upload.setHeaderEncoding("utf-8");//构建上传文件临时存储目录路径String uploadPath = (this)request.getServletContext().getRealPath("./")+file.separate+UPLOAD_DIRECTORY;

3、解析请求内容提取文件数据

list<FileItem> formItems = upload.parseRequest(request);//处理不在表单中的数据for(FileItem item : formItems){    if(!item.isFormField){        String fileName = new File(item.getName()).getName();        String filePath = uploadPath +file.separate+fileName;        File storeFile = new File(filePath);        item.write(storeFile);        }    }

4、跳转到jsp文件,反馈上传消息结果

request.getServletContext().getRequestDispatcher("/../jsp").forword(request,response);

servlet文件下载

getParameter和getAttribute区别

  • getParameter得到的都是String,用于读取提交表单的值,或是某个表单提交过去的数据。 getAtrribute获取可以是对象Object,需进行转换,可用此设置任意对象,用于获取对象容器的数据值。(主要为SESSION值)
  • getParameter()获取POST/GET传递的参数值,用于客户端重定向,用于表单或url重定向传值接收数据。
  • getAttribute()用于服务器重定向,在servlet中使用forword函数。

操作步骤

1、获得请求文件名

String fileName = request.getParameter("FileName");

2、设置相关属性

//设置文件MIME类型response.setContentType(getServletContext().getMimeType(filename)); //设置Content.Dispositionresponse.setHeader("Content-Disposition","attachment;filename="+filename);

3、获取目标文件绝对路径,读取文件

String FilePath = getServletContent().getRealPath("/upload/"+filename);//读取文件InputStream in = new FileInputStream(FilePath);OutputStream out response.getOutputStream();//写文件out.write(in.read());