FileUpload文件上传

来源:互联网 发布:avfun邀请码淘宝 编辑:程序博客网 时间:2024/06/07 06:23

文件上传
为什么使用文件上传?
例如社交网站需要提供用户照片.
很多企业内部,商品网站维护时需要上传一些文件
邮箱需要上传附件....
怎样完成文件上传操作?
浏览器
1.请求方式必须是 post
2.需要使用组件<input type="file" name="f">
3.表单必须设置encType="multipart/form-data"
4.上传文件的input 中,name属性必须要填写,不然不会上传. 

服务器端
通过request对象,获取InputStream,可以将浏览器提交的所有请求正文读取到.

多段式提交:
就是使用分割线,将表单中的各个提交项分隔开.
-------------------------------------------------------------------------------------
文件上传的插件

commons-fileupload 它是常用的一个文件上传工具

使用时要导入两个jar包
commons-fileupload-1.2.1.jar
commons-io-1.4.jar

快速入门
1.设置浏览器端
<form action="${pageContext.request.contextPath}/upload2" method="post"enctype="multipart/form-data">
<input type="file" name="f"> 
<input type="submit" value="上传">
</form>
2.在服务器端操作
// 1.创建一个 DiskFileItemFactory
DiskFileItemFactory factory = new DiskFileItemFactory();


// 2.创建一个ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);


// 3.完成上传操作


try {
// 3.1 得到所有上传项
List<FileItem> items = upload.parseRequest(request);


// 3.2遍历上传项
for (FileItem item : items) {


// 3.3判断是否是上传组件
if (!item.isFormField()) {


// 3.4 将文件真正上传
IOUtils.copy(item.getInputStream(), new FileOutputStream(
"d:/upload/a.txt"));
}


}


} catch (FileUploadException e) {
e.printStackTrace();
}
=============================================================
文件上传 后台步骤
1. 创建并使用DiskFileItemFactory 进行上传的设置(缓冲区大小,临时文件仓库)
2. 创建ServletFileUpload类,加载DiskFileItemFactory中的配置.
3. 使用ServletFileUpload 解析Request对象. =>  获得请求正文中每个分隔符之间的内容 封装的FileItem对象 集合.
4. 遍历FileItem对象集合.
//判断 当前FIleItem是否是一个字段类型
//不是字段类型 => 该FileItem 是 上传文件的流类型 => 对文件进行保存
//是字段类型 => 获得字段内容.


=============================================================
三个核心类
1.DiskFileItemFactory
用于设置文件上传时,缓冲区大小以及临时文件存储位置.
1.1 可以设置文件上传缓冲区大小
factory.setSizeThreshold(1024*1024); //设置为1m 默认是10k
1.2可以设置临时文件存储位置
File temp=new File(this.getServletContext().getRealPath("/temp"));
factory.setRepository(temp); //可以指定临时文件存储位置,默认是系统的临时文件存储位置

2.ServletFileUpload
它的作用是真正完成解析数据操作上传类

2.1pareRequest(HttpServletRequest request)
得到所有的上传信息,将每一部分映射成FileItem对象.

2.2isMultipartContent(HttpServletRequest request)
这个方法返回值是boolean,它是用于判断当前表单是否是一个上传的表单,
简单说,就判断它的encType的值是否是 multipart/form-data.

2.3setHeaderEncoding(String encoding)
用于解决上传文件名称中文乱码问题

2.4可以设置上传文件大小,如果超过设置大小.将会抛出异常(默认没有最大值)
void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小 
void  setSizeMax(long sizeMax) 设置总文件上传大小 

3.FileItem
它代表的是每一个上传项(其时就是表单中的每一个组件)

3.1 isFormField()
这个方法返回的是boolean类型,
它是判断当前组件是否是上传组件 简单说,就是判断type="file",
如果返回true,代表不是上传组件,返回false,代表是上传组件
3.2 getName()
获取非上传组件的上传文件的名称,如果是非上传组件,返回的是null
3.3 getFieldName()
获取组件名称,提交的键
3.4 getString()
获得每一段中的正文内容(文本类型)
3.5 delete方法
它是用于上传完成后,删除临时文件的
-----------------------------------------------------------------------
细节问题:关于文件上传时文件名称包含中文的乱码问题?
调用ServletFileUpload的setHeaderEncoding方法解决
-----------------------------------------------
细节问题:普通表单字段提交时,中文乱码问题?
FileItem的 getString方法返回提交的值.通过参数来设置解码码表
例如: getString("UTF-8");
-----------------------------------------------
细节问题: 如何设置上传文件大小限制?
调用ServletFileUpload的setSizeMax(总大小)
  setFileSizeMax(每个大小)方法
------------------------------------------------
细节问题:上传文件后,我们应该把文件保存到什么位置?
1.放到WEB-ROOT下(不再WEB-INF中)
|- 购物网站.商家上传商品图片,需要用户直接能够访问
2.放到WEB-INF中,或者项目以外硬盘的任何位置
|- 私人照片,网盘上传 不想要用户直接访问
3.放到数据库中(绝对不能这么做)


-----------------------------------------------------------------------------------
细节问题: 上传文件时,该使用什么名字将文件保存?
1>就用用户自己命名的文件名保存(可能会产生覆盖,不用)
2>自己生成不重复的文件名
* UUID(简单)
* 登录用户名+系统毫秒数
------------------------------------------------------------------------------------
细节问题:为了防止同一个目录下方上传文件数量过多,思考如何解决? 
1> /upload/2016/05/22/xxxx  使用当前日期作为子文件夹名称
2> 当前登录用户的用户名作为文件夹名称(适用于小网站不推荐)
------------------------------------------------------------------------------------
细节问题:如何获得用户命名的文件名?
item.getName(),返回文件名.

------------------------------------------------------------------------------------
细节问题:如何多文件上传
后台代码,无论上传一个还是上传多个,没有区别的.
前台需要准备多个<input type="file">

===================================================================================================
二.文件下载
1.文件下载方式
1. 直接将待下载文件放到webRoot文件夹或子文件夹下.
优点:简单
缺点:无法进行访问控制
使用场景: 需要推广的资源.
2.需要控制资源的下载.在下载前要经过逻辑处理.
将资源放到用户不能直接访问的地方. 例如: WEB-INF  或  d:/upload


------------------------------------------------------------------------------------
下载编码问题:
1. 如何使用一个servlet 提供多个文件的下载
  使用参数传递下载的文件名称
2.客户端的超连接中如果包含了中文,会出现get请求方式乱码问题
<a href="${pageContext.request.contextPath}/download?filename=天空.mp3">下载王非天空.mp3</a>
String filename = request.getParameter("name"); // yog.rar / 她说.mp3
byte[] b = filename.getBytes("ISO-8859-1");
filename = new String(b,"UTF-8");
实际上Get提交时包含中文乱码的解决。

3.关于下载文件名称中文乱码问题
response.setHeader("content-disposition", "attachment;filename="+ filename);

这段代码中的filename是指定下载文件时的名称

对于IE浏览器,它要求必须给一个UTF-8码
对于firefox浏览器,它要求必须给一个base64编码


if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"
+ base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");

}

====================================================================================================================



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package cn.itcast.b_api;



import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;


public class CServlet extends HttpServlet {


public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//2.1 判断当前请求是否是多段式提交的请求
if(!ServletFileUpload.isMultipartContent(request)){//判断是否是多段式提交
request.setAttribute("error","不是多段式提交");
request.getRequestDispatcher("error.jsp").forward(request, response);
return;
}

//1 创建配置工厂
DiskFileItemFactory factory = new DiskFileItemFactory();

//1.1 设置接收文件上传流的缓冲区大小,默认大小是:10240字节
factory.setSizeThreshold(20480);
//1.2 设置临时文件存放目录
factory.setRepository(new File("e:/temp"));

//2 根据配置工厂,创建解析器类(ServletFileUpload)
ServletFileUpload upload = new ServletFileUpload(factory);
//2.2 解析前设置解析段头使用的码表 => 解决文件名称乱码
upload.setHeaderEncoding("UTF-8");

//2.3 设置文件上传的最大大小(bytes)
//upload.setSizeMax(sizeMax); // 总大小限制
//upload.setFileSizeMax(30000); //单个文件大小限制

//2.4 解析request,并获得每一段内容
List<FileItem> list = null;
try {
list = upload.parseRequest(request);
} catch (FileUploadException e) {
request.setAttribute("error","解析出错!"+e.getMessage());
request.getRequestDispatcher("error.jsp").forward(request, response);
return;
}

if(list!=null){
//3 遍历FileItem
for(FileItem item : list){
//3.1 判断是哪种段
if(item.isFormField()){//普通文本段
//3.2 获得提交的键
String fieldName = item.getFieldName();
//3.3 获得提交的值
String value1 =item.getString();
String value2 =item.getString("UTF-8");

System.out.println("普通文本提交,键:"+fieldName+",提交的值(未解决乱码):"+value1+",解决乱码的:"+value2);
}else{//文件上传段
//3.4 提交的键
String fieldName = item.getFieldName();
//3.5 文件名
String name = item.getName();
//3.6 文件类型
String contentType = item.getContentType();

System.out.println("文件提交,键:"+fieldName+",文件名:"+name+"文件类型:"+contentType);

//3.7文件内容(非文本正文内容)
InputStream is = item.getInputStream();

FileOutputStream fos = new FileOutputStream("e:/upload/bbb.jpg");

IOUtils.copy(is,fos);
//3.8 删除临时文件
is.close();
fos.close();
item.delete();

}
}
}

}


}
原创粉丝点击