zoukankan      html  css  js  c++  java
  • 通过Servlet实现文件的下载

      当我们实现一个文件下载功能时,大多数人是通过Strust等框架实现的。Strust框架把底层的文件下载细节隐藏了起来,使我们不得其要领。下面我通过一个程序示例来再现通过Servlet下载文件的细节和原理。

    程序源码

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
    
        <!--可以配置一些Listener 或 Filter 来观察一些对象的生命周期 -->
        
        <servlet>
            <servlet-name>download_servlet</servlet-name>
            <servlet-class>edu.shao.webapp.sample.DownloadServlet</servlet-class>
            <init-param>
                <param-name>fileRoot</param-name>
                <param-value>d:/</param-value>
            </init-param>
            <init-param>
                <param-name>contentType</param-name>
                <param-value>application/octet-stream</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>download_servlet</servlet-name>
            <url-pattern>/download</url-pattern>
        </servlet-mapping>
    </web-app>

    DownloadServlet.java

     1 package edu.shao.webapp.sample;
     2 
     3 import java.io.BufferedInputStream;
     4 import java.io.File;
     5 import java.io.FileInputStream;
     6 import java.io.IOException;
     7 import java.net.URLEncoder;
     8 
     9 import javax.servlet.ServletConfig;
    10 import javax.servlet.ServletException;
    11 import javax.servlet.ServletOutputStream;
    12 import javax.servlet.http.HttpServlet;
    13 import javax.servlet.http.HttpServletRequest;
    14 import javax.servlet.http.HttpServletResponse;
    15 
    16 import org.apache.logging.log4j.LogManager;
    17 import org.apache.logging.log4j.Logger;
    18 
    19 public class DownloadServlet extends HttpServlet{
    20     private static final long serialVersionUID = 1L;
    21     public static Logger logger=LogManager.getLogger(DownloadServlet.class);
    22     
    23     private String contentType;
    24     private String enc="UTF-8";
    25     private String fileRoot;
    26     
    27     @Override
    28     public void init(ServletConfig config) throws ServletException {
    29         contentType = config.getInitParameter("contentType");
    30         fileRoot = config.getInitParameter("fileRoot");
    31     }
    32 
    33     @Override
    34     public void doGet(HttpServletRequest req, HttpServletResponse resp)
    35             throws ServletException, IOException {
    36         logger.debug("Do Get Method.");
    37         String fileName=req.getParameter("fileName");
    38         String filePath=fileRoot+File.separator+fileName;
    39         
    40         File downloadFile=new File(filePath);
    41         if (downloadFile.exists()) {
    42             logger.info("File exist");
    43             
    44             resp.setContentType(contentType);
    45             Long length=downloadFile.length();
    46             resp.setContentLength(length.intValue());
    47             fileName = URLEncoder.encode(downloadFile.getName(), enc);
    48             resp.addHeader("Content-Disposition", "attachment; filename=" + fileName);
    49             
    50             ServletOutputStream servletOutputStream=resp.getOutputStream();
    51             FileInputStream fileInputStream=new FileInputStream(downloadFile);
    52             BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);
    53             int size=0;
    54             byte[] b=new byte[4096];
    55             while ((size=bufferedInputStream.read(b))!=-1) {
    56                 logger.info("write to output stream..");
    57                 servletOutputStream.write(b, 0, size);
    58             }
    59             servletOutputStream.flush();
    60             servletOutputStream.close();
    61             bufferedInputStream.close();
    62         }else {
    63             logger.info("File is not exist");
    64         }
    65     }
    66 
    67 }

    解释:

    1、contentType用于定义用户的浏览器如何显示将要加载的数据,或者如何处理将要加载的数据。如网页的contentType是text/html,jpeg图片的contentType是image/jpeg。如果不知道文件类型,可以设置为二进制流文件 application/octet-stream

    2、contentType和fileRoot(待下载文件的目录)通过web.xml配置。

    3、resp.setContentType()、resp.setContentLength()、resp.addHeader("Content-Disposition", "attachment; filename=" + fileName); 三个调用设置一些必要的响应报头(reponse header)。

    运行结果:

    1、浏览器地址栏输入:http://localhost:8080/test/download?fileName=test.mkv  回车(文件“d:/test.mkv”的大小为700M)

    2、浏览器弹出下载提示窗口,但未点击保存。控制台先打印几条日志,然后停滞,说明已经向输出流写入了4kB左右(程序中byte数组的大小为4096B)的数据了。

    3、选择保存位置后,点击保存。此时控制台开始疯狂地输出log。。。

    4、最后下载完成,此次Request结束。

    小结:

      文件下载的原理非常简单,就是把数据从一个输入流中读出数据,再写入一个输出流。这里的输入流是FileInputStream(为了提高速度,对其包装了一个装饰类BufferedInputStream,以提供缓冲功能),输出流是ServletOutputStream。

      源码中的定义,public abstract class ServletOutputStream extends OutputStream。说明ServletOutputStream继承了OutputStream,它和FileOutputStream等输出流是一样的。

  • 相关阅读:
    java设计模式之适配器模式
    在Eclipse中建立Maven Web项目
    java设计模式之原型模式
    java设计模式之建造者模式
    java设计模式之工厂模式
    java设计模式之单例模式
    C# 前端多次上传文件
    C# async 和 await
    .NET 4.0 任务(Task)
    C# 5.0
  • 原文地址:https://www.cnblogs.com/windlaughing/p/3036148.html
Copyright © 2011-2022 走看看