目录
1.简述
在一个web项目中,用户向工程中上传文件是十分常见的操作,如头像设置、背景图片设置等。服务器在保存用户上传的文件的时候,需要解决以下四个问题:1.用户上传的文件不能直接通过在地址栏输入url去访问;2.用户上传的文件不能被覆盖(在同一个文件夹下的同名文件会被覆盖)。
这篇文章将简单讲解如何在Javaweb项目上传文件并解决上面提到的四个问题
2.原理讲解
上传文件的表单如图所示
一般在处理上传文件的时候,用流来处理,但是这样的话需要自己实现网络通信底层,太麻烦了,这里使用apache的commons-io组件来完成。
ServletFileUpload类负责处理上传的文件数据,并将表单中的每个输入项封装成FileItem对象。在获取ServletFileUpload对象的时候,需要一个DiskFileItemFactory对象
通过ServletFileUpload对象获得FileItem对象后,遍历所有的FileItem对象,判断每个对象只是简单的表单元素还是包含了文件,若包含了文件,将文件进行处理保存,并转发到上传信息的页面就好了。
3.代码如下(含注释)
3.1获得DiskFileItemFactory对象
public DiskFileItemFactory getDiskFileItemFactory(File tempFile){
DiskFileItemFactory factory = new DiskFileItemFactory();
// 为上传文件设置一个大小限定,当文件超过这个大小的时候,缓存在暂存区
factory.setSizeThreshold(1024*1024); //大小为1M
factory.setRepository(tempFile); //设置暂存区
return factory;
}
3.2获得ServletFileUpload对象
public ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setProgressListener(new ProgressListener() {
@Override
// pBytesRead:已经读取的文件大小
// pContentLength:文件总大小
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("总大小:"+ pContentLength + ";已上传:" + pBytesRead);
}
});
// 处理乱码问题
upload.setHeaderEncoding("UTF-8");
// 设置单个文件的最大值
upload.setFileSizeMax(1024*1024*10);
// 设置总共能够上传文件的大小
upload.setSizeMax(1024*1024*10);
return upload;
}
3.3上传文件
public void uploadFile(HttpServletRequest req, HttpServletResponse resp,ServletFileUpload upload, String uploadPath) throws IOException, ServletException {
String msg = "文件上传失败";
// 把前端请求解析,封装成一个FileItem对象,从ServletFIleUpload对象中获取
List<FileItem> fileItems = null;
try {
fileItems = upload.parseRequest(req);
} catch (FileUploadException e) {
e.printStackTrace();
}
for (FileItem fileItem : fileItems) {
// 当前FileItem对象只是一个表单对象
if(fileItem.isFormField()){
String name = fileItem.getFieldName(); //获得表单控件的name值
String value = fileItem.getString("UTF-8");//获得文本,处理乱码
System.out.println(name+" :"+value);
}else {
// 当前FileItem包含文件
// ===========================处理文件===============================
String uploadFileName = fileItem.getName();
if(uploadFileName.trim().equals("") || uploadFileName==null){
continue;
}
// 获得上传的文件名
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/")+1);
// 获得上传的文件后缀
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1);
// 使用UUID获得一个唯一的识别通用码,保证文件名唯一
// 网络传输中的东西,都需要序列化
// 实体类如果想要在多个电脑上运行,需要进行传输===》使用序列号
String uuidPath = UUID.randomUUID().toString();
// ==========================存放地址==========================================
String readPath = uploadPath+"/"+uuidPath;
// 给每个文件创建也给对应的文件夹
File realPathFile = new File(readPath);
if(!realPathFile.exists()){
realPathFile.mkdir();
}
// ===========================文件传输==========================================
// 获得文件上传的流
InputStream inputStream = fileItem.getInputStream();
// 创建一个文件输出流
FileOutputStream fos = new FileOutputStream(readPath+"/"+fileName);
// 创建一个缓冲区
byte[] buffer = new byte[1024*1024];
// 判断是否读取完毕
int len = 0;
while ((len=inputStream.read(buffer))>0){
fos.write(buffer, 0, len);
}
// 关闭流
fos.close();
inputStream.close();
}
msg = "文件上传成功";
}
req.setAttribute("msg", msg);
req.getRequestDispatcher("info.jsp").forward(req, resp);
}
3.4 doPost()
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 判断上传的文件是普通表单还是带文件的表单
String msg = "文件上传失败";
if(!ServletFileUpload.isMultipartContent(req)){
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 tmpFile = new File(tmpPath);
if(!tmpFile.exists()){
tmpFile.mkdir();
}
// 处理上传的文件,一般需要通过流来获取
// 此处使用apache的组件来实现 commons-io
/*
* ServletFileUpload负责处理上传的文件数据,并将表单中的每个输入项封装成fileItem对象
* 在使用ServletFileUpload对象解析请求时需要DIskFileItemFactory对象
* 所有,需要在进行解析工作前构造好DiskFileItemFactory对象*/
// 1. 创建DiskFileIntemFactory对象,处理文件上传路径或者大小限制
DiskFileItemFactory factory = getDiskFileItemFactory(tmpFile);
// 2。获取ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);
// 3.处理上传文件
uploadFile(req, resp,upload, uploadPath);
}
补充:通过表单上传文件,get方法对上传文件的大小有限制,post方法没有限制,所以一般使用post方法。而且使用get方法的话在获取ServletFileUpload时会出错。另外,表单如果包含一个文件上传输入的话,这个表单的enctype属性就必须设置为multipart/form-data。
4.运行结果
通过表单提交了文件后,可以在tomcat目录下找到项目文件夹,在WEB-INF目录下就多出了upload和temp这两个文件夹,上传的文件都保存在这两个文件夹下面。