javaweb_文件传输

文件下载

步骤:

  1. 获取下载文件的路径

  2. 获取下载的文件名

  3. 设置想办法让浏览器能够支持下载我们需要的东西

  4. 获取下载文件的输入流

  5. 创建缓冲区

  6. 获取OutputStream对象

  7. 将FileOutputStream流写入缓冲区

  8. 使用OutputStream将缓冲区中的数据输出到客户端

编写servlet:

 package com.zcc.servlet;
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.net.URLEncoder;
 
 public class FileDownload extends HttpServlet {
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         //1. 获取下载文件的路径
         String filePath="D:\\JavaWeb\\源代码\\javaweb_file\\src\\main\\resources\\image\\04.png";
 
         //2. 获取下载的文件名
         String fileName=filePath.substring(filePath.lastIndexOf("\\")+1);
 
         //3. 设置想办法让浏览器能够支持下载我们需要的东西
         resp.setHeader("Content-disposition","attachment;filename=" + URLEncoder.encode(fileName,"utf-8"));
 
         //4. 获取下载文件的输入流
         FileInputStream fileInputStream = new FileInputStream(filePath);
 
         //5. 创建缓冲区
         int len=0;
         byte[] buffer = new byte[1024];
 
         //6. 获取OutputStream对象
         ServletOutputStream outputStream = resp.getOutputStream();
 
         //7. 将FileOutputStream流写入缓冲区
         while ((len=fileInputStream.read(buffer))>0){
             outputStream.write(buffer,0,len);
        }
 
         //8. 使用OutputStream将缓冲区中的数据输出到客户端
         outputStream.close();
         fileInputStream.close();
    }
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         doGet(req, resp);
    }
 }

注册servlet:

 <servlet>
     <servlet-name>FileDownload</servlet-name>
     <servlet-class>com.zcc.servlet.FileDownload</servlet-class>
 </servlet>
 <servlet-mapping>
     <servlet-name>FileDownload</servlet-name>
     <url-pattern>/FileDownload</url-pattern>
 </servlet-mapping>

启动测试:

 

文件上传

1. 搭建好项目,导入所需的jar包

浏览器文件上传其实就是以流的方式提交到服务端

 <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
 <dependency>
     <groupId>commons-io</groupId>
     <artifactId>commons-io</artifactId>
     <version>2.6</version>
 </dependency>
 
 <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
 <dependency>
     <groupId>commons-fileupload</groupId>
     <artifactId>commons-fileupload</artifactId>
     <version>1.4</version>
 </dependency>

2. 实现原理

 

 

文件上传的注意事项:

  1. 为保证服务器安全,上传的文件存放在外界无法直接访问的目录下,比如放在WEB-INF目录下。

  2. 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。(可以添加后缀:-时间戳、-uuid、-md5…)

  3. 限制上传文件的最大值。

  4. 可以限制上传文件的类型,在收到上传文件名时,判断后缀名知否合法。(.mp4、.txt、.jpg、.png、.doc…)

3. 使用类介绍

需要用到的类详解:

ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象, 在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象,通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性。

  • ServletFileUpload:在后端获取文件上传的文件数据,并将上传文件数据的表单中的每个输入项都封装为一个FileItem对象。

  • FileItem.

  • DiskFileItemFactory:使用ServletFileUpload解析前端表单传过来的文件数据时需要使DiskFileItemFactory对象,所以在获取ServletFileUpload对象之前我们需要先获取DiskFileItemFactory对象。

  • fileItemFactory属性:ServletFileUpload对象的一个属性。

 

文件上传用到的方法:

 //isFormField方法用于判断FileItem类对象封装的数据是一个普通文本表单
 //还是一个文件表单,如果是普通表单字段则返回true,否则返回false
 boolean isFormField();//即:只要是上传的文件,返回的就是false
 
 //getFieldName方法用于返回表单标签name属性的值。
 String getFieldName();//获取这个input的name属性值
 
 //getString方法用于将FileItem对象中保存的数据流内容以一个字符串返回
 String getString();//用字符串存储文件的数据流
     
 //getName方法用于获得文件上传字段中的文件名
 String getName();
 
 //以流的形式返回上传文件的数据内容。
 InputStream getInputStream()
 
 //delete方法用来清空FileItem类对象中存放的主体内容
 //如果主体内容被保存在临时文件中,delete方法将删除该临时文件。
 void delete();
 

4. 代码编写

编写主页

注意:

如果一个表单中包含文件数据,那么该表单如果想要提交文件数据,那么它必须包含enctype属性,且属性值必须为enctype=“multipart/form-data”

 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <html>
 <body>
 <%--
 通过表单上传文件
 method必须是post,因为:
     get:上传文件大小有限制
     post:上传文件大小没有限制
 --%>
 <form action="${pageContext.request.contextPath}/file.do" method="post" enctype="multipart/form-data">
     <p>上传用户:<input type="text" name="username"></p>
     <p>上传文件1:<input type="file" name="file01"></p>
     <p>上传文件2:<input type="file" name="file02"></p>
     <p><input type="submit"> <input type="reset"></p>
 </form>
 </body>
 </html>
 

编写文件上传的servlet,并注册

 package com.zcc.文件上传;
 
 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.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.*;
 import java.text.DecimalFormat;
 import java.util.List;
 import java.util.UUID;
 
 //文件上传
 public class FileUpload extends HttpServlet {
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 
         //判断上传的表单是普通表单(比如字符串)还是带文件的表单
         // ServletFileUpload.isMultipartContent(req) 返回true表示是带文件的表单 false是不带文件的
         if (!ServletFileUpload.isMultipartContent(req)){
             return; //return的含义就是代码执行到此终止 如果是普通文件 直接终止
        }
 
         //创建上传文件的保存目录,为了安全建议在WEB-INF目录下,用户无法访问 安全
         String fileUploadPath = this.getServletContext().getRealPath("WEB-INF/FileUpload");//获取上传文件的保存路径
         File file = new File(fileUploadPath);
         if (!file.exists()){
             file.mkdir(); //如果目录不存在就创建一个这样的目录
        }
 
         //临时文件
         //临时路径 如果上传的文件超过预期的大小,我们将它存放在一个临时目录中,过几天自动删除,或者提醒用户转存为永久
         String tmpPath = this.getServletContext().getRealPath("WEB-INF/tmp");
         File file2 = new File(tmpPath);
         if (!file2.exists()){
             file2.mkdir();
        }
 
         //处理上传的文件一般需要通过流来获取,我们可以通过request.getInputstream(),原生态文件上传流获取,十分麻烦。
         //所以我们都建议使用Apache的文件上传组件来实现,common-fileupload,它需要依赖于common-io组件
 
         try {
             //1. 创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
             DiskFileItemFactory factory =getDiskFileItemFactory(file2);
             //2. 获取ServletFileUpload
             ServletFileUpload upload = getServletFileUpload(factory);
             //3. 处理上传文件
             String msg = uploadParseRequest(upload, req, fileUploadPath);
             //Servlet请求转发消息
             req.setAttribute("msg",msg);
             req.getRequestDispatcher("info.jsp").forward(req,resp);
 
        } catch (FileUploadException e) {
             e.printStackTrace();
        }
    }
 
     public static DiskFileItemFactory getDiskFileItemFactory(File file){
         //1. 创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
         DiskFileItemFactory factory = new DiskFileItemFactory();
         //通过这个工厂设置一个缓冲区,当上传的文件大小大于缓冲区的时候,将它放到临时文件
         //这里不设置的话会有默认的
         factory.setSizeThreshold(1024*1024);  //缓冲区大小设置为1M
         factory.setRepository(file);
         return factory;
    }
 
     public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
         //2. 获取ServletFileUpload
         ServletFileUpload upload = new ServletFileUpload(factory);
         //监听文件上传进度
         upload.setProgressListener(new ProgressListener() {
             public void update(long pBytesRead, long lpContentLength, int i) {
                 //pBytesRead 已读取到的文件大小
                 //lpContentLength 文件大小
                 System.out.println("总大小:"+lpContentLength+"已上传:"+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 FileUploadException, IOException {
 
         String msg = "";
         //3、处理上传文件
         //把前端的请求解析,封装成一个FileItem对象。
         List<FileItem> fileItems = upload.parseRequest(request);
         for (FileItem fileItem : fileItems) {
             if (fileItem.isFormField()){ //判断是普通表单还是带文件的表单 普通文件返回true
                 //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,不处理,告诉用户文件类型不对。 
               */ 
​ 
               //可以使用UUID(唯一识别的通用码),保证文件名唯一。 
               //UUID.randomUUID,随机生一个唯一识别的通用码。 
​ 
               //网络传输中的东西,都需要序列化。 
               //pojo,实体类,如果想要在多个电脑运行,传输--->需要吧对象都序列化了。 
               //JNI=java Native Interface 
               //implements Serializable :标记接口,JVM--->java栈 本地方法栈 native-->c++ 
​ 
               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; 
  } 

​ 

 

 <servlet>
     <servlet-name>FileUpload</servlet-name>
     <servlet-class>com.zcc.servlet.FileUpload</servlet-class>
 </servlet>
 <servlet-mapping>
     <servlet-name>FileUpload</servlet-name>
     <url-pattern>/file.do</url-pattern>
 </servlet-mapping>

 

编写成功页面

 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <html>
 <head>
     <title>Title</title>
 </head>
 <body>
 ${msg}
 </body>
 </html>

运行测试:

下载的文件在target目录下

 

 
posted @   超、自律即自由  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示