Web基础了解版12-上传下载
上传
-
用户在页面中选择要上传的文件,然后将请求提交到servlet
-
servlet收到请求,解析用户上传的文件,然后将文件存储到服务器
<form action="servlet" method="post" enctype="multipart/form-data"> <input type="file" name="file" /><br /><br /> <input type="submit" value="上传" /> </form>
-
表单的method属性必须为post
-
表单的enctype属性必须为multipart/form-data
-
注意:servelet
- 当enctype="multipart/form-data" 时,再使用getparamter()获取到内容永远为空。
- 需要引入解析请求中的参数和文件,这个工具就是commons-fileupload。
它的作用就是可以从request对象中解析出,用户发送的请求参数和上传文件的流。
commons-fileupload包依赖commons-io,两个包需要同时导入。
-
diskfileitemfactory
-
工厂类,用于创建servletfileupload,设置缓存等
-
该类一般直接使用构造器直接创建实例
-
方法:
-
public void setsizethreshold(int sizethreshold):用于设置缓存文件的大小(默认值10kb)
-
public void setrepository(file repository):用于设置缓存文件位置(默认系统缓存目录)
-
-
-
servletfileupload
-
该类用于解析request对象从而获取用户发送的请求参数(包括普通参数和文件参数)
-
该类需要调用有参构造器创建实例,构造器中需要一个diskfileitemfactory作为参数
-
方法:
-
public list<fileitem> parserequest(httpservletrequest request):解析request对象,获取请求参数,返回的是一个list,list中保存的是一个fileitem对象,一个对象代表一个请求参数。
-
public void setfilesizemax(long filesizemax):设置单个文件的大小限制,单位为b。如果上传文件超出限制,会在parserequest()抛出异常filesizelimitexceededexception。
-
public void setsizemax(long sizemax):限制请求内容的总大小,单位为b。如果上传文件超出限制,会在parserequest()抛出异常sizelimitexceededexception。
-
-
-
fileitem
-
该类用于封装用户发送的参数和文件,也就是用户发送来的信息将会被封装成一个fileitem对象,我们通过该对象获取请求参数或上传文件的信息。
-
该类不用我们手动创建,由servletfileitem解析request后返回。
-
方法:
-
string getfieldname():获取表单项的名字,也就是input当中的name属性的值。
-
string getname():获取上传的文件名,普通的请求参数为null。
-
string getstring(string encoding):获取内容,encoding参数需要指定一个字符集。
① 若为文件,将文件的流转换为字符串。
② 若为请求参数,则获取请求参数的value。
-
boolean isformfield():判断当前的fileitem封装的是普通请求参数,还是一个文件。
① 如果为普通参数返回:true
② 如果为文件参数返回:false
-
string getcontenttype():获取上传文件的mime类型
-
long getsize():获取内容的大小
-
-
//创建工厂类 diskfileitemfactory factory = new diskfileitemfactory(); //创建请求解析器 servletfileupload fileupload = new servletfileupload(factory); //设置上传单个文件的的大小 fileupload.setfilesizemax(1024*1024*3); //设置上传总文件的大小 fileupload.setsizemax(1024*1024*3*10); //设置响应内容的编码 response.setcontenttype("text/html;charset=utf-8"); try { //解析请求信息,获取fileitem的集合 list<fileitem> items = fileupload.parserequest(request); //遍历集合 for (fileitem fileitem : items) { //如果是普通的表单项 if(fileitem.isformfield()){ //获取参数名 string fieldname = fileitem.getfieldname(); //获取参数值 string value = fileitem.getstring("utf-8"); system.out.println(fieldname+" = "+value); //如果是文件表单项 }else{ //获取文件名 string filename = fileitem.getname(); //获取上传路径 string realpath = getservletcontext().getrealpath("/web-inf/upload"); //检查upload文件夹是否存在,如果不存在则创建 file f = new file(realpath); if(!f.exists()){ f.mkdir(); }; //为避免重名生成一个uuid作为文件名的前缀 string prefix = uuid.randomuuid().tostring().replace("-", ""); //将文件写入到服务器中 fileitem.write(new file(realpath+"/"+prefix+"_"+filename)); //清除文件缓存 fileitem.delete(); }
} } catch (exception e) { if(e instanceof sizelimitexceededexception){ //文件总大小超出限制 response.getwriter().print("上传文件的总大小不能超过30m"); }else if(e instanceof filesizelimitexceededexception){ //单个文件大小超出限制 response.getwriter().print("上传单个文件的大小不能超过3m"); } } response.getwriter().print("上传成功");
-
服务器以一个流的形式将文件发送给浏览器。
-
发送流的同时还需要设置几个响应头,来告诉浏览器下载的信息。
-
具体响应头如下:
-
content-type
-
下载文件的mime类型
-
可以通过servletcontext. getmimetype(string file)获取
-
也可以直接手动指定
-
使用response.setcontenttype(string type);
-
响应头样式:content-type: audio/mpeg
-
-
content-disposition
-
下载文件的名字,主要作用是提供一个默认的用户名
-
通过response.setheader("content-disposition", disposition)设置
-
响应头样式:content-disposition: attachment; filename=xxx.mp3
-
-
content-length
-
下载文件的长度,用于设置文件的长处(不必须)
-
通过response. setcontentlength(int len)设置。
-
设置后样式:content-length: 3140995
-
-
-
-
接下来需要以输入流的形式读入硬盘上的文件
-
fileinputstream is = new fileinputstream(file);
-
这个流就是我们一会要发送给浏览器的内容
-
-
通过response获取一个输出流,并将文件(输入流)通过该流发送给浏览器
-
获取输出流:servletoutputstream out = response.getoutputstream();
-
-
步骤演示
以下步骤都是在同一个servlet的doget()方法中编写的
1.获取文件的流:
string realpath = getservletcontext().getrealpath("/web-inf/mp3/中国话.mp3"); //获取文件的file对象 file file = new file(realpath); //获取文件的输入流 fileinputstream in = new fileinputstream(file);
2.获取头信息:
//获取文件的mime信息 string contenttype = getservletcontext().getmimetype(realpath); //设置下载文件的名字 string filename = "zhongguohua.mp3"; //创建content-disposition信息 string disposition = "attachment; filename="+ filename ; //获取文件长度 long size = file.length();
3.设置头信息
//设置content-type response.setcontenttype(contenttype); //设置content-disposition response.setheader("content-disposition", disposition); //设置文件长度 response.setcontentlength((int)size);
4.发送文件
//通过response获取输出流,用于向浏览器输出内容 servletoutputstream out = response.getoutputstream(); //将文件输入流通过输出流输出 byte[] b = new byte[1024]; int len = 0; while((len=is.read(b))> 0){ out.write(b, 0, len); } //最后不要忘记关闭输入流,输出流由tomcat自己处理,我们不用手动关闭 is.close();
中文文件名会出现乱码问题。解决此问题的方法很简单,在获取文件名之后为文件名进行编码:
filename = java.net.urlencoder.encode(filename,"utf-8");
火狐浏览器比较特殊需要特殊处理一下。
1.先要获取客户端信息(通过获取请求头中的user-agent信息)
string ua = request.getheader("user-agent");
2.然后判断浏览器版本,做不同的处理
//判断客户端是否为火狐 if(ua.contains("firefox")){ //若为火狐使用base64编码 filename = "=?utf-8?b?"+new base64encoder().encode(filename.getbytes("utf-8"))+"?="; }else{ //否则使用utf-8 filename = urlencoder.encode(filename,"utf-8"); }
string string = new string("你好.jpg".getbytes("gbk"), "iso8859-1");
上一篇: 通过编写Java代码让Jvm崩溃
下一篇: 智能指针