文件上传处理

一.前台处理

1.使用表单input元素

<form enctype="multipart/form-data" method="post" action="http://123.jsp">
  <input type="file" name="file" id="file" multiple /><br/>
</form>

这里要特别注意 form的enctype属性,一共有三种

  1)application/x-www-form-urlencoded(默认值)

  如图所示,为默认的表单提交方式。

  

 

  这种请求只会处理form中元素的value属性值,对value属性进行URL编码后再发送到服务器,并不会传输文件的内容。

  如图,http请求只发送了input元素的 name与value(即选中的文件名)

  

  查看原始http请求头时,发现确实对中文文件名进行了URL编码,在后台能通过getParameter获取到值是因为web服务器对原始的数据进行过一次处理了。

  

 

  如果我们使用默认的enctype属性值,并不能实现文件的上传。

 

  2)multipart/form-data

  最早的HTTP POST是不支持文件上传的,在1995年,ietf出台了rfc1867(RFC 1867 -Form-based File Upload in HTML),用以支持文件上传。也就是multipart/form-data方式。

  multipart/form-data由三部分组成

  第一部分就是第一行,表示分界线(boundary)
  第二部分表示该文件的一些内容配置信息,一般都是form-data(因为是FormData对象格式提交的),然后跟着其他name=value信息。
  第三部分就是第三行,传输文件的内容。

  具体如下图所示。

  

 

  第一行的分界线由浏览器随机生成,可以在请求头Content-Type获取,后台程序根据此分界线对多文件进行分割,然后逐个解析。

  

   设置为该值后,后台将不再能通过getParameter获取到参数值。如果同时希望传递一些参数,可以在URL后添加“?name=value”。

 

  3)text/plain

  text/plain意味着纯文本传输,浏览器不会进行编码处理。该方式在提交表单中一般不使用。

 

2.表单优化

普通的上传文件表单提交后,会进行跳转,如果文件较大还需要等服务器响应后才知道上传结果,这种方式用户体验很不好。

我们希望发送请求后页面不进行跳转,用户既可以继续操作该页面,也可观察上传进度等待结果。因此可以使用html5中新增的FormData对象以及XMLHttpRequest2.0实现这一功能。

利用FormData对象,我们可以使用一系列的键值对来模拟一个完整的表单,然后用XMLHttpRequest的send()方法来异步的提交这个"表单"。FormData配合AJAX实现带进度条的异步文件上传,可以参考 MDN

https://developer.mozilla.org/zh-CN/docs/Web/Guide/Using_FormData_Objects

https://developer.mozilla.org/zh-CN/docs/Using_files_from_web_applications

 

二.后台处理

1.解析文件

使用multipart/form-data将数据传输到后台就可以解析数据了,理论上可以通过request.getInputStream()获取请求文本进行解析,然而这是一项复杂繁琐的工作,你必须要对RFC标准相当熟悉。java中已经有开源的项目帮助我们解析使用multipart/form-data上传的文件。

在Apache官网下载commons-fileupload、commons-fileupload-io 两个jar包并导入到项目lib目录下中,就可以使用他们来解析文件了。

注意,HTTP请求的正文只有一次读取/解析的机会,如果使用fileupload解析前调用过以下函数,则fileupload会解析失败。

request.getParameter();

request.getParameterMap();

request.getParameterNames();

request.getParameterValues();

request.getReader();

request.getInputStream();

 

如果是servlet3.0(Tomcat7)已上版本,可以使用java原生的API  HttpServletRequest.getPart()

 

具体参考:http://stackoverflow.com/questions/2422468/how-to-upload-files-to-server-using-jsp-servlet/2424824#2424824

 

2.文件存储

后台解析出文件内容后,就可以存储文件内容了。我们可以使用 request.getServletContext().getRealPath("/WEB-INF/fileName")获取web目录下存储文件的路径,在通过FileOutputStream将内容写到磁盘文件中。但是这种方式是存在缺陷的。

1).文件是上传到WEB部署目录下的,一旦项目重新部署,所有上传的文件都会丢失,所以一般上传的文件都保存在数据库。

2).如果WEB容器没有配置将war文件展开到物理磁盘上,而是作为虚拟的文件系统部署在内存中,getRealPath()就会出错,它可能返回null 或者错误的路径

3).应该尽量避免使用getRealPath()方法。需要从服务器获取输入流 可使用 

ServletContext.getResourceAsStream() 

ServletContext.getResourcePaths()

ServletContext.getResource() (必须以"/"开头)

等方法替代。

  

 

posted @ 2016-06-17 20:32  Realwate  阅读(450)  评论(0编辑  收藏  举报