Java Web基础入门第六十八讲 文件下载

本文介绍了Java Web中如何实现文件下载。通过设置Content-Type和Content-Disposition响应头,确保浏览器以下载方式处理文件。首先,ListFileServlet列出所有可下载文件,然后DownloadServlet负责实际的文件传输。文中还提醒避免在JSTL标签中添加注释,以免引发异常。通过示例展示了文件下载功能的正常运行效果。
摘要由CSDN通过智能技术生成

我们做完文件上传之后,就要来做文件下载了。Web应用中实现文件下载的方式是超链接直接指向下载资源。程序实现下载需设置两个响应头:

  • 设置Content-Type的值为application/x-msdownload。Web服务器需要告诉浏览器其所输出的内容的类型不是普通的文本文件或HTML文件,而是一个要保存到本地的下载文件;
  • Web服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置Content-Disposition报头。该报头指定了接收程序处理数据内容的方式,在HTTP应用中只有attachment是标准方式,attachment表示要求用户干预。在attachment后面还可以指定filename参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。在设置Content-Dispostion之前一定要指定Content-Type。

列出提供下载的文件资源

我们要将Web应用系统中的文件资源提供给用户进行下载,首先我们要有一个页面列出上传文件目录下的所有文件,当用户点击文件下载超链接时就进行下载操作,编写一个ListFileServlet,用于列出Web应用系统中所有下载文件,该Servlet的代码如下:

package cn.liayun.web.servlet;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//列出网站所有文件
@WebServlet("/ListFileServlet")
public class ListFileServlet extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String path = this.getServletContext().getRealPath("/WEB-INF/upload");
		Map map = new HashMap();
		listfile(new File(path), map);
		
		request.setAttribute("map", map);
		request.getRequestDispatcher("/listfile.jsp").forward(request, response);
	}
	
	//如何保存递归出来的资源
	public void listfile(File file, Map map) {
		if (!file.isFile()) {//传进来的是目录
			File[] children = file.listFiles();
			for (File f : children) {
				listfile(f, map);
			}
		} else {//传进来的是文件
			/*
			 * 保存在服务器中的上传文件的文件名,又可能是这样的:7e8edb28-2084-4125-9dbf-966303805ef5_李阿昀_liayun.txt,
			 * 这时,我们要获取到文件的原始文件名:李阿昀_liayun.txt
			 */
			String filename = file.getName().substring(file.getName().indexOf("_") + 1);
			map.put(file.getName(), filename);//<a href="/Servlet?filename=文件在服务器里面的名称">文件的原始文件名</a>
		}
	}

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

}

这里简单说一下ListFileServlet中的listFile方法,listFile方法是用来列出上传目录下的所有文件的,listFile方法内部用到了递归,在实际开发中,我们肯定会在数据库创建一张表,里面会存储上传的文件名以及文件的具体存放目录,我们通过查询表就可以知道文件的具体存放目录,是不需要用到递归操作的。这个例子是因为没有使用数据库存储上传的文件名和文件的具体存放位置,而上传文件的存放位置又使用了散列算法打散存放,所以需要用到递归,在递归时,将获取到的文件名存放到从外面传递到listFile方法里面的Map集合当中,这样就可以保证所有的文件都存放在同一个Map集合当中。
接下来我们就要编写展示下载文件列表的listfile.jsp页面了。
在这里插入图片描述
温馨提示:千万不能在JSTL标签里面加注释!!!例如:
在这里插入图片描述
如若真这样写了,可能会抛这样乱七八糟的异常,令人心烦。

java.lang.NullPointerException
    at org.apache.taglibs.standard.tag.common.core.UrlSupport.resolveUrl(UrlSupport.java:155)
    at org.apache.taglibs.standard.tag.common.core.UrlSupport.doEndTag(UrlSupport.java:112)
    at org.apache.jsp.listfile_jsp._jspx_meth_c_005furl_005f1(listfile_jsp.java:267)
    at org.apache.jsp.listfile_jsp._jspx_meth_c_005furl_005f0(listfile_jsp.java:233)
    at org.apache.jsp.listfile_jsp._jspx_meth_c_005fforEach_005f0(listfile_jsp.java:183)
    at org.apache.jsp.listfile_jsp._jspService(listfile_jsp.java:140)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:720)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:466)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:391)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318)
    at cn.itcast.web.servlet.ListFileServlet.doGet(ListFileServlet.java:29)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

我们可以先上传一些文件,然后再访问ListFileServlet,就可以在listfile.jsp页面中显示提供给用户下载的文件资源了,如下图所示:
在这里插入图片描述

实现文件下载

因为要下载的文件可以是各种类型的文件,所以要将文件传送给客户端,其相应内容应该被当做二进制来处理,所以应该调用response对象的getOutputStream()方法返回ServeltOutputStream对象来向客户端写入文件内容。下面,我们编写一个用于处理文件下载的DownloadServlet,其代码如下:

package cn.liayun.web.servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//得到要下载的文件名,filename即为文件在服务器里面的名称,例如7e8edb28-2084-4125-9dbf-966303805ef5_李阿昀_liayun.txt
		String filename = request.getParameter("filename");
//		filename = new String(filename.getBytes("ISO8859-1"), "UTF-8");
		
		//找出这个文件                                                                                                      "/WEB-INF/upload"中的分隔符与平台无关,因为这是一个url地址
		String path = this.getServletContext().getRealPath("/WEB-INF/upload") + File.separator + getPath(filename);
		
		File file = new File(path + File.separator + filename);
		if (!file.exists()) {
			request.setAttribute("meassage", "对不起,您要下载的资源已被删除!");
			request.getRequestDispatcher("/message.jsp").forward(request, response);
			return;
		}
		
		//得到文件的原始文件名
		String oldname = file.getName().substring(file.getName().indexOf("_") + 1);
		
		//通知浏览器以下载的方式打开下面发送的数据
		response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(oldname, "UTF-8"));
		
		FileInputStream in = new FileInputStream(file);
		int len = 0;
		byte[] buffer = new byte[1024];
		OutputStream out = response.getOutputStream();
		while ((len = in.read(buffer)) > 0) {
			out.write(buffer, 0, len);
		}
		in.close();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
	
	public String getPath(String filename) {
		int hashCode = filename.hashCode();//得到字符串在内存中的地址,如121221
		int dir1 = hashCode & 15;//int dir1 = hashCode & 0xf;
		int dir2 = (hashCode >> 4) & 0xf; 
		
		return dir1 + File.separator + dir2;//得到诸如:3/5
	}

}

编写完用于处理文件下载的Servlet后,现在我们就来点击【下载】超链接进行下载文件,运行效果如下图所示:
在这里插入图片描述
从运行结果可以看到,我们的文件下载功能已经可以正常下载文件了。关于Java Web中的文件上传和下载功能的内容就这么多。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李阿昀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值