把文件从客户端传递到服务器的过程就是文件上传。
a、提供form表单,method必须是post
b、form表单的enctype必须是multipart/form-data
c、提供input type="file"类的上传输入域
作用:告知服务器请求正文的MIME类型。(请求消息头:Content-Type作用是一致的)
可选值:
l application/x-www-form-urlencoded(默认):
正文:name=admin&password=123
服务器获取数据:String name =request.getParameter("name");
l multipart/form-data:
正文:
服务器获取数据:request.getParameter(String)方法获取指定的表单字段字符内容,但文件上传表单已经不在是字符内容,而是字节内容,所以失效。
文件上传:解析请求正文的每部分的内容。
fileupload是由apache的commons组件提供的上传组件。它最主要的工作就是帮我们解析request.getInputStream()。
导入commons-fileupload相关jar包
l commons-fileupload.jar,核心包;
地址:http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi
l commons-io.jar,依赖包。
地址:http://commons.apache.org/proper/commons-io/download_io.cgi
DiskFileItemFactory、ServletFileUpload、FileItem。
a、解析原理
使用fileupload组件的步骤如下:
1. 创建工厂类DiskFileItemFactory对象:
DiskFileItemFactory factory = new DiskFileItemFactory()
2. 使用工厂创建解析器对象:
ServletFileUpload fileUpload = new ServletFileUpload(factory)
3. 使用解析器来解析request对象:
List
FileItem对象对应一个表单项(表单字段)。可以是文件字段或普通字段
l boolean isFormField():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段;
l String getFieldName():获取字段名称,例如:,返回的是username;
l String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文本文件;
l String getName():获取文件字段的文件名称;(a.txt)
l String getContentType():获取上传的文件的MIME类型,例如:text/plain。
l int getSize():获取上传文件的大小;
l InputStream getInputStream():获取上传文件对应的输入流;
l void write(File):把上传的文件保存到指定文件中。
l delete();删除临时文件
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
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.FileUploadBase;
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.FilenameUtils;
public class UploadServlet2 extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 判断表单的提交类型是否是enctype="multipart/form-data"
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
try {
// 创建一个解析器工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//factory.setRepository(new File("f:/"));//把临时文件保存到f盘下
// 通过工厂创建解析器
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTf-8");// 解决上传文件名乱码问题
// 限制单个文件上传的大小
upload.setFileSizeMax(1024 * 1024 * 3);// 文件限制为3M
// 限制文件上传的总大小
upload.setSizeMax(1024*1024*6);//文件总大小不能超过6M
// 解析request对象
List fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()) {// 判断是否是普通表单项(true:是普通表单项)
processFormField(fileItem);
} else {
processUploadFile(fileItem);
}
}
} catch (FileUploadBase.FileSizeLimitExceededException e) {
System.out.println("上传文件过大,不能超过3M");
} catch (FileUploadBase.SizeLimitExceededException e) {
System.out.println("上传文件过大,总大小不能超过6M");
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
// 解析上传文件表单项
private void processUploadFile(FileItem fileItem) {
try {
// 得到name的值 name="photo"
String name = fileItem.getFieldName();
// 得到文件名
String filename = fileItem.getName(); // F:\图片素材\有范儿\25.jpg 或 25.jpg
// 文件内容
InputStream in = fileItem.getInputStream();
System.out.println(name + "\t" + filename);
// 创建一个目录 File即代表文件又代表目录
File storeDirectory = new File(this.getServletContext()
.getRealPath("/upload"));
if (!storeDirectory.exists()) {
storeDirectory.mkdirs();// 创建目录
}
// 解决文件名路径问题
// filename = filename.substring(filename.lastIndexOf("/")+1);
filename = FilenameUtils.getName(filename);
//得到文件的扩展名
String extension = FilenameUtils.getExtension(filename);
//只能上传jpg和txt文件
/*if(!("jpg".equals(extension)||"txt".equals(extension))){
return;
}*/
// 解决文件名冲突的问题
filename = UUID.randomUUID() + "_" + filename;
// 创建子目录(目录打散)
String childDirectory = makeChildDirectory1(storeDirectory,
filename);
// 创建文件
File file = new File(storeDirectory, childDirectory + "/"
+ filename); // F:\\apache-tomcat-7.0.52\\webapps\\day20_00_upload\\upload\\F:\\图片素材\\有范儿\\25.jpg
// 创建一个文件输出流
fileItem.write(file);
/* OutputStream out = new FileOutputStream(file); int len = 0;
byte[] b = new byte[1024]; while((len=in.read(b))!=-1){
out.write(b, 0, len); }
out.close();
in.close();*/
fileItem.delete();//删除临时文件
} catch (Exception e) {
e.printStackTrace();
}
}
// 创建子目录2
private String makeChildDirectory1(File storeDirectory, String filename) {
int hashCode = filename.hashCode();// 得到一个32位的整数
String hexString = Integer.toHexString(hashCode);// 把整数转换成16进制的字符串
// 65fsad32fhf
String child = hexString.substring(0, 1) + "/"
+ hexString.substring(1, 2); // 6/5
File childDirectory = new File(storeDirectory + "/" + child);
if (!childDirectory.exists()) {
childDirectory.mkdirs();
}
return child;
}
// 创建子目录(以日期为单位)
private String makeChildDirectory(File storeDirectory) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String fdate = sdf.format(date); // 2016-05-07
// 创建目录
File childDirectory = new File(storeDirectory + "/" + fdate);
if (!childDirectory.exists()) {
childDirectory.mkdirs();
}
return fdate;
}
// 解析普通表单项
private void processFormField(FileItem fileItem) {
try {
String name = fileItem.getFieldName();// 得到name="name"
String value = fileItem.getString("UTF-8");// 得到value
System.out.println(name + "=" + value);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DownloadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=GBK");
String filename = "销售榜单.csv";
//解决文件名不安全的问题
filename = URLEncoder.encode(filename, "UTF-8");
//告知客户端浏览器下载文件
response.setHeader("content-disposition", "attachment;filename="+filename);
//告知浏览器下载文件的格式
//例:images/jpeg 作用:this.getServletContext().getMimeType(filename)得到文件类型
response.setHeader("content-type", this.getServletContext().getMimeType(filename));
PrintWriter out = response.getWriter();
out.write("id,name,price\n");
out.write("1,冰箱,200\n");
out.write("2,电话机,300\n");
out.write("3,复读机,200\n");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
a、文件名处理的问题 得到简单的没有路径文件名31.jpg
// 解决文件名路径问题 filename = filename.substring(filename.lastIndexOf("/")+1);
filename = FilenameUtils.getName(filename);
b、避免文件被覆盖,让文件名唯一即可
// 解决文件名冲突的问题
filename = UUID.randomUUID() + "_" + filename;
c、避免同一个文件夹中的文件过多
方案一:按照日期进行打散存储目录
// 创建子目录(以日期为单位)
private String makeChildDirectory(File storeDirectory) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String fdate = sdf.format(date); // 2016-05-07
// 创建目录
File childDirectory = new File(storeDirectory + "/" + fdate);
if (!childDirectory.exists()) {
childDirectory.mkdirs();
}
return fdate;
}
方案二:用文件名的hashCode计算打散的存储目录:二级目录
// 创建子目录2
private String makeChildDirectory1(File storeDirectory, String filename) {
int hashCode = filename.hashCode();// 得到一个32位的整数
String hexString = Integer.toHexString(hashCode);// 把整数转换成16进制的字符串 // 65fsad32fhf
String child = hexString.substring(0, 1) + "/"
+ hexString.substring(1, 2); // 6/5
File childDirectory = new File(storeDirectory + "/" + child);
if (!childDirectory.exists()) {
childDirectory.mkdirs();
}
return child;
}
d、限制文件的大小:web方式不适合上传大的文件
单个文件大小:
ServletFileUpload.setFileSizeMax(字节)
总文件大小:(多文件上传)
ServletFileUpload.setSizeMax(字节)
// 创建一个解析器工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//factory.setRepository(new File("f:/"));//把临时文件保存到f盘下
// 通过工厂创建解析器
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTf-8");// 解决上传文件名乱码问题
// 限制单个文件上传的大小
upload.setFileSizeMax(1024 * 1024 * 3);// 文件限制为3M
// 限制文件上传的总大小
upload.setSizeMax(1024*1024*6);//文件总大小不能超过6M
// 解析request对象
List fileItems = upload.parseRequest(request);
e、上传字段用户没有上传文件的问题
通过判断文件名是否为空即可
f、临时文件的问题
DiskFileItemFactory:
作用:产生FileItem对象
内部有一个缓存,缓存大小默认是10Kb。如果上传的文件超过10Kb,用磁盘作为缓存。
存放缓存文件的目录在哪里?默认是系统的临时目录。
如果自己用IO流实现的文件上传,要在流关闭后,清理临时文件。
FileItem.delete();