用JavaBean实现文件上传_第1页
用JavaBean实现文件上传_第2页
用JavaBean实现文件上传_第3页
用JavaBean实现文件上传_第4页
用JavaBean实现文件上传_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、用JavaBean实现文件上传(一)请求分析请求分析 要实现文件上传,我们必须先了解上传文件的HTTP请求。下面这个简单的应用示范了如何上传文件以及把HTTP请求的原始数据写入文件。用文本编辑器查看该文件即可了解请求的格式,在此基础上我们就可以提取出上传文件的名字、文件内容以及原本混合在一起的其他信息。 这个简单的应用是开发真正文件上传JavaBean的准备工作。它由三个文件构成:HTML文件main.html,JSP页面Jsp1.jsp,JavaBean文件SimpleBean.java。 main.html提供一个表单,用户从这里选择文件并把文件上传到服务器。main.html的代码如下:

2、 文件上传作者: 公司: 选择要上传的文件 可以看到,标记有一个enctype属性,属性值是MULTIPART/FORM-DATA。包括提交按钮在内,表单里面共有4个输入元素。前面两个输入元素是普通的text元素,即author和company。第三个输入元素的type属性是file,这个输入元素就是用来选择文件的元素。表单的action属性值是Jsp1.jsp,这意味着请求(包括上传的文件)将发送给Jsp1.jsp文件。Jsp1.jsp简单地调用名为SimpleBean的JavaBean。 下面是SimpleBean的实现代码: import java.io.*; import javax.

3、servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.ServletInputStream;public class FileUploadBean public void doUpload(HttpServletRequest request) throwsIOException PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(Demo.out);ServletInp

4、utStream in = request.getInputStream();int i = in.read();while (i != -1) pw.print(char) i);i = in.read();pw.close();这个JavaBean把HttpServletRequest对象的表单原始数据写入Demo.out文件。应用的用户界面由main.html文件提供,如下图所示。 我们选择上传的文件是abisco.html。选择上传HTML文件是为了便于观察上传后的格式,因为HTML文件本质上是文本文件,我们可以方便地浏览其内容。abisco.html文件的内容如下: Abisco点击

5、“上传”按钮之后,表单就发送给了Jsp1.jsp文件,一起发送的还有abisco.html文件。Jsp1.jsp文件不会向浏览器发送任何应答内容,但它会生成一个Demo.out文件。打开Demo.out文件,我们可以看到如下内容: -7d15340138 Content-Disposition: form-data; name=AuthorA. Christie-7d15340138Content-Disposition: form-data; name=CompanyAbisco-7d15340138Content-Disposition: form-data; name=Filename;

6、 filename=C:123dataabisco.htmlContent-Type: text/htmlAbisco-7d15340138-可以看到,HTTP请求体内包含了所有的表单输入,包括上传的文件。这些输入数据的分隔由一个分隔符实现。分隔符由一系列的“-”字符和一个随机数字构成。在上面的例子中,分隔符为“-7d15340138”。最后一个分隔符结束请求体,这个分隔符的后面多出两个“-”符号。对于非文件类型的输入数据,分隔符后面跟着下面这行内容:Content-Disposition: form-data; name=inputName。其中inputName是表单元素的名字。例如:Co

7、ntent-Disposition: form-data; name=Author。在这行内容的后面,紧跟着两个连续的回车换行符和表单元素值。 而对于文件型输入域,分隔符的后面有两行内容。第一行内容包含输入元素的名字以及上传文件在客户端的完整路径,如上例中这行内容是“Content-Disposition: form-data; name=Filename; filename=C:123dataabisco.html”。这行内容指出文件输入元素的名字是filename,文件的路径是“C:123dataabisco.html”。注意Windows浏览器会设置文件路径,而Unix/Linux以及M

8、ac浏览器只发送文件名字。 第二行包含了文件的内容类型,因此它的具体内容和上传的文件有关。本例中第二行的内容是“Content-Type: text/html”。 和非文件输入元素一样,文件内容在两个连续的回车换行符之后正式开始。用JavaBean实现文件上传(二)上传文件上传文件众所周知,JavaBean是Java平台的软件组件,下面要实现的上传功能就是用JavaBean实现,所以它可以方便地应用到任何需要文件上传功能的应用之中。 代码清单如下: package com.brainysoftware.web;import javax.servlet.http.HttpServletReque

9、st;import javax.servlet.ServletInputStream;import java.util.Dictionary;import java.util.Hashtable;import java.io.PrintWriter;import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;public class FileUploadBean private String savePath, filepath, filename, contentType;private

10、 Dictionary fields;public String getFilename() return filename;public String getFilepath() return filepath;public void setSavePath(String savePath) this.savePath = savePath;public String getContentType() return contentType;public String getFieldValue(String fieldName) if (fields = null | fieldName =

11、 null)return null;return (String) fields.get(fieldName);private void setFilename(String s) if (s=null)return;int pos = s.indexOf(filename=);if (pos != -1) filepath = s.substring(pos+10, s.length()-1);/ Windows浏览器发送完整的文件路径和名字/ 但Linux/Unix和Mac浏览器只发送文件名字pos = filepath.lastIndexOf();if (pos != -1)filena

12、me = filepath.substring(pos + 1);elsefilename = filepath;private void setContentType(String s) if (s=null)return;int pos = s.indexOf(: );if (pos != -1)contentType = s.substring(pos+2, s.length();public void doUpload(HttpServletRequest request) throws IOException ServletInputStream in = request.getIn

13、putStream();byte line = new byte128;int i = in.readLine(line, 0, 128);if (i 3)return;int boundaryLength = i - 2;String boundary = new String(line, 0, boundaryLength); /-2丢弃换行字符fields = new Hashtable();while (i != -1) String newLine = new String(line, 0, i);if (newLine.startsWith(Content-Disposition:

14、 form-data; name=) if (newLine.indexOf(filename=) != -1) setFilename(new String(line, 0, i-2);if (filename=null)return;/文件内容i = in.readLine(line, 0, 128);setContentType(new String(line, 0, i-2);i = in.readLine(line, 0, 128);/空行i = in.readLine(line, 0, 128);newLine = new String(line, 0, i);PrintWrite

15、r pw = new PrintWriter(new BufferedWriter(newFileWriter(savePath=null? : savePath) + filename);while (i != -1 & !newLine.startsWith(boundary) / 文件内容的最后一行包含换行字符/ 因此我们必须检查当前行是否是最/ 后一行i = in.readLine(line, 0, 128);if (i=boundaryLength+2 | i=boundaryLength+4)& (new String(line, 0, i).startsWith(boundary

16、)pw.print(newLine.substring(0, newLine.length()-2);elsepw.print(newLine);newLine = new String(line, 0, i);pw.close();else / 普通表单输入元素/ 获取输入元素名字int pos = newLine.indexOf(name=);String fieldName = newLine.substring(pos+6, newLine.length()-3);i = in.readLine(line, 0, 128);i = in.readLine(line, 0, 128);n

17、ewLine = new String(line, 0, i);StringBuffer fieldValue = new StringBuffer(128);while (i != -1 & !newLine.startsWith(boundary) / 最后一行包含换行字符/ 因此我们必须检查当前行是否是最后一行i = in.readLine(line, 0, 128);if (i=boundaryLength+2 | i=boundaryLength+4) & (new String(line, 0, i).startsWith(boundary)fieldValue.append(ne

18、wLine.substring(0, newLine.length()-2);elsefieldValue.append(newLine);newLine = new String(line, 0, i);fields.put(fieldName, fieldValue.toString();i = in.readLine(line, 0, 128);代码的第一行是包声明,如果你不想让该类从属于任何包,可以删除这行代码。接下来的几行代码声明了该JavaBean所要引用的各个类和接口。 FileUploadBean类有5个私有的属性(域),6个公用的方法,2个私有的方法。用JavaBean实现文

19、件上传(三)属性属性 FileUploadBean类的5个域都是私有的,它们是: private String savePath该域指定了文件上传后保存到服务器的哪一个路径。savePath的值用setSavePath方法设置。这个值应该在调用doUpload方法之前设置;如没有设置,上传后的文件将保存到服务器的默认目录。 private String filepath该域指定了上传文件在客户端的完整路径。filepath的值由doUpload方法设置,在JSP页面或者Servlet中调用getFilepath方法可以获取filepath域的值。对于非Windows下的浏览器,该值等于file

20、name。 private String filename该域是上传文件的名字。filename的值由setFilename方法设置。在JSP或者Servlet中调用getFilename方法可以获取filename域的值。private String contentType该域是上传文件的内容类型。contentType的值由doUpload方法设置,你可以用getContentType方法获得contentType域的值。 private Dictionary fieldsfields域保存了用户在表单中输入数据的名字/值对。调用getFieldValue方法可以获取表单输入元素的值。用J

21、avaBean实现文件上传(四)方法方法 前面四个public类型的方法用于返回FileUploadBean对象的私有域,它们是:getFilepath,getFilename,getContentType以及getFieldValue。 public String getFilepath()返回filepath私有域的值。 public String getFilename()返回filename私有域的值。 public String getContentType()返回contentType私有域的值。 public String getFieldValue(String fieldNa

22、me)返回HTML表单中指定输入元素的值,元素的名字通过fieldName参数指定。 public void setSavePath(String savePath)用该方法指定服务器上保存上传文件的目录的名字。public void doUpload(HttpServletRequest request) throws IOExceptiondoUpload是FileUploadBean类中最重要的一个方法。它的任务有二个:第一,它从HTML表单提取出输入域的名字和值并保存到Dictionary对象;第二,doUpload方法提取出上传的文件,把这个文件保存到savePath指定的路径,并分

23、别把文件的名字、路径、内容类型赋给filename、filepath和contentType域。 private void setContentType(String s)由doUpload方法调用。setContentType方法从原始字节数据提取出上传文件的内容类型。 private void setFilename(String s)由doUpload方法调用。setFilename方法从原始字节数据提取出文件路径和名字。 doUpload方法的参数是Servlet/JSP容器创建的HttpServletRequest对象。HttpServletRequest对象描述了程序为了提取出HT

24、ML表单元素名字-值对以及上传文件必须处理的HTTP请求。doUpload方法首先通过HttpServletRequest对象的getInputStream方法获得ServletInputStream对象。 如前所述,每一个表单元素由分界符和一组回车换行符分隔。因此,我们可以一行一行地读入HttpServletRequest对象的内容。下面这行代码定义了一个名为line的byte数组:然后,我们用ServletInputStream对象的readLine方法读入HttpServletRequest对象内容的第一行: int i = in.readLine(line, 0, 128);第一行应该

25、是分界符,而且如果没有错误的话,它的长度应该大于3。如果它的长度小于3,我们可以认为出现了错误,doUpload方法应该立即返回: if (i 3) return;分界符和分界符的长度都非常重要,从本文后面你可以看到这一点。分界符由一组回车换行符结束,因此它的实际长度要比readLine方法返回的字节数少2。 int boundaryLength = i - 2;丢弃byte数组line的最后2个回车换行符即可获得分界符: String boundary = new String(line, 0, boundaryLength);接下来,fields域被实例化成Hashtable对象。这个Ha

26、shtable对象将用来保存HTML表单元素的名字/值对。 fields = new Hashtable(); 由于已经有了分界符,接下来我们就可以开始提取出表单元素的值。具体方法是用一个while循环按行读入HttpServletRequest对象的内容,直至遇到内容结束readLine方法返回-1为止。所有的表单元素都以分界符开始,后面跟上“Content-Disposition”行,这一行由下面这些字符开始: Content-Disposition: form-data; name= 表单元素有两种类型:文件,非文件(普通的表单元素,如TEXT或者HIDDEN元素)。这两种表单元素的区别

27、在于文件元素包含字符串“filename=filename”。由此,我们可以利用该信息把文件和非文件的表单输入元素区别开来,代码如下: if (newLine.startsWith(Content-Disposition: form-data; name=) if (newLine.indexOf(filename=) != -1) / 文件型表单输入元素/ 这里加上提取文件的代码. . . else / 普通表单输入元素/ 这里加上提取表单元素的代码. . .现在,我们首先来看看提取文件内容的代码。 文件路径包含在“Content-Disposition”的后面。为提取文件路径和文件名字,d

28、oUpload方法调用了setFilename私有方法。setFilename方法提取出文件路径和文件名字信息,然后把它们赋值给filepath和filename域。调用setFilename方法之后,filename域应该不再是null。如果此时filename域仍旧是null,则说明遇到了问题,doUpload方法直接返回。 if (filename=null) return;“Content-Disposition”行之后的下一行是内容类型行。因此,doUpload方法接着调用readLine方法,然后调用setContentType私有方法。setContentType方法和setFi

29、lename方法相似,它从原始字节数据中提取出上传文件的内容类型并保存到contentType域。 紧接内容类型行的下一行是空行,因此程序再调用了一次readLine方法。 i = in.readLine(line, 0, 128); 接下来开始了真正的文件内容。我们先应该做好通过PrintWriter对象把文件写入磁盘的准备。 PrintWriter pw = new PrintWriter(new BufferedWriter( new FileWriter( savePath=null? : savePath ) + filename);上传文件保存到哪个位置取决于savePath域是否

30、已经设置。如果savePath域没有设置,它的值是null,则文件将被保存到默认目录;如果savePath域已经设置,它的值不是null,则上传的文件被保存到它所指定的目录。 然后我们就可以提取文件的内容。具体方法是使用while循环,每次循环读入一行内容并通过PrintWriter的输出方法把它写入磁盘。但我们知道,文件的最后一行包含两个回车换行符号,所以保存到磁盘的字节数据不应该包含这两个字符。因此,如果读入的行不是文件的最后一行,我们把所有读到的字节数据写入磁盘;如果读入的行已经是文件的最后一行,写入磁盘的字节数据要减去最后两个字符。然而,我们并不知道文件的大小,我们只知道紧接文件内容的

31、下一行又是一个分界符;或者,如果文件是最后一个HTML表单元素,接下来的一行是分界符加上两个短划线字符。因此,只要检查下一行内容是否是分界符,我们就知道了何时应该结束while循环。这就是前面说分界符很重要的原因,在这里我们必须用到分界符。 虽然我们可以读取下一行内容然后用startsWith方法检查它是否是一个分界符,然而,由于字符串操作的开销非常大,为了减少字符串操作,我们比较readLine读入的字节数组的长度。后者应该等于boundaryLength + 2;或者,如果它是HttpServletRequest对象中的最后一行,由于多出了最后两个短划线字符,它应该等于boundaryLength + 4。由于一行内容即使不是分界符也可以和分界符一样长,当长度匹配之后我们又将它与分界符比较。这就是前面提到boundaryLength很重要的原因了。 整个处理过程的实现代码如下: while (i != -1 &

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论