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

目录

  • 一、所需的jar包
  • 二、文件上传
  • 三、文件下载

    文件上传都是以流的方式提交服务器端的,如果直接使用servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦的,一般采用apache的common-fileupload组件

一、所需要的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);
   }
}

运行效果:
这里写图片描述
这里写图片描述
这里写图片描述

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

三、文件下载

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);
   }
}

文件列表显示效果:
这里写图片描述

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);
  }
}

运行结果:
这里写图片描述

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

猜你喜欢

转载自blog.csdn.net/u013090299/article/details/80584945
今日推荐