欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java程序员从笨鸟到菜鸟(二十六)servlet实现文件上传和下载

程序员文章站 2022-05-30 21:25:57
...

目录

一、所需要的jar包

  • common-io
  • common-fileupload
  • jstl

二、文件上传

2.1 上传文件步骤:

  1. 获取文件保存目录
  2. 判断目录是否存在,不存在就新建
  3. 创建DiskFileItemFactory工厂
  4. 创建文件解析器ServletFileUpload
  5. 判断提交的数据是否是上传的表单数据
  6. 使用ServletFileUpload解析上传数据,结果返回一个List集合,每一个FileItem对应一个Form表单输入项
  7. 遍历集合,判断输入的是否是上传文件
  8. 获得上传文件名称,只保留文件名部分
  9. 获取item中的文件输入流InputStream in
  10. 创建一个文件输出流FileOutputStream out
  11. 创建一个缓冲区byte[] buffer
  12. 判断输入流中的数据是否读完 len = in.read(buffer) > 0
  13. 使用FileOutputStream输出流将数据写入指定目录
  14. 关闭输入流、输出流

2.2 文件上传页面:upload.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>测试文件上传</title>
    <script type="text/javascript" src="../../resources/js/jquery.min.js"></script>
</head>
<body>
    <form action="${pageContext.request.contextPath }/servlet/UploadServlet" enctype="multipart/form-data"  method="post">
        上传文件:<input type="file" name="file"><br/>
        <input type="submit" value="上传"/>文件上传结果:${message}
    </form>

<script type="text/javascript">

    // 触发文件选择的click事件
    $("#file").trigger("click");

</script>
</body>
</html>

2.3 处理文件上传的servlet:UploadServlet

在web.xml中配置servlet

<!-- 实现文件上传 -->
<servlet>
  <servlet-name>UploadServlet</servlet-name>
  <servlet-class>ssh.controller.UploadServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>UploadServlet</servlet-name>
  <url-pattern>/servlet/UploadServlet</url-pattern>
</servlet-mapping>

UploadServlet 实现:

public class UploadServlet extends HttpServlet {
   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       // 设置文件上传保存的目录
       String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
       File file = new File(savePath);
       if (!(file.exists()) && file.isDirectory()) {
           file.mkdir();
       }

       // 上传时生成的临时问价保存目录
       String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");

       File tempFile = new File(tempPath);
       if (!tempFile.exists()) { // 存放临时目录的文件夹不存在,新建目录
           tempFile.mkdir();
       }

       // 消息提示
       String message = "";
       try {
           // 1.创建一个DiskFileItemFactory工厂
           DiskFileItemFactory factory = new DiskFileItemFactory();
           // 设置工厂的缓冲区大小,当上传文件超过缓冲区大小,就会创建一个临时文件存放到指定的临时目录
           factory.setSizeThreshold(1024 * 100); // 设置缓冲区的大小为100KB,默认大小是10KB
           // 设置上传时生成的临时文件保存目录
           factory.setRepository(tempFile);
           // 2.创建一个文件上传解析器
           ServletFileUpload upload = new ServletFileUpload(factory);
           // 解决上传文件中文乱码
           upload.setHeaderEncoding("utf-8");
           // 设置上传单个文件的大小最大值,设置1024 * 1024字节,也就是1MB
           upload.setFileSizeMax(1024 * 1024 * 50);
           // 设置同时上传各个文件大小总和不能超过10MB
           upload.setSizeMax(1024 * 1024 * 500);
           // 3.判断提交上来的数据是否是上传表单的数据
           if (!ServletFileUpload.isMultipartContent(request)) {
               return;
           }

           // 4.使用ServletFilterUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem代表一个表单输入项
           List<FileItem> list = upload.parseRequest(request);
           for (FileItem item: list) {
               // 如果fileItem封装的是普通的输入项的数据
               if (item.isFormField()) {
                   String name = item.getFieldName();
                   // 解决普通输入项的数据的中文乱码问题
                   String value = item.getString("utf-8");
               } else { // 如果fileItem封装的是上传的文件
                   // 获取上传文件的名称
                   String fileName = item.getName();
                   if (null == fileName || "".equals(fileName.trim())) {
                       continue;
                   }
                   // 处理获取到的上传文件名的路径部分,只保留文件名部分
                   fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
                   // 得到文件的扩展名
                   String fileExtrName = fileName.substring(fileName.lastIndexOf(".") + 1);
                   // 如果需要限制上传文件的格式,可以根据扩展名做过滤
                   if (!("txt".equals(fileExtrName))) {
                       message = "只能上传文本文档";
                       //request.setAttribute("message", "只能上传文本文档");
                       //request.getRequestDispatcher("/WEB-INF/jsp/message.jsp").forward(request, response);
                   } else {
                       // 监听文件上传进度
                       upload.setProgressListener(new ProgressListener() {
                           @Override
                           public void update(long l, long l1, int i) {
                               System.out.println("文件大小为:" + l1 + ",当前已处理:" + l);
                           }
                       });
                       // 获取item中的上传文件的输入流
                       InputStream in = item.getInputStream();
                       // 创建一个文件输出流
                       FileOutputStream out = new FileOutputStream(savePath + "\\" + fileName);
                       // 创建一个缓冲区
                       byte[] buffer = new byte[1024];
                       // 判断输入流是否读完的标志
                       int len = 0;
                       // 循环将输入流读到缓冲区
                       while ((len = in.read(buffer)) > 0) {
                           // 使用输入流将缓冲区的数据写入指定的保存目录savePath
                           out.write(buffer, 0, len);
                       }
                       // 关闭输入流
                       in.close();
                       // 关闭输出流
                       out.close();
                       // 删除处理文件上传时生成的临时文件
                       item.delete();
                       message = "文件上传成功";
                   }
               }
           }
       } catch (FileUploadBase.FileSizeLimitExceededException e) {
           e.printStackTrace();
           message = "单个文件大小不能超过50MB";
        } catch (FileUploadBase.SizeLimitExceededException e) {
           e.printStackTrace();
           message = "上传的文件总数大小超限";
       } catch (Exception e) {
           e.printStackTrace();
           message = "文件上传失败";
       } finally {
           request.setAttribute("message", message);
           request.getRequestDispatcher("/WEB-INF/upload/upload.jsp").forward(request, response);
       }
   }

   /**
    * 生成文件文件名,文件名以:uuid+"_"+文件名称
    * @param fileName 文件名称
    * @return uuid + "_" + 文件名称
    * */
   private String createFileName(String fileName) {
       // 为防止文件覆盖的现象发生,为上传的文件产生一个唯一的文件名
       return UUID.randomUUID().toString() + "_" + fileName;
   }

   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       doPost(request, response);
   }
}

运行效果:
Java程序员从笨鸟到菜鸟(二十六)servlet实现文件上传和下载
Java程序员从笨鸟到菜鸟(二十六)servlet实现文件上传和下载
Java程序员从笨鸟到菜鸟(二十六)servlet实现文件上传和下载

文件上传可以对上传文件的格式(获取扩展名)、文件大小、单次上传文件的总大小做限制,代码中有注释体现

三、文件下载

3.1 可供下载的资源文件列表显示

  1. 获取上传文件的目录
  2. 存储要下载的文件名Map
  3. 遍历递归所有的文件和目录,将文件存储到map中
  4. 将Map结合发送到前台页面进行显示
显示文件列表的jsp页面:listfile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
  <title>下载文件显示页面</title>
</head>
<body>
  <table border="1">
      <!-- 遍历Map集合 -->
      <c:forEach var="file" items="${fileNameMap}">
       <tr>
         <c:url value="/servlet/DownloadServlet" var="downurl">
              <c:param name="filename" value="${file.key}"/>
          </c:url>
         <td> ${file.value}<a href="${downurl}">下载</a></td>
      </tr>
      </c:forEach>
  </table>
</body>
</html>
处理显示文件的servlet:FileListServlet
在web.xml中配置
<!-- 列出文件下载目录 -->
<servlet>
  <servlet-name>FileListServlet</servlet-name>
  <servlet-class>ssh.controller.FileListServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>FileListServlet</servlet-name>
  <url-pattern>/servlet/FileListServlet</url-pattern>
</servlet-mapping>
FileListServlet实现:
public class FileListServlet extends HttpServlet {
   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       // 获取文件上传目录
       String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");
       // 存储要下载的文件名
       Map<String, String> fileNameMap = new HashMap<String, String>();
       // 递归遍历filePath目录下所有的文件和目录,将文件名存储到map集合中
       listFile(new File(uploadFilePath), fileNameMap);
       // 将map集合发送到listfile.jsp进行页面展示
       request.setAttribute("fileNameMap", fileNameMap);
       request.getRequestDispatcher("/WEB-INF/jsp/listfile.jsp").forward(request, response);
   }

   /**
    * 递归遍历指定目录下所有文件
    * @param file 代表一个文件,也代表一个目录
    * @param map 用来存储文件名
    *
    * */
   private void listFile(File file, Map<String, String> map) {
       // 如果file代表的不是一个文件,而是一个目录
       if (!file.isFile()) {
           // 列出文件夹下所有的文件和目录
           File[] files = file.listFiles();
           // 遍历File数组
           for (File f: files) {
               // 递归
               listFile(f, map);
           }
       } else {
           // 处理文件名,上传后的文件是以uuid_文件名的形式重新命名的
           String realFileName = file.getName().substring(file.getName().indexOf("_") + 1);
           map.put(file.getName(), realFileName);
       }
   }

   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       doPost(request, response);
   }
}

文件列表显示效果:
Java程序员从笨鸟到菜鸟(二十六)servlet实现文件上传和下载

3.2 文件下载

  1. 获取需要下载的文件名
  2. 通过文件名找出文件所在的位置
  3. 得到要下载的文件,如果文件不存在信息提示
  4. 读取要下载的文件,保存到文件输入流
  5. 创建输出流
  6. 创建缓冲区
  7. 循环将输入流中的内容读到缓冲区
  8. 关闭输入流、输出流
处理文件下载的DownloadServlet
在web.xml中配置
<!-- 实现文件下载 -->
<servlet>
    <servlet-name>DownloadServlet</servlet-name>
    <servlet-class>ssh.controller.DownloadServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>DownloadServlet</servlet-name>
    <url-pattern>/servlet/DownloadServlet</url-pattern>
</servlet-mapping>
DownloadServlet实现
public class DownloadServlet extends HttpServlet {
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // 获取要下载的文件名
      String fileName = request.getParameter("filename");

      // 上传文件保存的目录
      String fileSavePath = this.getServletContext().getRealPath("/WEB-INF/upload");
      // 通过文件名找出文件所在目录
      String path = findFileSavePathByName(fileName, fileSavePath);

      // 得到要下载的文件
      File file = new File(path + "\\" + fileName);
      // 如果文件不存在
      if (!file.exists()) {
          request.setAttribute("message", "您要下载的资源已被删除");
          request.getRequestDispatcher("/WEB-INF/jsp/message.jsp").forward(request, response);
      }
      // 处理文件名
      String realName = fileName.substring(fileName.indexOf("_") + 1);
      // 设置响应头,控制浏览器下载该文件
      response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realName, "UTF-8"));
      // 读取要下载的文件,保存到文件输入流
      FileInputStream fis = new FileInputStream(path + "\\" + fileName);
      // 创建输出流
      OutputStream os = response.getOutputStream();
      // 创建缓冲区
      byte[] bytes = new byte[1024];
      int len = 0;
      // 循环将输入流中的内容读取到缓冲区
      while ((len = fis.read(bytes)) > 0) {
          os.write(bytes, 0, len);
      }
      // 关闭文件输入流
      fis.close();
      // 关闭文件输出流
      os.close();
  }

  /**
   * 通过文件名找出文件所在的路径
   * @param fileName 要下载的文件名
   * @param fileSavePath 上传文件的根目录
   * @return 返回要下载文件的存储目录
   * */
  private String findFileSavePathByName(String fileName, String fileSavePath) {
      int hashcode = fileName.hashCode();
      //int dir1 = hashcode & 0xf; // 使用hascode打散存储,但是文件目录获取之后出错
      //int dir2 = (hashcode & 0xf0) >> 4;
      String dir = fileSavePath;
      File file = new File(dir);
      if (!file.exists()) {
          // 创建目录
          file.mkdir();
      }
      return dir;
  }

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      doPost(request, response);
  }
}

运行结果:
Java程序员从笨鸟到菜鸟(二十六)servlet实现文件上传和下载

原文传送门:https://www.cnblogs.com/xdp-gacl/p/4200090.html