用Servlet进行文件上传的原理和实现

上传人:平*** 文档编号:9260682 上传时间:2017-10-01 格式:DOC 页数:16 大小:95.26KB
返回 下载 相关 举报
用Servlet进行文件上传的原理和实现_第1页
第1页 / 共16页
用Servlet进行文件上传的原理和实现_第2页
第2页 / 共16页
用Servlet进行文件上传的原理和实现_第3页
第3页 / 共16页
用Servlet进行文件上传的原理和实现_第4页
第4页 / 共16页
用Servlet进行文件上传的原理和实现_第5页
第5页 / 共16页
点击查看更多>>
资源描述

《用Servlet进行文件上传的原理和实现》由会员分享,可在线阅读,更多相关《用Servlet进行文件上传的原理和实现(16页珍藏版)》请在金锄头文库上搜索。

1、用 Servlet 进行文件上传的原理和实现Servlet 是用 Java 编写的、协议和平台都独立的服务器端组件,使用请求/响应的模式,提供了一个基于 Java 的服务器解决方案。使用 Servlet 可以方便地处理在 HTML 页面表单中提交的数据,但 Servlet 的 API 没有提供对以 mutilpart/form-data 形式编码的表单进行解码的支持,因而对日常应用中经常涉及到到文件上传等事务无能为力。如何用 Servlet 进行文件的上传,必须编程实现。一、基本原理通过 HTML 上载文件的基本流程如下图所示。浏览器端提供了供用户选择提交内容的界面(通常是一个表单),在用户提

2、交请求后,将文件数据和其他表单信息编码并上传至服务器端,服务器端(通常是一个 cgi 程序)将上传的内容进行解码了,提取出 HTML 表单中的信息,将文件数据存入磁盘或数据库。 二、各过程详解A)填写表单并提交 通过表单提交数据的方法有两种,一种是 GET 方法,另一种是 POST 方法,前者通常用于提交少量的数据,而在上传文件或大量数据时,应该选用 POST 方法。在 HTML 代码中,在 标签中添加以下代码可以页面上显示一个选择文件的控件。在页面中显示如下(可能随浏览器不同而不同) 可以直接在文本框中输入文件名,也可以点击按钮后弹出供用户选择文件的对话框。 B)浏览器编码 在向服务器端提交

3、请求时,浏览器需要将大量的数据一同提交给 Server 端, 而提交前,浏览器需要按照 Server 端可以识别的方式进行编码,对于普通的表单数据,这种编码方式很简单,编码后的结果通常是 field1=value2&field2=value2& 的形式,如 name=aaaa&Submit=Submit。这种编码的具体规则可以在 rfc2231 里查到, 通常使用的表单也是采用这种方式编码的,Servlet 的 API 提供了对这种编码方式解码的支持,只需要调用 ServletRequest 类中的方法就可以得到用户表单中的字段和数据。这种编码方式( application/x-www-for

4、m-urlencoded )虽然简单,但对于传输大块的二进制数据显得力不从心,对于传输这类数据,浏览器采用了另一种编码方式,即 multipart/form-data 的编码方式,采用这种方式,浏览器可以很容易的表单内的数据和文件一起。这种编码方式先定义好一个不可能在数据中出现的字符串作为分界符,然后用它将各个数据段分开,而对于每个数据段都对应着 HTML 页面表单中的一个 Input 区,包括一个 content-disposition 属性,说明了这个数据段的一些信息,如果这个数据段的内容是一个文件,还会有 Content-Type 属性,然后就是数据本身。 这里,我们可以编写一个简单的

5、Servlet 来看到浏览器到底是怎样编码的。实现流程: 重载 HttpServlet 中的 doPost 方法 调用 request.getContentLength() 得到 Content-Length ,并定义一个与 Content-Length 大小相等的字节数组 buffer 。 从 HttpServletRequest 的实例 request 中得到一个 InputStream, 并把它读入 buffer 中。 使用 FileOutputStream 将 buffer 写入指定文件。代码清单/ ReceiveServlet.javaimport java.io.*;import

6、javax.servlet.*;import javax.servlet.http.*;/示例程序:记录下 Form 提交上来的数据,并存储到 Log 文件中public class ReceiveServlet extends HttpServletpublic void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException/1int len = request.getContentLength();byte buffer = new bytele

7、n;/2InputStream in = request.getInputStream();int total = 0; int once = 0;while (total =0) once = in.read(buffer,total,len);total += once;/3OutputStream out=new BufferedOutputStream( new FileOutputStream(Receive.log,true);byte breaker=rnNewLog: -rn.getBytes();System.out.println(request.getContentTyp

8、e();out.write(breaker,0,breaker.length);out.write(buffer);out.close();in.close(); 在使用 Opera 作为浏览器测试时,从指定的文件( Receive.log )中可以看到如下的内容 -_OPERAB_-T/DQLi2fn47+D52OOrpdrzContent-Disposition: form-data; name=idid00-_OPERAB_-T/DQLi2fn47+D52OOrpdrzContent-Disposition: form-data; name=file3; filename=Autoexe

9、c.batContent-Type: application/octet-streamecho offprompt $d $t $p $_$-_OPERAB_-T/DQLi2fn47+D52OOrpdrz-这里 _OPERAB_-T/DQLi2fn47+D52OOrpdrz 就是浏览器指定的分界符,不同的浏览器有不同的确定分界符的方法,但都需要保证分界符不会在文件内容中出现。下面是用 IE 进行测试的结果 -7d137a26e18Content-Disposition: form-data; name=name123-7d137a26e18Content-Disposition: form-d

10、ata; name=introduceI am.I am.-7d137a26e18Content-Disposition: form-data; name=file3; filename=C:Autoexec.batContent-Type: application/octet-streamecho offprompt $d $t $p $_$SET PATH=d:pfIBMVJava2eabbin;%PATH%;D:PFROSE98ICOMMON-7d137a26e18-这里 -7d137a26e18 作为分界符。关于分界符的规则可以概况为两条: 除了最后一个分界符,每个分界符后面都加一个

11、CRLF 即 u000D 和 u000A, 最后一个分界符后面是两个分隔符- 每个分界符的开头也要加一个 CRLF 和两个分隔符(-)。浏览器采用默认的编码方式是 application/x-www-form-urlencoded ,可以通过指定 form 标签中的 enctype 属性使浏览器知道此表单是用 multipart/form-data 方式编码如:C)提交请求 提交请求的过程由浏览器完成的,并且遵循 HTTP 协议,每一个从浏览器端到服务器端的一个请求,都包含了大量与该请求有关的信息, 在 Servlet 中,HttpServletRequest 类将这些信息封装起来,便于我们提

12、取使用。在文件上载和表单提交的过程中,有两个关心的问题,一是上载的数据是是采用的那种方式的编码,这个问题的可以从 Content-Type 中得到答案,另一个是问题是上载的数据量有多少即 Content-Length ,知道了它,就知道了 HttpServletRequest 的实例中有多少数据可以读取出来。这两个属性,我们都可以直接从 HttpServletRequest 的一个实例中获得,具体调用的方法是 getContentType() 和 getContentLength() 。Content-Type 是一个字符串,在上面的例子中,增加System.out.println(reque

13、st.getContentType();可以得到这样的一个输出字符串:multipart/form-data; boundary=-7d137a26e18前半段正是编码方式,而后半段正是分界符;任务分解上述的字符串,取出分界符。通过 String 类中的方法,我们可以把这个字符串分解,提取出分界符。String contentType = request.getContentType( );int start = contentType.indexOf(boundary=);int boundaryLen = new String(boundary=).length();String boun

14、dary = contentType.substring(start+boundaryLen);boundary = - + boundary;判断编码方式可以直接用 String 类中的 startsWith 方法判断。if(contentType=null | !contentType.startsWith(multipart/form-data)这样,我们在解码前可以知道: 编码的方式是否是 multipart/form-data 数据内容的分界符 数据的长度 我们可以用类似于 ReceiveServlet 中的方式将这个请求的输入流读入一个长度为 Content-Length 的字节数

15、组,接下来就是将这个字节数组里的内容全部提取出来了。D)解码 解码对我们来说是整个上载过程最繁琐的一个步骤,经过以上的流程,我们可以得到一个包含有所有上载数据的一个字节数组和一个分界符,通过对 Receive.log 分析,还可以得到每个数据段中的分界符。而我们要得到以下内容: 提交的表单中的各个字段以及对应的值 如果表单中有 file 控件,并且用户选择了上载文件,则需要分析出字段的名称、文件在浏览器端的名字、文件的 Content-Type 和文件的内容。字节数组的内容可以分解如下:具体解码过程也可以分为两个步骤: 将上载的数据分解成数据段,每个数据段对应着表单中的一个 Input 区。 对每个数据段,再进行分解,提出上述要求得到的内容。这两个步骤主要的操作有两个,一个是从一个数组中找出另一个数组的位置,类似于 String 类中的 indexOf 的功能,另一个是从一个数组中提取出另一个数组, 类似于 String 类中的 substring

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号