1 准备工作
对于文件上传,浏览器在上传的过程中是以流的形式提交到服务器端的。一般选择采用apache的开源工具common-fileUpload这个文件上传组件
common-fileUpload是依赖common-io这个包的,所以还需要下载这个包
2 使用类介绍
注意事项:
- 为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放在 WEB-INF目录下
- 为防止文件覆盖的情况发现,要为上传文件产生一个唯一的文件名
- 要限制上传文件的最大值
- 可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法
需要用到的类详解:
ServletFileUpload负责处理上传的文件数计,并将表单中每个输入项封装成一个Fileitem对象,在使用ServletFileUpload对象解析请求时需要DiskFileFactory对象,所以,我们需要在进行解析工作前构造好DiskFileitemFactory对象,通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性
3 FileItem类
在HTML页面input必须有name
例:
表单如果包含一个文件上传输入项的话,这个表单的enctype就必须设置为multipart/form-data
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
上传用户:<input type="text" name="username"><br/>
上传文件1:<input type="file" name="file1"><br/>
上传文件2:<input type="file" name="file2"><br/>
<input type="submit" value="提交">
</form>
浏览器表单的类型如果为multipart/form-data,在服务器端想获得数计就要通过流
常用方法
//isFormFiled方法用于判断FileItem类对象封装的数据是一个普通文本表单
//这是一个文件表单,如果是普通表单字段则返回true,否则返回false
boolean isFormFiled();
//getFieldName 方法用于返回表单标签name属性的值
String getFieldName();
//getString 方法用于将FileItem对象中保存的数据类内容以一个字符串返回
String getString();
//getName方法用于获得上传字段中的文件名
String getName();
//以流的形式返回上传文件的数据内容
InputStream getInputStream();
//delete方法用来清空FileItem对象中存放的主体内容
//如果主体内容被保存在临时文件中,delete方法将删除该临时问题
void delete();
3 ServletFileUpload
负责处理上传文件的数据,将表单中每个输入项封装成FileItem对象中,使用其parseRequest(HttpServletRequest)方法可以将通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回
常用方法:一个对象名为upload
- upload.setHeaderEncoding(“UTF-8”); 乱码问题
- upload.setFileSizeMax(int len); 设置单个文件最大值
- upload.setSizeMax(1024102410); 设置总共能够上传文件的大小
4 DiskFileItemFactory
一个可以获得ServletFileUpload类对象的工厂类,可以对于上传的文件做限制
对于大于
常用方法:
- setSizeThreshold(int len) 设置缓冲区大小
- setRepository(file2); 临时目录的保存目录,需要一个File对象
5 示例
前端页面核心代码:
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
上传用户:<input type="text" name="username"><br/>
上传文件1:<input type="file" name="file1"><br/>
上传文件2:<input type="file" name="file2"><br/>
<input type="submit" value="提交">
</form>
请求的searvlet
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
//几个步骤可以选择封装成方法
public class FileUploadServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//判断上传的文件是普通表单还是带文件的表单
if (!ServletFileUpload.isMultipartContent(request)){//如果是一个普通的表单
return;//终止方法运行
}
//创建上传文件的保存路径,建议保存在web-inf下面,安全,用户无法直接访问上传的文件
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File file = new File(uploadPath);
if (!file.exists()){
file.mkdir();//创建这个目录
}
//缓存,临时文件
//临时路径,假如文件超过了预期的大小,我们就把他放到一个临时文件中,过几天自动删除,或者提醒用户转存为永久
String temp = this.getServletContext().getRealPath("/WEB-INF/temp");
File file2 = new File(temp);
if (!file2.exists()){
file2.mkdir();//创建这个目录
}
//1.创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的
DiskFileItemFactory factory = new DiskFileItemFactory();
//通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中;
factory.setSizeThreshold(1024*1024);//缓冲区大小为1M
factory.setRepository(file2);//临时目录的保存目录,需要一个File
//2.获取ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);
//监听文件上传进度
upload.setProgressListener(new ProgressListener() {
public void update(long l, long l1, int i) {
System.out.println("总大小:"+l1+"已上传:"+l);
}
});
//处理乱码问题
upload.setHeaderEncoding("UTF-8");
//设置单个文件的最大值
upload.setFileSizeMax(1024*1024*10);
//设置总共能够上传文件的大小
upload.setSizeMax(1024*1024*10);
//3.处理上传的文件
//把前端请求解析,封装成一个FileItem对象
try {
List<FileItem> fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
//判断上传的表单是不是带文件的表单
if (fileItem.isFormField()){//这不是文件
//getFileName指的是前端表单控件的name
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8");//处理乱码
System.out.println(name+":"+value);
}else {//这是文件
//1、处理文件
String name = fileItem.getName();
//可能存在文件名不合法
if (name.trim().equals("")||name==null){
continue;
}
//获得上传的文件名 /**/**/**.mp4
String fileName = name.substring(name.lastIndexOf("/") + 1);
//获得文件的后缀名
String fileExtName = fileName.substring(fileName.lastIndexOf(".") + 1);
//判断后缀名。如果我们不需要这样的,就直接return,告诉用户类型不对
//省略判断文件类型
//可以利用uuid来保证文件名唯一
//UUID.randomUUID(),随机生成一个唯一识别的通用码
//网络传输中的东西都需要序列化
//POJO实体类,如果想要在多个电脑上运行,需要把对象序列化
//implements Serializable:标记接口,JVM--》本地方法站 native-->native
String uuidPath = UUID.randomUUID().toString();
//2、存放地址
//存到哪里 uploadPath
//文件真实存在的路径 realPath
String realPath = uploadPath + "/" + uuidPath;
//给每个文件创建一个对于的文件夹
File realPathFile = new File(realPath);
if (!realPathFile.exists()){
realPathFile.mkdir();
}
//3、文件传输
//获得上传文件的流
InputStream is = fileItem.getInputStream();
//创造一个文件输出流
FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
//创造一个缓冲区
byte[] buffer = new byte[1024 * 1024];
//开始传输
int len=0;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//关闭流
fos.close();
is.close();
//清除临时文件
fileItem.delete();
//返回消息 msg = "文件上传成功"
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
}
}