本文共 6394 字,大约阅读时间需要 21 分钟。
简述:
代码如下:
package com._test.servlet;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class DownLoadServlet extends HttpServlet { /** * 序列化 */ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { OutputStream out;// 输出响应数据的输出流 InputStream in; // 读取本地文件的输入流 // 获得fileName请求参数 String fileName = req.getParameter("fileName"); if (fileName == null) { out = resp.getOutputStream(); out.write("Please input fileName .".getBytes()); out.close(); return; } /** * 获得读取本地文件的输入流 */ in = getServletContext().getResourceAsStream("/store/" + fileName); /** * in.available()返回的值是该inputstream在不被阻塞的情况下一次可以读取到的数据长度 */ int length = in.available(); /** * 设置响应正文的MIME类型:该实体头的作用是让服务器告诉浏览器它发送的数据属于什么文件类型。 * 当浏览器收到响应类型是application/force-download的MEMI类型时,会以下载的方式来处理响应正文 */ resp.setContentType("application/force-download"); /** * Content-Length:用于描述HTTP消息实体的传输长度。 * */ resp.setHeader("Content-Length", String.valueOf(length)); /** * 服务端向客户端游览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如txt、jpg等,会直接在浏览器中显示, * 如果需要提示用户保存 * ,就要利用Content-Disposition进行一下处理,关键在于一定要加上attachment,这样浏览器会提示保存还是打开 * ,即使选择打开,也会使用相关联的程序比如记事本打开,而不是IE直接打开了 */ resp.setHeader("Content.Disposition", "attachment;filename=\"" + fileName + "\""); /** * 把本地文件中的数据发送给客户 */ out = resp.getOutputStream(); int bytesRead = 0; byte[] buffer = new byte[512]; while ((bytesRead = in.read(buffer))!=-1) { out.write(buffer, 0, bytesRead); } in.close(); out.close(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); }}
上传文件是指把客户端的文件发送到服务器端,当客户端向服务器上传文件时,客户端发送的HTTP请求正文采用“multipart/form-data”数据类型,表示复杂的包含多个子部分的复合表单。 不管HTTP请求时何种数据类型,Servlet容器都会把HTTP请求包装成一个HttpServletRequest对象。当请求正文是“multipart/form-data”数据类型时,servlet直接从HttpServletRequest对象中解析出复合表单的每个子部分仍然是一项非常复杂的工作。 为了简化对“multipart/form-data”类型的处理过程,可以利用apache开源软件组织提供的两个软件包来实现文件上传: (1)fileupload软件包(commons-fileupload-1.3.2-jar):负责上传和下载软件包,下载地址http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi 。 (2)io软件包(commons-io-2.5-jar):负责输入输出的软件包,下载地址;http://commons.apache.org/proper/commons-io/download_io.cgi 对于正文部分是“multipart/form-data”类型的HTTP请求,uploadfile软件包把请求正文包含的复合表单中的每个子部分看作是一个FileItem对象,FileItem对象分为两种类型: (1)formField:普通表单域类型,表单中的文本框及提交按钮等都是这种类型。 (2)非formFiled:上传文件类型,表单中的文件域就是这种类型,它包含了文件数据。
(1)upload.html代码如下:
Insert title here
POST /upload HTTP/1.1Referer http://localhost:8080/helloapp/upload.html......Content-Type:multipart/form-data;boundray=----------------------7d82fe91203a8Content-Length:858----------------------7d82fe91203a8Content-Disposition:form-data;name="username"Tom----------------------7d82fe91203a8Content-Disposition:form-data;name="file1"filename="C:\img.rar"Content-Type:application/octet-stream----------------------7d82fe91203a8Content-Disposition:form-data;name="file2"filename="C:\tips.txt"Content-Type:application/octet-stream----------------------7d82fe91203a8Content-Disposition:form-data;name="submit"upload----------------------7d82fe91203a8
分块展示如下图:
此内容必须一字不差,包括最后的回车。 注意:Content-Length: 858 这里的858是下面FileItem所有内容的总长度(包括最后的回车) 注意这一行: Content-Type:multipart/form-data;boundray= ----------------------7d82fe91203a8 multipart/form-data是必须的. ----------------------7d82fe91203a8是分隔符,分隔多个文件、表单项。 其中82fe91203a8 是即时生成的一个数字,用以确保整个分隔符不会在文件或表单项的内容中出现。 前面的 ---------------------------7d 是 IE 特有的标志。 Mozila 为---------------------------71
1.boolean isFormField()。isFormField方法用来判断FileItem对象里面封装的数据是一个普通文本表单字段,还是一个文件表单字段。如果是普通文本表单字段,返回一个true否则返回一个false。因此可以用该方法判断是否是普通表单域还是文件上传表单域。 2.String getName()。getName方法用来获得文件上传字段中的文件名。 3.String getFieldName()。getFieldName方法用来返回表单标签的name属性的值。 4.void write(File file)。write方法将FileItem对象中的内容保存到某个指定的文件中。如果FileItem对象中的内容是保存在某个临时文件中,该方法完成后,临时文件可以会被删除。该方法也可以将普通表单字段保存在一个文件中,但最主要的用途是把上传的文件内容保存在本地文件系统中。 5.String getString()。getString()方法将FileItem对象中保存的数据流内容以一个字符串返回。它有两个重载形式。public Java.lang.String getString()和public java.lang.String getString(java.lang.String encodeing) throws java.io.UnsupportedEncodingException。前者使用缺省的字符集编码将主体内容转换成字符串,后者使用参数指定的字符集编码。如果在读取普通表单字段元素的内容时,出现了乱码现象,可以调用第二个方法,并传入 正确的字符集编码名称。 6.String getContentType()。此方法用来获得上传文件的类型,即标段字段元素描述头属性“content-type”的值,如image/jpeg。如果FileItem对象对应的是普通的表单字段,将返回null。 7.boolean isInMemory()。判断FileItem对象封装的数据是保存在内存中还是硬盘中。 8.void delete()。此方法用来清空FileItem对象中封装的主体内容,如果内容是被保存在临时文件中,该方法会把临时文件删除。 9.InputStream getInputStream()。以流的形式返回上传文件的主体内容。 10.long getSize()。返回上传文件的大小。
a、FileItemFacroty和FileItem FileItemFactory是创建是创建FileItem对象的工厂,DiskFileItemFactory类 和DiskFileItem类,分别实现了FileItemFacroty接口和FileItem接口。DiskFileItem类表示基于硬盘的FileItem,DiskFileItem类能够把客户端上传的数据保存到硬盘。DiskFileItemFacroty是创建DiskFileItem对象的工厂。 为了提高想硬盘写数据的效率,尤其是写大容量数据的效率,fileupload软件包在写数据时会使用缓存,以及向临时目录存一些临时数据。 如代码:
//创建一个基于硬盘的FileItem DiskFileItemFactory factory = new DiskFileItemFactory() ; //设置硬盘写数据时所使用缓存区的大小,此处为4k factory.setSizeThreshold(4*1024); //设置临时目录 factory.setRepository(new File(tempFilePath));b、ServletFileUpload类 第一、ServletFileUpload类为文件上传处理器,它与FileItemFacroty关联。如:
//创建一个文件上传处理器 ServletFileUpload fileUpload = new ServletFileUpload(factory) ; //设置允许上传的文件的最大尺寸,此处为4M fileUpload.setSizeMax(4*1024*1024);第二、ServletFileUpload类的parseRequest(HttpServletRequest req)方法能够解析HttpServletRequest对象中的复合表单数据。 如
List items = fileUpload.parseRequest(req) ;第三、在得到包含FileItem对象的集合list之后,遍历这个集合,判断每个FileItem对象的类型,然后做出相应的处理。 代码如下:
Iterator iter = items.iterator() ; while (iter.hasNext()) { FileItem item = (FileItem) iter.next() ; if(item.isFormField()){ //普通表单域 }else { //处理上传文件 } }