前言:
干了这几个项目,也做过几次文件上传下载,要么是copy项目以前的代码,要么是百度的,虽然做出来了,但学习一下原理弄透彻还是很有必要的。刚出去转了一圈看周围有没有租房的,在北京出去找房子是心里感觉最不爽的时候,没有归属感,房租还不便宜,RT,不能好高骛远,还是脚踏实地一点一点学技术吧,终将有一日,工资会涨的。
java文件上传
传统的文件上传,不用jquery插件的话,就是用form表单提交,项目里用过uploadify,可以异步上传文件,原理我也没研究。现在说传统的form表单上传文件。
文件上传核心:
用 来声明一个文件域。样式如 文件:_____ .
必须使用post方式提交表单。
必须设置表单的类型为multipart/form-data.是设置这个表单传递的不是key=value值。传递的是字节码.
新建web项目:
jsp form表单:enctype(编码类型)的默认值就是 application/x-www-form-urlencoded
浏览器查看 http报文:
主要参数:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 接收服务器返回的类型,*/*表示所有。
Referer:http://localhost:8888/upload/ 来自哪个网站
Accept-Language:zh-CN,zh;q=0.8 :请求回应中首选的语言为简体中文
Accept-Encoding:gzip, deflate, br支持的压缩格式
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 用户浏览器类型
Host:localhost:8888 主机地址
Connection:keep-alive 报文发送完毕后仍然保持连接
Cache-Control:max-age=0 缓存
Content-Length:41 41字节
对文件上传来说,重要的参数是:
Content-Type:application/x-www-form-urlencoded
这个参数只有post请求才有,默认就是application/x-www-from-urlencoded ,Content-type表示正文类型,get方式没有正文,因为参数在url里。
在Servlet里可以用request对象取到Content-type:request.getHeader("Content-type"); 默认的值为 application/x-www-form-urlencoded,
如果是get请求,则request.getHeader("Content-type");为null。
下图是get请求时的http头信息,参数再url传递,没有Content-type
文件上传,必须设置enctype="multipart/form-data"
from表单:
上传一个word:
此时的http消息的Content-Type:
其中的 boundary=----WebKitFormBoundary44gVxAkoSg3tk3oR 指的是文件上传的分隔符。在请求正文里体现。
看请求的正文:
-----xxxxxxxxxx 标识文件开始,最后一行的 --------xxxxxxxxxxxx--(分隔符末尾多了2个--),标识文件结束。第一个input 是text类型,第二个是二进制,content-type 是application/octet-stream 表示 二进制流。如果选择的是图片,Content-Type: image/jpeg,文本则,Content-Type: text/plain。
二进制流的接收:
当表单类型是post类型,切enctype="multipart/form-data",则所有的数据都是以二进制流的形式向服务器上传,所以request.getParameter("xxx") 永远为null,只能通过req.getInputStream(); 获取正文。
上传一个txt:
Servlet:
packagecom.lhy.upload;importjava.io.BufferedReader;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.io.OutputStream;importjava.io.PrintWriter;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;/***
*@authorAdministrator
**/@WebServlet(name="UploadServlet",urlPatterns="/UploadServlet")public class UploadServlet extendsHttpServlet{
@Overrideprotected voiddoGet(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException {//this.doPost(req, resp);
}
@Overrideprotected voiddoPost(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException {
req.setCharacterEncoding("UTF-8");
String contentType= req.getHeader("Content-type");
System.out.println("contentType: "+contentType);
String name= req.getParameter("name");
System.out.println(name);//null
InputStream is=req.getInputStream();//------WebKitFormBoundaryG0ULv7eVfQ1K2PBA//Content-Disposition: form-data; name="image"; filename="静夜思.txt"//Content-Type: text/plain//
//
//------WebKitFormBoundaryG0ULv7eVfQ1K2PBA--
BufferedReader br = new BufferedReader(newInputStreamReader(is));
String firstLine= br.readLine();//第一行,分隔符
String fileName =br.readLine();//Content-Disposition: form-data; name="image"; filename="jingyesi.txt"
fileName = fileName.substring(fileName.lastIndexOf("=")+2,fileName.length()-1);
br.readLine();
br.readLine();
String data= null;//获取当前项目的运行路径
String path = getServletContext().getRealPath("/up");
PrintWriter pw= new PrintWriter(path+"/"+fileName);while((data = br.readLine()) != null){if(data.equals(firstLine+"--")){break ; //读到了文件尾
}
pw.println(data);
}
pw.flush();
pw.close();
is.close();/*FileOutputStream fos = new FileOutputStream(path+"/"+"b.doc");
// byte[] b = new byte[1024];
int len = 0;
while((len = is.read()) != -1){
fos.write(len);
}
fos.flush();
fos.close();
is.close();*/}
}
项目里:
例子只是读取了txt,其他的二进制需要使用inputStream读取。
我读取了图片写到项目里,打不开,大小比原始图片会小一点,不知为何
欢迎关注个人公众号一起交流学习: