在实际应用开发中,文件上传是很常用的功能。例如,OA办公提交公文,项目测试提交测试报告,再比如基于Web的邮件系统发送邮件附件。
在早期的HTML中,表单不能实现文件的上传,在1995年RFC1867规范(即HTML中的基于表单的文件上传)对表单做出扩展,增加了表单元素<input type="file">。例如:
<form method="post" action="upload.jsp" enctype="multipart/form-data"> <input type="file" name="file1" size="40"><p> <input type="submit" value="上传"> </form>
我们新建一个项目,里面创建一个adminImg.jsp(名字随便取),页面代码如下:
<form action="/doudouleyuan/pages/admin/adminImg.jsp" method="post" enctype="multipart/form-data"> <input type="file" name="file1" size="50"/><br/> <input type="file" name="file2" size="50"/><br/> <input type="text" name="desc"/><p> <input type="submit" value="上传"/> </form>
请求头:
请求Request Payload,具体不知道什么含义,姑且认为是请求装载内容,也就是服务端要收到的内容
几个重要点:
【1】可以看到请求头的Content-Type的值是multipart/form-data,指明客户端传送的是文件内容,如果Content-Type的值不是multipart/form-data,那么可以认为这次请求不是上传文件。Content-Type还有一个属性boundary是用来指明传送内容分隔符,这个分隔符是随机的,而且不同浏览器采用的分隔符形式也是不同的。
【2】请求头Content-Length用于表明传送内容的总长度,如果服务器端要限制上传文件的大小,可以利用ServletRequest接口的getContentLength()得到请求正文的长度,然后判断是否接受客户端上传的文件内容。
【3】请求正文每一部分都有Content-Disposition报头域,它的值是form-data,属性name指明在表单中的字段名。我们可以通过判断Content-Disposition报头域是否包含filename属性来确定该部分内容是否是文件的内容。
【4】对所有的多部分MIME类型来说,每一部分都有一个可选的报头域Content-Type,默认值是text/plain,如果文件的内容是填写表单上传的话,那么文件输入就被标识为application/octet-stream,如果浏览器指导文件内容是什么类型的,就标识为相应的媒体类型,例如上面的image/jpeg。
【5】在每一部分空行之后就是上传文件的内容或表单中相应字段的值,最后的结尾是分隔符加上两个连续的连字符(--),我们在获取请求正文的文件数据时,可以通过判断分隔符之后是否有两个连续的连字符(--)确定数据处理是否完成。
【6】对于文件上传,一定是通过输入流来获取文件内容,不能使用ServletRequest接口的getParameter()方法,而需要调用ServletRequest接口的getInputStream()方法来得到输入流,然后从输入流中读取传送的内容,再根据文件上传的格式进行分析,取出上传文件的内容和表单其它字段的内容。在分析文件上传格式的时候,不能简单地进行字符串比较,因为传送的内容有可能是像图片这样的二进制数据,而不单出是字符数据