一:需要的jar包
commons—io.jar
commons—fileupload.jar这个包对io有依赖
二:上传三部曲
相关类:
工厂:DiskFileItemFactory
解析器:ServletFileUpload
表单项:FileItem
1)创建工厂
DiskFileItemFactory factory = new DiskFileItemFactory ();
2)创建解析器
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
3)使用解析器来解析request,得到FileItem集合
List<FileItem> fileItem = servletFileUpload.parseRequest(request);
三:源码
1.jsp
<%-- Created by IntelliJ IDEA. User: YuWenHui Date: 2017/4/12 0012 Time: 14:00 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>上传图片</title> </head> <body> <h1>上传1</h1> <form action="<c:url value='/FileUploadServlet'/>" method="post" enctype="multipart/form-data"> 用户名;<input type="text" name="username"/><br/> 照 片:<input type="file" name="zhaoPian"/><br/> <input type="submit" value="上传"/> </form> </body> </html>
2:配置文件
servlet> <servlet-name>FileUploadServlet</servlet-name> <servlet-class>servlet.FileUploadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FileUploadServlet</servlet-name> <url-pattern>/FileUploadServlet</url-pattern> </servlet-mapping>
3:servlet
package servlet;
import cn.itcast.commons.CommonUtils;
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 java.io.File;
import java.io.IOException;
import java.util.List;
/**
* Created by YuWenHui on 2017/4/12 0012.
*/
public class FileUploadServletPlus extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
// 得到工厂
DiskFileItemFactory diskFileItemFactory=new DiskFileItemFactory();
// 创建解析器
ServletFileUpload servletFileUpload =new ServletFileUpload(diskFileItemFactory);
// 得到FIleItem集合
try {
List<FileItem> fileItemList = servletFileUpload.parseRequest(request);
FileItem fileItem1 = fileItemList.get(0);
FileItem fileItem2 = fileItemList.get(1);
// 演示普通表单项
System.out.println("普通表单项:"+fileItem1.getFieldName()+":"+fileItem1.getString("utf-8"));
// 演示文件表单项
System.out.println("文件表单项目演示:");
System.out.println("ContentType:"+fileItem2.getContentType());
System.out.println("名称:"+fileItem2.getName());
System.out.println("size:"+fileItem2.getSize());
// 获取文件的绝对路径
String rootPath = this.getServletContext().getRealPath("/WEN-INF/files/");
String fileName = fileItem2.getName();
// 处理文件上传绝对路径问题
int index = fileName.lastIndexOf("\");
if (index != -1){
fileName = fileName.substring(index+1);
}
// 给文件名添加UUID来处理文件的同名问题
String saveName = CommonUtils.uuid()+"_"+fileName;
// 得到hashCode
int hashCode = fileName.hashCode();
// 将hashCode转换成16进制
String hex = Integer.toHexString(hashCode);
// 生成完整路径
File dirFile = new File(rootPath,hex.charAt(0)+"/"+hex.charAt(1));
// 创建目录链
dirFile.mkdirs();
// 创建目录文件
File destFile = new File(dirFile,saveName);
// 保存文件
fileItem2.write(destFile);
System.out.println("文件保存在:"+dirFile);
System.out.println(rootPath);
} catch (FileUploadException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
}
}
四:上传的细节
1:文件必须保存到WEB-INF下
目的是不让浏览器直接访问到,防止攻击
2:关于文件名的问题
1.个别浏览器上传的是完整路径,需要切割
如:上传的是E:/JavaWeb/***.jpg,我们只需要***.jpg
//获取文件名 String filename = fileItem2.getName(); //java里面/符号需要转义,如果没用则返回-1 int index = fulename.lastIndexOf("\"); if(index != -1){ filename = filename.subString(index+1); }
2.文件名乱码或者普通表单项中乱码
request.setCharacterEnCoding("utf-8))是有效的,因为fileUpload内部会调用request.getCharacterEnCoding()
servletFileUpload.setHeanderencoding("utf-8")优先级高
3.文件同名问题
使用UUID来为每个文件添加前缀,扩展名不能更改
这里需要是tools.jar包,而tool.jar对commons-beanutils和commons-logging.jar两个包存在依赖
filename = commonUtils.uuid()+"_"+filename;
3:目录打散问题
不能在一个目录下存放过多的文件,存放过多时,打开目录速度变慢,并不易读取
*哈希打散:
通过文件名称得到int值,即调用hashCode()
将int值换成16进制,获取16进制的前两位用来生成目录,即生成2级目录
// 获取文件的绝对路径 String rootPath = this.getServletContext().getRealPath("/WEN-INF/files/"); String fileName = fileItem2.getName(); // 处理文件上传绝对路径问题 int index = fileName.lastIndexOf("\"); if (index != -1){ fileName = fileName.substring(index+1); } // 给文件名添加UUID来处理文件的同名问题 String saveName = CommonUtils.uuid()+"_"+fileName; // 得到hashCode int hashCode = fileName.hashCode(); // 将hashCode转换成16进制 String hex = Integer.toHexString(hashCode); // 生成完整路径 File dirFile = new File(rootPath,hex.charAt(0)+"/"+hex.charAt(1)); // 创建目录链 dirFile.mkdirs(); // 创建目录文件 File destFile = new File(dirFile,saveName); // 保存文件 fileItem2.write(destFile); System.out.println("文件保存在:"+dirFile); System.out.println(rootPath);
4:文件的大小限制
单个文件的大小限制和整个请求的大小限制
servletFileUpload.setFileSizeMax(2*1024*1024);//限制单个文件的大小为2M servletFileUpload.setSizeMax(4*1024*1024);//限制整个表单大小为4M
必须在解析之前对文件或者表单进行限制,即servFileUpload.parseRequest(request);函数调用之前使用
若超出大小parseRequest函数将抛出异常
超大文件的上传:
可能和对文件的大小进行限制的方法有冲突
需要在DiskFileItemFactory()创建时添加2个参数,如
DiskFileItemFactory diskFileItemFactory=new DiskFileItemFactory(20*1024,new File("E:/JavaWebSrc/FileUpload/"));
5:上传不能是用BaseServlet
当上传文件时,request.getParametere()方法的返回值永远为null