导入jar包,或者maven
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
使用类的介绍
【文件上传的注意事项】
1. 为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于web-inf目录下。
2. 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
3. 要限制上传文件的最大值。
4. 可以限制上传文件的类型,在收到上传文件名时,判断后级名是否合法。
【需要用到的类详解】
ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个filetem对象,在使用ServletFileUpload对象解析请求时需要DiskFileltemFactory对象。所以,我们需要在进行解析工作前构造好DikFileltemFactory对象,通过ServletFileUpload对象的构造方法或setFileltemFactory( ) 设置ServletFileUpload对象的fileltemFactory属性。
Fileltem类
在HTML页面input必须有 name<input type="file" name="filename">
表单如果包含一个文件上传输入项的话,这个表单的enctype属性就必须设置为 multipart / form-data
浏览器表单的类型如果为 multipart / form-data, 在服务器想获取数据就要通过流
【常用方法介绍】
//isFormField 方法用于判断FileItem类对象封装的数据是一个普通文本表单
//还是一个文件表单,如果是普通表单字段则返回true,否则返回false
boolean isFlormField();
//getFieldName方法用于返回表单标签name属性的值
String getFieldName();
//getString 方法用于将FileItem对象中保存的数据流内容以一个字符串返回
String getString();
//getName 方法用于获得文件上传字段中得文件名
String getName();
//以流得形式返回上传文件得数据内容
InputStream getInputStream();
//delete方法用来清空FileItem类对象中存放的主体内容
//如果主题内容被保存在临时文件中,delete方法将删除临时文件
void delete();
ServletFileUpload类
ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个Fileltem对象中,使用其paraRequest(HttpServletRequest)方法可以将通过表单中每一个HTML标签提交的数据封装成一个Fileltem对象,然后以List列表的形式返回,使用该方法处理上传文件简单易用。
代码编写
UploadFileServlet
packagecom.yatian.servlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.util.List;importjava.util.UUID;importorg.apache.commons.fileupload.FileItem;importorg.apache.commons.fileupload.FileUploadException;importorg.apache.commons.fileupload.ProgressListener;importorg.apache.commons.fileupload.disk.DiskFileItemFactory;importorg.apache.commons.fileupload.servlet.ServletFileUpload;public class FileServlet extendsHttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throwsjavax.servlet.ServletException, IOException {//判断上传的表单是普通表单还是带文件的表单,是返回true,否返回false;
if (!ServletFileUpload.isMultipartContent(request)){return;//如果这是一个普通文件我们直接返回
}//如果通过了这个if,说明我们的表单是带文件上传的//创建上传文件的保存目录,为了安全建议在WEB-INF目录下,用户无法访问
String uploadpath = this.getServletContext().getRealPath("WEB-INF/Upload");//获取上传文件的保存路径
File uploadfile = newFile(uploadpath);if (!uploadfile.exists()){
uploadfile.mkdir();//如果目录不存在就创建这样一个目录
}/*//临时文件
//临时路径,如果上传的文件超过预期的大小,我们将它存放到一个临时目录中,过几天自动删除,或者提醒用户转存为永久
String tmppath = this.getServletContext().getRealPath("WEB-INF/tmp");
File file = new File(tmppath);
if (!file.exists()){
file.mkdir();//如果目录不存在就创建这样临时目录
}*/
//处理上传的文件一般需要通过流来获取,我们可以通过request.getInputstream(),原生态文件上传流获取,十分麻烦//但是我们都建议使用Apache的文件上传组件来实现,common-fileupload,它需要依赖于common-io组件;
try{//1、创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
DiskFileItemFactory factory =gteDiskFileItemFactory(file);//2、获取ServletFileUpload
ServletFileUpload upload =getServletFileUpload(factory);//3、处理上传文件
String msg =uploadParseRequest(upload,request,uploadpath);//Servlet请求转发消息
request.setAttribute("msg",msg);
request.getRequestDispatcher("/info.jsp").forward(request,response);
}catch(FileUploadException e){
e.printStackTrace();
}
}public staticDiskFileItemFactory gteDiskFileItemFactory(File file){//1、创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
DiskFileItemFactory factory = newDiskFileItemFactory();//通过这个工厂设置一个缓冲区,当上传的文件大小大于缓冲区的时候,将它放到临时文件中;
factory.setSizeThreshold(1024 * 1024);//缓冲区大小为1M
factory.setRepository(file);returnfactory;
}public staticServletFileUpload getServletFileUpload(DiskFileItemFactory factory){//2、获取ServletFileUpload
ServletFileUpload upload = newServletFileUpload(factory);/*//监听文件上传进度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long pBytesRead, long lpContentLenght, int i) {
//pBytesRead:已读取到的文件大小
//pContentLenght:文件大小
System.out.println("总大小:"+lpContentLenght+"已上传:"+pBytesRead);
}
});
//处理乱码问题
upload.setHeaderEncoding("UTF-8");
//设置单个文件的最大值
upload.setFileSizeMax(1024 * 1024 * 10);
//设置总共能够上传文件的大小
//1024 = 1kb * 1024 = 1M * 10 = 10M
upload.setSizeMax(1024 * 1024 * 10);*/
return upload;
}public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest request,String uploadpath) throwsIOException, FileUploadException { String msg= "";//3、处理上传文件//把前端的请求解析,封装成一个FileItem对象 List fileItems =upload.parseRequest(request);for(FileItem fileItem : fileItems) {if (fileItem.isFormField()){ //判断是普通表单还是带文件的表单//getFieldName指的是前端表单控件的name String name =fileItem.getFieldName(); String value= fileItem.getString("UTF-8");//处理乱码 System.out.println(name+":"+value); }else {//判断它是带文件的表单//======================处理文件=======================// //拿到文件的名字 String uploadFileName =fileItem.getName(); System.out.println("上传的文件名:"+uploadFileName);if (uploadFileName.trim().equals("") || uploadFileName == null){continue; }//获得上传的文件名,例如/img/girl/ooa.jpg,只需要ooa,其前面的后面的都不需要 String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);//获得文件的后缀名 String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);/** 如果后缀名 fileExtName 不是我们需要的 *就直接return,不处理,告诉用户类型不对 **/System.out.println("文件信息【文件名:"+fileName+"文件类型:"+fileExtName+"】");//可以使用UUID(唯一通用识别码)来保证文件名的统一 String uuidFileName =UUID.randomUUID().toString();//=======================传输文件=========================// //获得文件上传的流 InputStream inputStream =fileItem.getInputStream();//创建一个文件输出流 FileOutputStream fos = new FileOutputStream(uploadpath + "/" + uuidFileName +"."+fileExtName);//创建一个缓冲区 byte[] buffer = new byte[1024 * 1024];//判断是否读取完毕 int len = 0;//如果大于0,说明还存在数据 while ((len=inputStream.read(buffer))>0){ fos.write(buffer,0,len); }//关闭流 fos.close(); inputStream.close(); msg= "文件上传成功!"; fileItem.delete();//上传成功,清除临时文件 } }returnmsg; } }
//package com.cong.servlet;
//
//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 javax.servlet.ServletException;
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//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 FileServlet extends javax.servlet.http.HttpServlet{
// protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//
// //判断上传的文件是普通表单还是带文件的表单
// if(!ServletFileUpload.isMultipartContent(request)){
// return;//终止方法运行,说明这是一个普通的表单,直接返回
// }
//
// //创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件;
// String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
// File uploadFile = new File(uploadPath);
// if(!uploadFile.exists()){
// uploadFile.mkdir();//创建这个目录
// }
//
// //缓存,临时文件
// //临时路径,假如文件超过了预期的大小,我们就把他放到一个临时文件中,过几天自动删除,或者提醒用户转存为永久
// String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
// File file = new File(tmpPath);
// if(!file.exists()){
// file.mkdir();//创建这个临时文件目录
// }
//
// //处理上传的文件,一般都需要通过流来获取,我们可以使用request.getInputStream() ,原生态的文件上传流获取,十分麻烦
// //但是我们都建议使用Apache的文件上传组件来实现,common-fileupload, 它需要依赖于commons-io组件
//
// //1.创建DiskFileItemFactory对象,处理文件上传路径或者大小的限制的:
// DiskFileItemFactory factory = new DiskFileItemFactory();
// /*
// //通过这个工厂设置一个缓冲区,当上传的我呢见大于这个缓冲区的时候,将他放到临时文件中;
// factory.setSizeThreshold(1024*1024);//缓冲区大小为1M
// factory.setRepository(file);//临时目录的保存目录,需要一个File
// */
//
// //2.获取ServletFileUpload
// ServletFileUpload upload = new ServletFileUpload(factory);
//
// //3.处理上传的文件
// try {
// String msg = uploadParseRequest(upload,request,uploadPath);
// //servlet请求转发消息
// request.setAttribute("msg", msg);
// request.getRequestDispatcher("/info.jsp").forward(request,response);
// }catch (FileUploadException e){
// e.printStackTrace();
// }
//
//
//
//3.处理上传的文件
//把前端请求解析,封装成一个FileItem对象,需要从ServletFileUpload对象中获取
try {
List<FileItem> fileItems = upload.parseRequest(request);
//fileItem每一个表单对象
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{//文件
//=================处理文件====================//
//拿到文件的名字
String uploadFileName = fileItem.getName();
//可能出现文件名不合法的情况
if(uploadFileName.trim().equals("") || uploadFileName==null){
continue;
}
//获得上传的文件名 /images/girl/paojie.png
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/")+1);
//获得文件的后缀名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1);
//网络传输中的东西,都需要序列化
//POJO,实体类,如果想要早多个电视上运行, 传输====》需要把对象都序列化了
//implements Serializable : 标记接口 jvm----》本地方法栈 native----》C++
//可以使用UUID(唯一识别的通用码),保证文件名唯一;
//UUID.randomUUID(),随机生一个唯一识别的通用码
String uuidPath = UUID.randomUUID().toString();
//=================存放地址====================//
//存到哪? uploadPath
//文件真实存在的路径realPath
String realPath = uploadPath+"/"+uuidPath;
//给每个文件创建一个对应的文件夹
File realPathFile = new File(realPath);
if(!realPathFile.exists()){
realPathFile.mkdir();
}
//=================文件传输====================//
//获得文件上传的流
InputStream inputStream = fileItem.getInputStream();
//创建一个文件输出流
//realPath = 真实的文件夹
//差了一个文件;加上输出文件的名字+“/”+uuidFileName
FileOutputStream fos = new FileOutputStream(realPath+"/"+fileName);
//创建一个缓冲区
byte[] buffer = new byte[1024*1024];
//判断是否读取完毕
int len = 0;
//如果大于0说明还存在数据;
while((len = inputStream.read(buffer))>0){
fos.write(buffer, 0, len);
}
//关闭流
fos.close();
inputStream.close();
msg = "文件上传成功";
fileItem.delete();//上传成功,清除临时文件
}
return msg;
}
//
//
// }
//
// protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//
// }
// public static DiskFileItemFactory gteDiskFileItemFactory(File file){
1、创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
//
// DiskFileItemFactory factory = new DiskFileItemFactory();
//
通过这个工厂设置一个缓冲区,当上传的文件大小大于缓冲区的时候,将它放到临时文件中;
//
// factory.setSizeThreshold(1024 * 1024);//缓冲区大小为1M
//
// factory.setRepository(file);
//
// return factory;
//
// }
//
// public static String getServletFileUpload(DiskFileItemFactory factory){
2、获取ServletFileUpload
//
// ServletFileUpload upload = new ServletFileUpload(factory);
//
///*//监听文件上传进度
//
//upload.setProgressListener(new ProgressListener() {
//@Override
//
//public void update(long pBytesRead, long lpContentLenght, int i) {
pBytesRead:已读取到的文件大小
//
pContentLenght:文件大小
//
//System.out.println("总大小:"+lpContentLenght+"已上传:"+pBytesRead);
//
//}
//
//});
//
处理乱码问题
//
//upload.setHeaderEncoding("UTF-8");
//
设置单个文件的最大值
//
//upload.setFileSizeMax(1024 * 1024 * 10);
//
设置总共能够上传文件的大小
//
1024 = 1kb * 1024 = 1M * 10 = 10M
//
//upload.setSizeMax(1024 * 1024 * 10);
//
//return upload;
//
//}*/
//
// public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest request,String uploadpath) throws IOException, FileUploadException {
// String msg = "";
//
3、处理上传文件
//
把前端的请求解析,封装成一个FileItem对象
//
// List fileItems = upload.parseRequest(request);
//
// for (FileItem fileItem : fileItems) {
// if (fileItem.isFormField()){ //判断是普通表单还是带文件的表单
//
getFieldName指的是前端表单控件的name
//
// String name = fileItem.getFieldName();
//
// String value = fileItem.getString("UTF-8");//处理乱码
//
// System.out.println(name+":"+value);
//
// }else {//判断它是带文件的表单
//
======================处理文件=======================//
//
拿到文件的名字
//
// String uploadFileName = fileItem.getName();
//
// System.out.println("上传的文件名:"+uploadFileName);
//
// if (uploadFileName.trim().equals("") || uploadFileName == null){
// continue;
//
// }
//
获得上传的文件名,例如/img/girl/ooa.jpg,只需要ooa,其前面的后面的都不需要
//
// String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
//
获得文件的后缀名
//
// String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
//
// /*
//
// * 如果后缀名 fileExtName 不是我们需要的
//
// *就直接return,不处理,告诉用户类型不对
//
// * */
//
// System.out.println("文件信息【文件名:"+fileName+"文件类型:"+fileExtName+"】");
//
可以使用UUID(唯一通用识别码)来保证文件名的统一
//
// String uuidFileName = UUID.randomUUID().toString();
//
=======================传输文件=========================//
//
获得文件上传的流
//
// InputStream inputStream = fileItem.getInputStream();
//
创建一个文件输出流
//
// FileOutputStream fos = new FileOutputStream(uploadpath + "/" + uuidFileName +"."+ fileExtName);
//
创建一个缓冲区
//
// byte[] buffer = new byte[1024 * 1024];
//
判断是否读取完毕
//
// int len = 0;
//
如果大于0,说明还存在数据
//
// while ((len=inputStream.read(buffer))>0){
// fos.write(buffer,0,len);
//
// }
//
关闭流
//
// fos.close();
//
// inputStream.close();
//
// msg = "文件上传成功!";
//
// fileItem.delete();//上传成功,清除临时文件
//
// }
//
// }
//
// return msg;
//
// }
//
// }
//}
package com.cong.servlet;
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 javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.*;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
@WebServlet("/upload") // 定义 Servlet 映射路径
public class FileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 设置最大文件大小为 10MB
private static final int MAX_FILE_SIZE = 10 * 1024 * 1024;
// 设置内存缓冲区大小为 1MB
private static final int MEMORY_THRESHOLD = 1 * 1024 * 1024;
// 上传文件存储目录
private static final String UPLOAD_DIRECTORY = "WEB-INF/upload";
// 临时文件存储目录
private static final String TEMP_DIRECTORY = "WEB-INF/temp";
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 检查请求是否为多部分内容
if (!ServletFileUpload.isMultipartContent(request)) {
// 如果不是,设置错误信息并转发到 info.jsp
request.setAttribute("message", "错误:表单必须包含 enctype=multipart/form-data");
request.getRequestDispatcher("/info.jsp").forward(request, response);
return;
}
// 配置上传参数
DiskFileItemFactory factory = getDiskFileItemFactory(request);
ServletFileUpload upload = getServletFileUpload(factory);
// 设置整体请求的大小限制
upload.setSizeMax(MAX_FILE_SIZE);
// 确保上传目录存在
String uploadPath = getServletContext().getRealPath("/") + File.separator + UPLOAD_DIRECTORY;
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}
String message = "";
try {
// 解析请求的内容以提取文件数据
List<FileItem> formItems = upload.parseRequest(request);
if (formItems != null && !formItems.isEmpty()) {
// 遍历表单字段
for (FileItem item : formItems) {
// 处理非表单字段
if (item.isFormField()) {
String fieldName = item.getFieldName();
String fieldValue = item.getString("UTF-8");
System.out.println("普通表单字段:" + fieldName + " = " + fieldValue);
} else {
// 处理文件字段
String fileName = Paths.get(item.getName()).getFileName().toString();
if (fileName == null || fileName.trim().isEmpty()) {
message = "未选择文件上传";
continue;
}
// 检查文件大小
if (item.getSize() > MAX_FILE_SIZE) {
message = "文件大小超过限制(10MB)";
continue;
}
// 检查文件类型(根据需要,可以添加更多类型)
String fileExt = getFileExtension(fileName);
if (!isAllowedFileType(fileExt)) {
message = "不支持的文件类型:" + fileExt;
continue;
}
// 生成唯一的文件名,防止重名
String newFileName = UUID.randomUUID().toString() + "_" + fileName;
// 保存文件到指定路径
File storeFile = new File(uploadDir, newFileName);
try (InputStream inputStream = item.getInputStream();
FileOutputStream outputStream = new FileOutputStream(storeFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
message = "文件上传成功:" + newFileName;
System.out.println(message);
}
}
}
} catch (FileUploadException e) {
message = "错误信息: " + e.getMessage();
e.printStackTrace();
}
// 将消息存储在请求范围内
request.setAttribute("message", message);
// 转发到 info.jsp
request.getRequestDispatcher("/info.jsp").forward(request, response);
}
/**
* 配置 DiskFileItemFactory
*/
private DiskFileItemFactory getDiskFileItemFactory(HttpServletRequest request) {
// 配置工厂参数
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存缓冲区大小
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 设置临时文件存储位置
String tempPath = getServletContext().getRealPath("/") + File.separator + TEMP_DIRECTORY;
File tempDir = new File(tempPath);
if (!tempDir.exists()) {
tempDir.mkdirs();
}
factory.setRepository(tempDir);
return factory;
}
/**
* 配置 ServletFileUpload
*/
private ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
return new ServletFileUpload(factory);
}
/**
* 获取文件扩展名
*/
private String getFileExtension(String fileName) {
if (fileName == null || fileName.trim().isEmpty()) {
return "";
}
int dotIndex = fileName.lastIndexOf(".");
return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1).toLowerCase();
}
/**
* 检查是否为允许的文件类型
*/
private boolean isAllowedFileType(String fileExt) {
// 定义允许的文件类型(根据需求添加)
String[] allowedTypes = {"jpg", "jpeg", "png", "gif", "pdf", "doc", "docx"};
for (String type : allowedTypes) {
if (type.equalsIgnoreCase(fileExt)) {
return true;
}
}
return false;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 直接跳转到上传页面(根据实际情况调整)
response.sendRedirect("upload.jsp");
}
}