Java Web实现文件下载的几种方式

文件下载可以说是网站的基础功能,要实现最下载功能,有一种最基本的方法,那就是将超链接的href属性指向对应的资源文件。

如下面连接指向了百度首页的图片:

​ ​I’m the index of Baidu​​

但这种方式的缺陷也是很明显的,目录信息被获取,不利于信息安全。其实信息安全还是其次,主要还是因为它不方便。如果直接指向资源文件,那么浏览器会自动打开图片等一些文件,而不会弹出窗口提示用户保存。

因此这种方式并不能很好地解决下载的问题。因此就有了下面的几种下载方式。

而在Java中,要实现下载功能一般有三种实现方式:

1、使用Servlet实现文件下载

2、在Struts中用Servlet实现下载

3、使用Struts框架提供的文件下载功能

其实这三种实现方式的原理都一样,都是利用InputStream从文件中读取数据,然后利用OutputStream将数据接入到返回客户端的response中。

其核心代码如下:

1 try {
 2         InputStream inStream = new FileInputStream(file);
 3         ServletOutputStream servletOS = response.getOutputStream();
 4         byte[] buf = new byte[4096];
 5         int readLength;
 6         while((readLength = inStream.read(buf))!= -1)
 7         {
 8             servletOS.write(buf, 0, readLength);
 9         }
10         inStream.close();
11         servletOS.flush();
12         servletOS.close();
13     }
14     catch(Exception e)
15     {
16         e.printStackTrace();
17     }
18     return response;

其中第一种在Servlet中实现文件下载是最原始的下载方式。而第二种在Struts中用Servlet实现文件下载也是最原始的方式,只不过我们是在Struts的Action中进行操作,不用去创建Servlet。

而第三种则是Struts对文件下载功能进行了封装,我们只要按照其规定的配置就可以直接使用。

这几种方式各有各的优缺点,选择适合自己的方式即可。下面对上面提到的三种方式进行详细解析:

一、使用Servlet实现文件下载

这种方式性能最好,条理最清晰,但是可能代码量多了点。

准备:只需Java的JDK即可运行。

1、在web.xml中进行Servlet配置

1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app version="2.5" 
 3     xmlns="http://java.sun.com/xml/ns/javaee" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 5     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 6     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 7 
 8     <!-- 文件下载  -->
 9     <servlet>
10         <servlet-name>fileDownLoadServlet</servlet-name>
11         <servlet-class>com.chanshuyi.download.FileDownLoadServlet</servlet-class>
12     </servlet>
13     <servlet-mapping>
14         <servlet-name>fileDownLoadServlet</servlet-name>
15         <url-pattern>/fileDownLoadServlet</url-pattern>
16     </servlet-mapping>
17 </web-app>

2、创建Servlet类

1 package com.chanshuyi.download;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.IOException;
  6 import java.io.InputStream;
  7 import java.io.UnsupportedEncodingException;
  8 import java.net.URLEncoder;
  9 
 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 /**
 17  * 文件下载Servlet
 18  * @param filePath 下载文件相对于项目根目录的相对地址</P>如:uploaded\hello.txt
 19  * @author chenyr
 20  *
 21  */
 22 @SuppressWarnings("serial")
 23 public class FileDownLoadServlet extends HttpServlet {
 24     
 25     /** 项目的根目录</P>如:D:\Workspaces\DownUpProject\WebRoot\ **/
 26     private String rootPath;
 27     
 28     /** 下载文件的相对于项目根目录的相对路径 **/
 29     private String filePath;
 30     
 31     /** 下载文件在磁盘的绝对路径 **/
 32     private String fullPath;
 33     
 34     /** 下载文件名 **/
 35     private String fileName;
 36     
 37     /** 编码过后的下载文件名 **/
 38     private String encodeFileName;
 39 
 40     /**
 41      * 自定义init,用于初始化下载所属属性
 42      * @param request
 43      * @return
 44      * @throws UnsupportedEncodingException 
 45      */
 46     public boolean myInit(HttpServletRequest request)
 47     {        
 48         boolean flag = false;
 49         try
 50         {
 51             setRootPath(this.getServletContext().getRealPath("/"));            
 52             setFilePath(new String(request.getParameter("filePath").getBytes("iso-8859-1"), "utf-8"));    
 53             setFullPath(getRootPath() + getFilePath());
 54             
 55             setFileName(getFilePath().substring(getFilePath().lastIndexOf("\\") + 1));
 56             setEncodeFileName(URLEncoder.encode(getFileName(), "utf-8"));    //支持中文文件名
 57             
 58             flag = true;
 59         }
 60         catch(Exception e)
 61         {
 62             e.printStackTrace();
 63         }
 64         return flag;
 65     }
 66 
 67     /**
 68      * Servlet类的服务方法
 69      */
 70     @Override
 71     protected void service(HttpServletRequest request,
 72             HttpServletResponse response) throws ServletException, IOException {
 73         download(request, response);
 74     }
 75     
 76     /**
 77      * 文件下载
 78      * @param path
 79      * @param request
 80      * @param response
 81      * @return
 82      * @throws UnsupportedEncodingException 
 83      */
 84     public HttpServletResponse download(HttpServletRequest request, HttpServletResponse response){
 85             /* 初始化相关属性信息 */
 86             myInit(request);
 87                         
 88             /* 检查文件是否存在 */
 89             File file = new File(getFullPath());
 90             if(!file.exists())
 91             {
 92                 System.out.println("文件不存在:" + file.getAbsolutePath());
 93                 return null;
 94             }
 95             
 96             /* 设置response头信息 */
 97             response.reset();    
 98             response.setContentType("application/octet-stream");    //代表任意二进制数据
 99             response.addHeader("Content-Disposition", "attachment;filename=\"" + getEncodeFileName() + "\"");
100             response.setContentLength((int)file.length());
101             
102             /* 读取文件数据流 */
103             if(file.exists())
104             {
105                 /* 读取文件数据 */
106                 if((int)file.length() != 0)
107                 {
108                     try
109                     {
110                         InputStream inStream = new FileInputStream(file);
111                         
112                         ServletOutputStream servletOS = response.getOutputStream();
113                         byte[] buf = new byte[4096];
114                         int readLength;
115                         while((readLength = inStream.read(buf))!= -1)
116                         {
117                             servletOS.write(buf, 0, readLength);
118                         }
119                         
120                         inStream.close();
121                         servletOS.flush();
122                         servletOS.close();
123                     }
124                     catch(Exception e)
125                     {
126                         e.printStackTrace();
127                     }
128                 }
129             }
130             return response;
131     }
132 
133     /*
134      * GET/SET
135      */
136     public String getFilePath() {
137         return filePath;
138     }
139 
140     public void setFilePath(String filePath) {
141         this.filePath = filePath;
142     }
143 
144     public String getFullPath() {
145         return fullPath;
146     }
147 
148     public void setFullPath(String fullPath) {
149         this.fullPath = fullPath;
150     }
151 
152     public String getFileName() {
153         return fileName;
154     }
155 
156     public void setFileName(String fileName) {
157         this.fileName = fileName;
158     }
159 
160     public String getEncodeFileName() {
161         return encodeFileName;
162     }
163 
164     public void setEncodeFileName(String encodeFileName) {
165         this.encodeFileName = encodeFileName;
166     }
167 
168     public String getRootPath() {
169         return rootPath;
170     }
171 
172     public void setRootPath(String rootPath) {
173         this.rootPath = rootPath;
174     }
175 }

这个Servlet类对下载功能进行很好的封装,只需要传入名字为:filePath的参数就可以进行下载(filePath是下载文件相对于根目录[WEBROOT目录]的相对路径)。

98行设置response的contentType为application/octet-stream,可以实现任意类型文件的下载。

56行设置URLEncoder.encode对文件名进行编码转换,实现对中文文件名的下载支持。

3、创建访问页面测试

1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 2 <%
 3 String path = request.getContextPath();
 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 5 %>
 6 
 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 8 <html>
 9   <head>
10     <base href="<%=basePath%>">
11     
12     <title>My JSP 'index.jsp' starting page</title>
13     <meta http-equiv="pragma" content="no-cache">
14     <meta http-equiv="cache-control" content="no-cache">
15     <meta http-equiv="expires" content="0">    
16     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
17     <meta http-equiv="description" content="This is my page">
18     <!--
19     <link rel="stylesheet" type="text/css" href="styles.css">
20     -->
21   </head>
22   
23   <body>
24           <a href="fileDownLoadServlet?filePath=uploaded\通讯录.xls">哈哈,测试文件下载</a>
25   </body>
26 </html>

二、在Struts中用Servlet实现下载

这种方式其实就是将数据流写入response中,其实现方式与第一种完全相同。不同的是在Servlet类中,我们可以直接得到request、response、ServletContext,但是在Struts的Action中我们必须通过其他方式得到这几个变量。

下面的代码实在第一种实现方式的代码的基础上进行少量修改而成的,它实现了在Struts Action中下载的功能:

package com.chanshuyi.download;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class FileDownloadViaServlet extends ActionSupport {
  
  HttpServletRequest request = ServletActionContext.getRequest();
  HttpServletResponse response = ServletActionContext.getResponse();
  ServletContext servletContext = ServletActionContext.getServletContext();
  
  /** 项目的根目录</P>如:D:\Workspaces\DownUpProject\WebRoot\ **/
  private String rootPath;
  
  /** 下载文件的相对于项目根目录的相对路径 **/
  private String filePath;
  
  /** 下载文件在磁盘的绝对路径 **/
  private String fullPath;
  
  /** 下载文件名 **/
  private String fileName;
  
  /** 编码过后的下载文件名 **/
  private String encodeFileName;

  /**
   * 自定义init,用于初始化下载所属属性
   * @param request
   * @return
   * @throws UnsupportedEncodingException 
   */
  public boolean myInit()
  {   
    boolean flag = false;
    
    try
    {
      setRootPath(servletContext.getRealPath("/"));     
      setFilePath(new String(request.getParameter("filePath").getBytes("iso-8859-1"), "utf-8"));  
      setFullPath(getRootPath() + getFilePath());
      
      setFileName(getFilePath().substring(getFilePath().lastIndexOf("\\") + 1));
      setEncodeFileName(URLEncoder.encode(getFileName(), "utf-8")); //支持中文文件名
      
      flag = true;
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
    return flag;
  }

  /**
   * Action执行方法
   */
  @Override
  public String execute() {
    download();
    return null;
  }
  
  /**
   * 文件下载
   * @param path
   * @param request
   * @param response
   * @return
   * @throws UnsupportedEncodingException 
   */
  public HttpServletResponse download(){
      /* 初始化相关属性信息 */
      myInit();
            
      /* 检查文件是否存在 */
      File file = new File(getFullPath());
      if(!file.exists())
      {
        System.out.println("文件不存在:" + file.getAbsolutePath());
        return null;
      }
      
      /* 设置response头信息 */
      response.reset(); 
      response.setContentType("application/octet-stream");  //代表任意二进制数据
      response.addHeader("Content-Disposition", "attachment;filename=\"" + getEncodeFileName() + "\"");
      response.setContentLength((int)file.length());
      
      /* 读取文件数据流 */
      if(file.exists())
      {
        /* 读取文件数据 */
        if((int)file.length() != 0)
        {
          try
          {
            InputStream inStream = new FileInputStream(file);
            
            ServletOutputStream servletOS = response.getOutputStream();
            byte[] buf = new byte[4096];
            int readLength;
            while((readLength = inStream.read(buf))!= -1)
            {
              servletOS.write(buf, 0, readLength);
            }
            
            inStream.close();
            servletOS.flush();
            servletOS.close();
          }
          catch(Exception e)
          {
            e.printStackTrace();
          }
        }
      }
      return response;
  }

  /*
   * GET/SET
   */
  public String getFilePath() {
    return filePath;
  }

  public void setFilePath(String filePath) {
    this.filePath = filePath;
  }

  public String getFullPath() {
    return fullPath;
  }

  public void setFullPath(String fullPath) {
    this.fullPath = fullPath;
  }

  public String getFileName() {
    return fileName;
  }

  public void setFileName(String fileName) {
    this.fileName = fileName;
  }

  public String getEncodeFileName() {
    return encodeFileName;
  }

  public void setEncodeFileName(String encodeFileName) {
    this.encodeFileName = encodeFileName;
  }

  public String getRootPath() {
    return rootPath;
  }

  public void setRootPath(String rootPath) {
    this.rootPath = rootPath;
  }
  
}

三、使用Struts框架提供的文件下载功能

通过Struts封装的方式实现文件下载,我们需要在Struts配置文件中进行Response HTTP头等信息的设置,以及建立对应的Action。

准备:导入Struts所需的Jar包,并搭建好Struts环境。不清楚的,可以点这里:​​Struts框架配置详解​​

1、在Struts中添加Action

1 <!-- 文件下载 -->
 2         <action name="fileDownload" class="com.chanshuyi.download.FileDownLoadAction" method="download">   
 3               <!-- 初始文件名 -->  
 4             <param name="fileName">佛山“狠刹”四风网络监督平台短信责任人填报表V1.0.xls</param>
 5               <result name="success" type="stream">   
 6                 <param name="contentType">application/vnd.ms-excel</param>   
 7                 <param name="inputName">mbInputStream</param>   
 8                 <param name="contentDisposition">attachment;filename=${downloadFileName}</param>   
 9                 <param name="bufferSize">4096</param>   
10             </result> 
11         </action>

其中mbInputStream中的mbInputStream对应Action中类型为InputStream的属性。

2、创建Action类

1 package com.chanshuyi.download;
  2 
  3 import java.io.FileNotFoundException;
  4 import java.io.InputStream;
  5 import java.io.UnsupportedEncodingException;
  6 import java.net.URLEncoder;
  7 
  8 import javax.servlet.http.HttpServletRequest;
  9 
 10 import org.apache.struts2.ServletActionContext;
 11 
 12 import com.opensymphony.xwork2.ActionSupport;
 13 
 14 public class FileDownLoadAction extends ActionSupport {
 15     
 16     /** 项目的根目录</P>如:D:\Workspaces\DownUpProject\WebRoot\ **/
 17     private String rootPath;
 18     
 19     /** 下载文件的相对于项目根目录的相对路径 **/
 20     private String filePath;
 21     
 22     /** 下载文件在磁盘的绝对路径 **/
 23     private String fullPath;
 24     
 25     /** 下载文件名 **/
 26     private String fileName;
 27     
 28     /** 编码过后的下载文件名 **/
 29     private String encodeFileName;
 30     
 31     
 32     /** 对应于配置文件的输入流 **/
 33     private InputStream inputStream;
 34     
 35     public String getRootPath() {
 36         return rootPath;
 37     }
 38 
 39     public void setRootPath(String rootPath) {
 40         this.rootPath = rootPath;
 41     }
 42 
 43     public String getFilePath() {
 44         return filePath;
 45     }
 46 
 47     public void setFilePath(String filePath) {
 48         this.filePath = filePath;
 49     }
 50 
 51     public String getFullPath() {
 52         return fullPath;
 53     }
 54 
 55     public void setFullPath(String fullPath) {
 56         this.fullPath = fullPath;
 57     }
 58 
 59     public String getFileName() {
 60         return fileName;
 61     }
 62 
 63     public void setFileName(String fileName) {
 64         this.fileName = fileName;
 65     }
 66     
 67     public void setEncodeFileName(String encodeFileName) {
 68         this.encodeFileName = encodeFileName;
 69     }
 70     
 71     /**
 72      * 初始化参数
 73      * @throws UnsupportedEncodingException 
 74      */
 75     public void myInit() throws UnsupportedEncodingException
 76     {
 77         HttpServletRequest request = ServletActionContext.getRequest();
 78         
 79         setRootPath(ServletActionContext.getServletContext().getRealPath("/"));            
 80         setFilePath(new String(request.getParameter("filePath").getBytes("iso-8859-1"), "utf-8"));    
 81         setFullPath(getRootPath() + getFilePath());
 82         
 83         setFileName(getFilePath().substring(getFilePath().lastIndexOf("\\") + 1));
 84         setEncodeFileName(URLEncoder.encode(getFileName(), "utf-8"));    //支持中文文件名
 85     }
 86 
 87     /**
 88      * 对应的Action方法
 89      * @return
 90      * @throws UnsupportedEncodingException 
 91      */
 92     public String download() throws UnsupportedEncodingException
 93     {
 94         myInit();
 95         return SUCCESS;
 96     }
 97 
 98     /**
 99      * 对文件名进行编码转换,以支持中文文件名
100      * @return
101      */
102     public String getEncodeFileName() {
103         return encodeFileName;   
104     }
105     
106     /**
107      * 获取下载文件的输入流
108      * @return
109      * @throws FileNotFoundException 
110      */
111     public InputStream getInputStream() throws FileNotFoundException {
112         return new java.io.FileInputStream(getFullPath());
113     }
114 }

参考文章:http://blog.ncmem.com/wordpress/2023/11/24/java-web%e5%ae%9e%e7%8e%b0%e6%96%87%e4%bb%b6%e4%b8%8b%e8%bd%bd%e7%9a%84%e5%87%a0%e7%a7%8d%e6%96%b9%e5%bc%8f/
欢迎入群一起讨论

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
⼤数据中数据采集的⼏种⽅式 ⼀、采集⼤数据的⽅法 1.1通过系统⽇志采集⼤数据 ⽤于系统⽇志采集的⼯具,⽬前使⽤最⼴泛的有:Hadoop 的Chukwa、ApacheFlumeAFacebook的Scribe和LinkedIn的Kafka等。这 ⾥主要学习Flume。 Flume是⼀个⾼可靠的分布式采集、聚合和传输系统,Flume⽀持在⽇志系统中定制各类数据发送⽅,⽤于收集数据,同时对数据进⾏简单 处理,并写到诸如⽂本、HDFS这些接受⽅中。 Flume的核⼼其实就是把数据从数据源收集过来,再将收集到的数据送到指定的⽬的地…… 1.2通过⽹络采集⼤数据 ⽹络采集是指通过⽹络爬⾍或⽹站公开API等⽅式,从⽹站上获取⼤数据信息,该⽅法可以将⾮结构化数据从⽹页中抽取出来,将其存储为 统⼀的本地数据⽂件,并以结构化的⽅式存储。它⽀持图⽚、⾳频、视频等⽂件或附件的采集。 ⼀般来说,⽹络爬⾍⼯具基本可以分类3类:分布式⽹络爬⾍⼯具(Nutch)、Java⽹络爬⾍⼯具(Crawler4j、WebMagic、 WebCollector)、⾮Java⽹络爬⾍⼯具( Scrapy)。 1.2.1⽹络爬⾍原理 所谓的⽹络爬⾍,其实是⼀种按照⼀定规则,⾃动地抓取web信息的程序或脚本。 ⽹络爬⾍可以⾃动采集所有其能够访问到的页⾯内容,为搜索引擎和⼤数据分析提供数据来源,⼀般有数据采集、数据处理和数据存储三部 分功能。 ⽹络爬⾍是如何爬数据的? 这是因为⽹页中除了供⽤户浏览的⽂字信息外,还包含⼀些超链接信息,通过获取这些超链接URL,再辅以⼀ 定的算法,爬⾍就能得到数据了。 1.2.2爬⾍⼯作流程 基本情况下,爬⾍会⾸先获取⼀部分种⼦URL,将这些URL放⼊待抓取URL队列,从队列中取出待抓取URL,解析DNS得到主机IP,并将 URL对应⽹页下载储存。最后将这些URL放⼊已抓取队列中,如此循环。 1.2.3爬⾍抓取策略 互联⽹上的⽹页数量以亿级为单位,该以什么样的策略爬这些⽹页的数据成为了⼀个问题,⼤致分为⼏个类型。 通⽤⽹络爬⾍,⼜称为全⽹爬⾍,主要为门户站点搜索引擎和⼤型web服务提供商采集数据,⼜分为深度优先策略和⼴度优先策略。 聚焦⽹络爬⾍,⼜称为主题⽹络爬⾍,是指选择性地爬⾏那些与预先定义好的主题相关的页⾯的⽹络爬⾍。也就是有⼀个明显的主题, ⽐如⽂本、⽐如图⽚……聚焦⽹络爬⾍⼜分为⼏种:1.基于内容、2.基于链接结构、3.基于增强学习(?)、4.基于语境(?) 增量式⽹络爬⾍,是指获取的⽬标⽹页尽量为新⽹页。 深层⽹络爬⾍,如果将那些传统搜索引擎可以索引的页⾯归属于表层⽹页,那么深层⽹络爬⾍获取的页⾯就是之外的"深层⽹页"。 1.3具体的爬⾍⼯具 1.3.1Scrapy Scrapy 是⼀个为了爬取⽹站数据、提取结构性数据⽽编写的应⽤框架,可以应⽤在包括数据挖掘、信息处理或存储历史数据等⼀系列的程 序中。 虽然Scrpay⾮常强⼤,不过它是适⽤于Python的,⽽本⼈正好⼜没有接触过Python,所以这⼀部分暂且只做了解…… 1.3.2Crawler4j、WebMagic、WebCollector 这三者都是JAVA的单机爬⾍开源框架,区别可能是在于算法和调度之类的地⽅?这点搜索了⼀下,都没有能查到,就姑且这样认为吧。 这⾥我就⽤WebMagic做⼀个Demo试⼀试吧! 1.4跑⼀下WebMagic 百度后我找到了WebMagic的 照着⾥⾯的例⼦测试⼀下: ⾸先新建⼀个maven项⽬,是不是web项⽬都可以,只要是maven就⾏了。嗯,当然不要maven也可以⼿动导⼊jar包,不过为了⽅便 还是使⽤maven吧。 官⽹有⼀个官⽅的简单例⼦ public class GithubRepoPageProcessor implements PageProcessor { // 部分⼀:抓取⽹站的相关配置,包括编码、抓取间隔、重试次数等 private Site site = Site.me().setRetryTimes(3).setSleepTime(1000); @Override // process是定制爬⾍逻辑的核⼼接⼝,在这⾥编写抽取逻辑 public void process(Page page) { // 部分⼆:定义如何抽取页⾯信息,并保存下来 page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString()); page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toStri

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值