注意事项
我们在文件上传的时候需要知道一下几个事项。
1.为了服务器的安全,上传的文件应该放在外界不能直接访问的文件夹下,比如我们可以放在WEB-INF目录下。
2.为了防止上传文件出现覆盖 现象,上传文件的文件名应该保持他的唯一性(时间戳、uuid、位运算……)。
3.要限制上传文件的最大值。
4.限制上传文件的类型,在确定完上传文件名之后,我们应该对文件的后缀名进行判断。
准备工作
我们在进行文件上传之前我们应该准备两个jar包,UUID是啥。
处理上传文件,我们一般是通过request.getInputStream()方法来进行 这样我会很麻烦。我们是用Apache,组件
commonsfileuploadhttps://mirrors.tuna.tsinghua.edu.cn/apache//commons/fileupload/binaries/commons-fileupload-1.4-bin.zip
他的核心以赖于commons-io组件https://mirror.bit.edu.cn/apache//commons/io/binaries/commons-io-2.8.0-bin.zip
UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准。UUID是一个128比特的数值,这个数值可以通过一定的算法计算出来。为了提高效率,常用的UUID可缩短至16位。UUID用来识别属性类型,在所有空间和时间上被视为唯一的标识。
创建项目
这里创建项目的方式有多种,不论你使用那一种创建方式,创建完之后都先要进行这两个jar的导入。
要把所导入的jar同时导入我们的项目目录下。
接下来就是写jsp页面,这里需要注意的是我们创建的from表单提交方式必须是post,enctype="multipart/form-data"类型必须这样写,这样服务器端才能从过流进行获取。<input type="file" name="file1" >
这里的name也是必须要写的,否则不能读取。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%-- get提交方式限制文件大小,文件大小只能为4kb左右--%>
<%-- post提交方式不限值文件大小--%>
<%--enctype="multipart/form-data" 表单类型这样是如果服务器端想获取数据就必须要通过流--%>
<%--这里必须加上这个 ${pageContext.request.contextPath}这是获取服务器路径的--%>
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post" >
上传用户:<input type="text" name="username"><br>
<input type="file" name="file1" ><br>
<input type="file" name="file2"><br>
<input type="submit">
</form>
</body>
</html>
Servlet
接下就是需要我们创建一个servlet,写好映射路径。
我们对表单进行一个判断,看其是否带有上传文件,如果不对就直接结束这个方法不往下走。
//第一步我们是先判断改表单是普通表单还是带有上床文件的表单
if (!FileUpload.isMultipartContent(request)){
return;//如果是普通的表单他就会true 否则false 此时这个程序就会终止 不在会往下执行
}
创建上传文件的路径
这里上传文件的路径在WEB-INF目录下,这样比较安全,外界并不能直接访问WEB-INF文件。有一个判断是判断当前路径下是否存在文件夹,如果不存就创建一个。
//创建上传文件的保存的路径
String upLoadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(upLoadPath);
if (!uploadFile.exists()){
uploadFile.mkdir();//如果不存在就创建一个
}
同时我们还需要创建一个临时文件夹,来进行缓冲临时文件。
//临时文件创建,如果文件大小超过我们的预期值,我们会把他存放在临时文件中,过几天会自动删除
String tem = this.getServletContext().getRealPath("/WEB-INF/tem");
File file1 = new File(tem);
if (!file1.exists()){
file1.mkdir();//创建一个临时目录
}
核心 代码
ServletFileUpload类负责处理上传文件的数据,并将表单中的每个输入项封装成Filetem对象中,使用其paseRequest(HttpServletRequest)方法可以将通过表单中每一个HTML标签提交的数据封装称一个Filetem对象,然后以List列表形式返回,使用改方法处理上文件简单易用。
ServletFileUpload类负责处理上传文件的数据,并将表单中的每个输入项封装成Filetem对象中,再使用ServletFileUpload对象解析请求时需DiskFileItemFactory对象,所以我们在需要进行解析工作前构造好DiskFileItemFactory对象,通过ServletFileUpload对象的构造方法后或setFileItemFactory()方法设置ServletUpLoad对象的fileItem。
对这些类了解完之后,核心步骤就三步,这里我们用了三个方法来写
1.创建DiskFileItemFactory,处理临时文件的上传路径或者大小的限制。
public static DiskFileItemFactory getDiskFileItemFactory(File file) {
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
diskFileItemFactory.setSizeThreshold(1024*1024);//文件缓冲区,超过这个缓冲区1M 会被存为临时文件
diskFileItemFactory.setRepository(file);
System.out.println("DiskFileItemFactor创建成功");
return diskFileItemFactory;
}
2获取ServletFileUpload ,监听文件的进度,设置文件的大小,这些是根据情况来的,不写也可以他会有默认值。
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
//监听文件上传进度
servletFileUpload.setProgressListener(new ProgressListener() {
@Override
//l以读文件大小 l1文件大小
public void update(long l, long l1, int i) {
System.out.println("文件大小为:"+l+"\t"+l1);
}
});
//处理乱码问题
servletFileUpload.setHeaderEncoding("utf-8");
//设置单个文件的上传最大值
servletFileUpload.setFileSizeMax(1024*1024*20);
//设置总共能上传文件的大小
servletFileUpload.setSizeMax(1024*1024*50);
return servletFileUpload;
}
3.处理这些上传文件。主要是通过parseRequest()来获取FileItem,
这里需要进行传三个参数,ServletFileUpload,HttpServletRequest ,upLoadPath。在这里根据自己的需要来进行编写。
public static String uploadParseRequest(ServletFileUpload servletFileUpload, HttpServletRequest request, String upLoadPath) {
String msg="文件上传";
try {
//把前端请求解析,封装成一个FileTem对象,从servletFileUpload中获取
List<FileItem> fileItems = servletFileUpload.parseRequest(request);
for (FileItem fileItem:fileItems) {
//判断上传表单是普通表单还是带有文件的表单
if (fileItem.isFormField()){
//获取表单控件名字
String fieldName = fileItem.getFieldName();
//处理中文乱码
String value = fileItem.getString("UTF-8");
System.out.println(fieldName+value);
}else{//现在是带有文件的表单
//处理文件---------------------
//获取文件名
String name = fileItem.getName();
System.out.println(name);
//trim()去除前后空格 判断文件名是否合法
if (name.trim().equals("")||name==null){
continue;//如果不合发他就会直接返回 判断下以位
}
//获取上传文件名 从最后以个/的下为开始截取
String filename = name.substring(name.lastIndexOf("/") + 1);
System.out.println(filename);
//获取文件的后缀名 用户判断文件名是否合法
String fileExtName = name.substring(name.lastIndexOf(".") + 1);
System.out.println(fileExtName);
// UUID.randomUUID()会生成一个唯一表示的通用码
String uuidPath= UUID.randomUUID().toString();
//文件地址---------------
//文件存放的真实路径
String realpath = upLoadPath + "/" + uuidPath;
File realPathFile = new File(realpath);
if (!realPathFile.exists()){
realPathFile.mkdir();
}
//文件传输------------ (这个传输过程是先读取本地输入流,再把本地文件上传到服务器上,输出流)
//获取文件上传输入的流
InputStream inputStream = fileItem.getInputStream();
//创建一个输出流
FileOutputStream fileOutputStream = new FileOutputStream(realpath + "/"+filename);
//创建一个缓冲区
byte[] bytes = new byte[1024 * 1024];
//判断是否读取完毕
int len=0;
while ((len=inputStream.read(bytes))>0){
fileOutputStream.write(bytes,0,len);
}
msg="文件上传成功";
inputStream.close();
fileOutputStream.close();
//上传成功清除临时文件
fileItem.delete();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return msg;
}
接下来就是写一些相应跳转
request.setAttribute("msg",msg);
request.getRequestDispatcher("info.jsp").forward(request,response);
上传完成之后我们需要在这个路径下来进行查找
这里我们可以看到他的文件名是uuid。
完整的servlet
package aw;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
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 javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.UUID;
@WebServlet(name = "FileuploadServlet",urlPatterns = {"/upload.do"})
public class FileuploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//第一步我们是先判断改表单是普通表单还是带有上床文件的表单
if (!FileUpload.isMultipartContent(request)){
return;//如果是普通的表单他就会true 否则false 此时这个程序就会终止 不在会往下执行
}
//创建上传文件的保存的路径
String upLoadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(upLoadPath);
if (!uploadFile.exists()){
uploadFile.mkdir();//如果不存在就创建一个
}
//临时文件创建,如果文件大小超过我们的预期值,我们会把他存放在临时文件中,过几天会自动删除
String tem = this.getServletContext().getRealPath("/WEB-INF/tem");
File file1 = new File(tem);
if (!file1.exists()){
file1.mkdir();//创建一个临时目录
}
//处理上传文件,我们一般是通过request.getInputStream()方法来进行 这样我会很麻烦
//我们是用Apache,组件commons-fileupload,他的核心以赖于commons-io组件
//1.创建DiskFileItemFactory对象,处理文件的上传路径或者大小的限制
DiskFileItemFactory factory = getDiskFileItemFactory(file1);
//2.获取ServletFileUpload
ServletFileUpload servletFileUpload = getServletFileUpload(factory);
System.out.println(servletFileUpload.getSizeMax()+"--------------");
//3.处理上传文件
String msg = uploadParseRequest(servletFileUpload, request, upLoadPath);
request.setAttribute("msg",msg);
request.getRequestDispatcher("info.jsp").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
public static DiskFileItemFactory getDiskFileItemFactory(File file) {
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
diskFileItemFactory.setSizeThreshold(1024*1024);//文件缓冲区,超过这个缓冲区1M 会被存为临时文件
diskFileItemFactory.setRepository(file);
System.out.println("DiskFileItemFactor创建成功");
return diskFileItemFactory;
}
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
//监听文件上传进度
servletFileUpload.setProgressListener(new ProgressListener() {
@Override
//l以读文件大小 l1文件大小
public void update(long l, long l1, int i) {
System.out.println("文件大小为:"+l+"\t"+l1);
}
});
//处理乱码问题
servletFileUpload.setHeaderEncoding("utf-8");
//设置单个文件的上传最大值
servletFileUpload.setFileSizeMax(1024*1024*20);
//设置总共能上传文件的大小
servletFileUpload.setSizeMax(1024*1024*50);
return servletFileUpload;
}
public static String uploadParseRequest(ServletFileUpload servletFileUpload, HttpServletRequest request, String upLoadPath) {
String msg="文件上传";
try {
//把前端请求解析,封装成一个FileTem对象,从servletFileUpload中获取
List<FileItem> fileItems = servletFileUpload.parseRequest(request);
for (FileItem fileItem:fileItems) {
//判断上传表单是普通表单还是带有文件的表单
if (fileItem.isFormField()){
//获取表单控件名字
String fieldName = fileItem.getFieldName();
//处理中文乱码
String value = fileItem.getString("UTF-8");
System.out.println(fieldName+value);
}else{//现在是带有文件的表单
//处理文件---------------------
//获取文件名
String name = fileItem.getName();
System.out.println(name);
//trim()去除前后空格 判断文件名是否合法
if (name.trim().equals("")||name==null){
continue;//如果不合发他就会直接返回 判断下以位
}
//获取上传文件名 从最后以个/的下为开始截取
String filename = name.substring(name.lastIndexOf("/") + 1);
System.out.println(filename);
//获取文件的后缀名 用户判断文件名是否合法
String fileExtName = name.substring(name.lastIndexOf(".") + 1);
System.out.println(fileExtName);
// UUID.randomUUID()会生成一个唯一表示的通用码
String uuidPath= UUID.randomUUID().toString();
//文件地址---------------
//文件存放的真实路径
String realpath = upLoadPath + "/" + uuidPath;
File realPathFile = new File(realpath);
if (!realPathFile.exists()){
realPathFile.mkdir();
}
//文件传输------------
//获取文件上传输入的流
InputStream inputStream = fileItem.getInputStream();
//创建一个输出流
FileOutputStream fileOutputStream = new FileOutputStream(realpath + "/"+filename);
//创建一个缓冲区
byte[] bytes = new byte[1024 * 1024];
//判断是否读取完毕
int len=0;
while ((len=inputStream.read(bytes))>0){
fileOutputStream.write(bytes,0,len);
}
msg="文件上传成功";
inputStream.close();
fileOutputStream.close();
//上传成功清除临时文件
fileItem.delete();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return msg;
}
}