Java实现文件上传详解

发布时间:2025-12-09 18:29:19 浏览次数:5

文件上传的原理

ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象,在使用

ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造好

DiskFileItemFactory对象,通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象

fileItemFactory属性

ServletFileUpload类

ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象中,使用其parseRequest(HttpServletRequest)方法

可以将通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回,使用该方法处理上传文件简单易用
trim()方法去掉首尾空格

实现过程

前端提交form表导致FileServlet中

我们在FileServlet中实现上传文件的功能
1.首先
判断上传的文件是普通表单还是带文件的表单

if(!ServletFileUpload.isMultipartContent(request)){return;//终止方法运行,说明这是一个普通的表单,直接返回}

2.创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件

String uploadPath=this.getServletContext().getRealPath("/WEB-INF/upload");File uploadFile=new File(uploadPath);if(!uploadFile.exists()){uploadFile.mkdir();//创建这个目录}System.out.println("创建目录成功");

3.缓存,临时文件:文件超过规定大小,被弄成临时文件,过几天自动删除,或者提醒用户转存为永久

String tmpPath=this.getServletContext().getRealPath("/WEB-INF/upload");File file=new File(tmpPath);if(!file.exists()){file.mkdir();//创建这个目录}

4.处理上传的文件,一般需要通过流来获取,我们可以使用request.getInputStream(),原生态的文件上传流获取,十分麻烦
但是我们都建议使用Apache的文件上传组件来实现,common-fileupload,它需要依赖于commons-io组件:
🌟创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的:
DiskFileItemFactory factory=new DiskFileItemFactory();
通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中:
factory.setSizeThreshold(1024*1024);
actory.setRepository(file);

DiskFileItemFactory factory=getDiskFileItemFactory(file);//======================================================DiskFileItemFactory getDiskFileItemFactory(File file){DiskFileItemFactory factory=new DiskFileItemFactory();//通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中:factory.setSizeThreshold(1024*1024);factory.setRepository(file);return factory;}

5.获取ServletFileload 用来监听
监听文件的上传进度

ServletFileUpload upload=getServletFileUpload(factory);//=====================================================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);//设置总共能够上传文件的大小//1024=1kb*1024=1M*10=10Mupload.setSizeMax(1024*1024*10);return upload;}

6.处理上传文件

String msg=uploadParseRequest(upload,request,uploadPath);//=======================================================String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request,String uploadPath){String msg="上传失败";try {List<FileItem> fileItems=upload.parseRequest(request);//fileItem每一个表单对象for (FileItem fileItem : fileItems) {//判断上传的文件是普通的表单还是带文件的表单if(fileItem.isFormField()){//getFiledName指的是前端表单控件的name;String name=fileItem.getFieldName();String value=fileItem.getString("UTF-8");System.out.println(name+":"+value);}else{//如果是文件表单//1.处理文件=================String uploadFileName=fileItem.getName();System.out.println("上传的文件名:"+uploadFileName);//可能存在文件名不合法的情况if(uploadFileName.trim().equals("")||uploadFileName==null){continue;}//获得上传的文件名 /images/gurl/paojie.pngString fileName=uploadFileName.substring(uploadFileName.lastIndexOf("/")+1);//获得文件的后缀名String fileExtName=uploadFileName.substring(uploadFileName.lastIndexOf(".")+1);/** 如果文件的后缀名fileExtName不是我们所要的* 就直接return 不处理,告诉用户文件类型不对* *///可以使用UUID(唯一识别的通用码),保证文件名唯一//UUID.randomUUID() 随机生成一个唯一识别的通用码//网络传输中的东西都需要序列化,//POJO,实体类只能在本机上用,如果想要在多个电脑上运行,传输===》需要把对象都序列化了//implements Serializable 没有方法的接口-》标记接口。JVM虚拟机在运行的时候,JVM的本地方法栈-- native->c++//JNI=java Native Interface->java 本地化接口//Java栈//UUID 通过位运算,生成随机序列号保证不重复性String uuidPath = UUID.randomUUID().toString();//2.存放地址=================//存到哪?uploadPath//文件真实存在的路径realPathString realPath=uploadPath+"/"+uuidPath;//给每个文件创建一个对应的文件夹File realPathFile=new File(realPath);if(!realPathFile.exists()){realPathFile.mkdir();}//3.文件传输=================//获取文件上传的流InputStream inputStream=fileItem.getInputStream();//创建一个文件输出流//realPath=真实的文件夹//差了一个文件,加上输出文件的名字+"/"+uuidFileNameFileOutputStream 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);}msg="上传文件成功";//关闭流fos.close();inputStream.close();fileItem.delete();//上传文件成功,清除临时文件}}} catch (FileUploadException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return msg;}

7.最后得到文件上传的结果利用Servlet请求转发

//servlet请求转发消息request.setAttribute("msg",msg);request.getRequestDispatcher("info.jsp").forward(request,response);

完整代码

package com.lding.servlet;import org.apache.commons.fileupload.FileItem;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.http.HttpServletRequest;import java.io.*;import java.util.List;import java.util.UUID;/*** @program: FileTransport* @description: ${description}* @author: 王丁* @date: 2021-11-11 11:25**/public class FileServlet extends javax.servlet.http.HttpServlet {protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {System.out.println("进入FileServlet");//判断上传的文件是普通表单还是带文件的表单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();//创建这个目录}System.out.println("创建目录成功");//缓存,临时文件//文件超过规定大小,被弄成临时文件,过几天自动删除,或者提醒用户转存为永久String tmpPath=this.getServletContext().getRealPath("/WEB-INF/upload");File file=new File(tmpPath);if(!file.exists()){file.mkdir();//创建这个目录}//处理上传的文件,一般需要通过流来获取,我们可以使用request.getInputStream(),原生态的文件上传流获取,十分麻烦//但是我们都建议使用Apache的文件上传组件来实现,common-fileupload,它需要依赖于commons-io组件:/*ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个FileTtem对象在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象对象的fileItemFactory属性*/DiskFileItemFactory factory=getDiskFileItemFactory(file);// //🌟监听文件上传的进度ServletFileUpload upload=getServletFileUpload(factory);//3.🌟处理上传文件String msg=uploadParseRequest(upload,request,uploadPath);//servlet请求转发消息request.setAttribute("msg",msg);request.getRequestDispatcher("info.jsp").forward(request,response);}DiskFileItemFactory getDiskFileItemFactory(File file){DiskFileItemFactory factory=new DiskFileItemFactory();//通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中:factory.setSizeThreshold(1024*1024);factory.setRepository(file);return factory;}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);//设置总共能够上传文件的大小//1024=1kb*1024=1M*10=10Mupload.setSizeMax(1024*1024*10);return upload;}String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request,String uploadPath){String msg="上传失败";try {List<FileItem> fileItems=upload.parseRequest(request);//fileItem每一个表单对象for (FileItem fileItem : fileItems) {//判断上传的文件是普通的表单还是带文件的表单if(fileItem.isFormField()){//getFiledName指的是前端表单控件的name;String name=fileItem.getFieldName();String value=fileItem.getString("UTF-8");System.out.println(name+":"+value);}else{//如果是文件表单//1.处理文件=================String uploadFileName=fileItem.getName();System.out.println("上传的文件名:"+uploadFileName);//可能存在文件名不合法的情况if(uploadFileName.trim().equals("")||uploadFileName==null){continue;}//获得上传的文件名 /images/gurl/paojie.pngString fileName=uploadFileName.substring(uploadFileName.lastIndexOf("/")+1);//获得文件的后缀名String fileExtName=uploadFileName.substring(uploadFileName.lastIndexOf(".")+1);/** 如果文件的后缀名fileExtName不是我们所要的* 就直接return 不处理,告诉用户文件类型不对* *///可以使用UUID(唯一识别的通用码),保证文件名唯一//UUID.randomUUID() 随机生成一个唯一识别的通用码//网络传输中的东西都需要序列化,//POJO,实体类只能在本机上用,如果想要在多个电脑上运行,传输===》需要把对象都序列化了//implements Serializable 没有方法的接口-》标记接口。JVM虚拟机在运行的时候,JVM的本地方法栈-- native->c++//JNI=java Native Interface->java 本地化接口//Java栈//UUID 通过位运算,生成随机序列号保证不重复性String uuidPath = UUID.randomUUID().toString();//2.存放地址=================//存到哪?uploadPath//文件真实存在的路径realPathString realPath=uploadPath+"/"+uuidPath;//给每个文件创建一个对应的文件夹File realPathFile=new File(realPath);if(!realPathFile.exists()){realPathFile.mkdir();}//3.文件传输=================//获取文件上传的流InputStream inputStream=fileItem.getInputStream();//创建一个文件输出流//realPath=真实的文件夹//差了一个文件,加上输出文件的名字+"/"+uuidFileNameFileOutputStream 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);}msg="上传文件成功";//关闭流fos.close();inputStream.close();fileItem.delete();//上传文件成功,清除临时文件}}} catch (FileUploadException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return msg;}protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {}}

运行结果

如果对您有帮助,免费的赞点一个~感谢🙏

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477