java+web+批量下载文件

Wesley13
• 阅读 650

JavaWeb 文件下载功能

文件下载的实质就是文件拷贝,将文件从服务器端拷贝到浏览器端,所以文件下载需要IO技术将服务器端的文件读取到,然后写到response缓冲区中,然后再下载到个人客户端。

1. 文件名 - 接受前端发来的文件名

获取到前端页面发送过来的要下载的文件的名字

String filenameValue = req.getParameter("filename");

2. ServletContext域 - 获取到ServletContext域对象

后面将调用此对象的一系列方法,用于获取文件路径、文件MimeType,并设置文件输出类型

ServletContext servletContext = req.getServletContext();  //获取到ServletContext域对象

3. 文件路径 - 获取指定文件在web项目中的路径

通过获取到ServletContext域对象的getRealPath()方法,读取download目录下文件的绝对路径

注意:download目录必须放在webContent目录下面,否则可能会找不到,导致报异常,在读取资源的时候,项目demo会直接去查找webContent下面的文件和文件夹

String realPath = servletContext.getRealPath("download/"+filenameValue);  //获取到要下载文件在web项目中的绝对路径

4. 文件MimeType - 获取文件的MimeType类型

通过获取到的 ServletContext 域对象的 getMimeType() 方法,获取到文件MimeType

MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准。

MIME 协议指示 MIME 用户代理如何显示附加的文件。

MIME 参考手册:http://www.w3school.com.cn/media/media\_mimeref.asp

告知浏览器文件的类型:response.setContentType(文件的MIME类型);

String mimeType = servletContext.getMimeType(filenameValue);  //获取到要下载文件的mimeType类型

5. 输出类型 - 设置文件的输出类型

根据之前获取到的文件MimeType,然后通过 Response 域对象的 setContentType() 方法,设置文件的输出类型

resp.setContentType(mimeType);  //设置文件的输出类型

6. 设置响应头 - 确定文件是内嵌或弹出下载框

通过 Response 域对象的 setHeader("Content-Disposition","attachment;filename="+filename) 方法设置响应头

Content-Disposition(内容处置/处理)

是 MIME 协议的扩展,Content-Disposition 可以控制用户请求所得的内容存为一个文件时提供一个默认的文件名

inline 和 attachment:文件直接在浏览器上显示或者在访问时弹出文件下载对话框。

inline 表示:内嵌显示,文本和图片都可以解析,但对于文件或者视频会自动去调用成attachment,因此可以直接使用inline

attachment:弹出下载框,因为attachment是让文件以附件的形式打开,因此会调用下载,但此下载的功能并没有提示

//设置输出(下载)的文件的默认文件名为filenameValue的值,inline表示内嵌文本和图片,文件和视频会自动调用成attachment

resp.setHeader("Content-Disposition", "inline;filename="+filenameValue);

7. 执行输出(下载) - IO流

7.1 通过 new,创建字节输入流 FileInputStream,读取文件

7.2 通过Response域,创建Servlet的输出流,输出文件

FileInputStream fileInputStream = new FileInputStream(realPath);

ServletOutputStream  outputStream = resp.getOutputStream();

int b=0;

byte[] by = new byte[1024*8];

while ((b=fileInputStream.read(by))!=-1) {

  outputStream.write(by, 0, b);

}

outputStream.flush();

fileInputStream.close();

outputStream.close();  //关流,response获得流会自动关闭,因此也可以不用手动关

功能实现代码

Java 代码 - /demo/src/com/Download.java

package com;

import java.io.FileInputStream;

import java.io.IOException;

import java.net.URLEncoder;

import javax.servlet.ServletConfig;

import javax.servlet.ServletContext;

import javax.servlet.ServletException;

import javax.servlet.ServletOutputStream;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class Download extends HttpServlet{

    @Override

    public void init(ServletConfig config) throws ServletException {

        /**重写了Servlet的init(ServletConfig config)方法后一定要记得调用父类的init方法,

        * 否则在service/doGet/doPost方法中使用getServletContext()方法获取ServletContext对象时

        * 就会出现java.lang.NullPointerException异常

        * */

        super.init(config);

    }

    @Override

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        doPost(req, resp);

    }

    @Override

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        /**1. 接受前端页面发送过来的文件名字

        * 获取到前端页面发送过来的要下载的文件的名字

        * */

        String filenameValue = req.getParameter("filename");

        //---------------------

//      filenameValue = URLEncoder.encode(filenameValue, "gbk");

        /**2. 获取到ServletContext域对象

        * 后面将调用此对象的一系列方法,用于获取文件路径、文件MimeType、文件输出类型

        * */

        ServletContext servletContext = req.getServletContext();  //获取到ServletContext域对象

        /**3. 获取指定文件在web项目中的路径

        * 通过获取到ServletContext域对象的getRealPath()方法,读取download目录下文件的绝对路径

        * download目录必须放在webContent目录下面,否则可能会找不到,导致报异常,

        * 在读取资源的时候,项目demo会直接去查找webContent下面的文件和文件夹

        * */

        String realPath = servletContext.getRealPath("download/"+filenameValue);  //获取到要下载文件在web项目中的绝对路径

        /**4. 获取到文件MimeType

        * 通过获取到的ServletContext域对象的getMimeType()方法,获取到文件MimeType

        * MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准。

        * MIME 协议指示 MIME 用户代理如何显示附加的文件。

        * MIME 参考手册:http://www.w3school.com.cn/media/media\_mimeref.asp

        * */

        String mimeType = servletContext.getMimeType(filenameValue);  //获取到要下载文件的mimeType类型

        /**5. 设置文件的输出类型

        * Response域对象的setContentType()方法,设置文件的输出类型

        * */

        resp.setContentType(mimeType);  //设置文件的输出类型

        /**6. 设置响应头,确定文件是内嵌或弹出下载框

        * 通过 Response 域对象的 setHeader("Content-Disposition","attachment;filename="+filename) 方法设置响应头,

        * Content-Disposition(内容处置/处理) :

        *      是 MIME 协议的扩展,Content-Disposition 可以控制用户请求所得的内容存为一个文件的时候提供一个默认的文件名,

        * inline 和 attachment :

        *      文件直接在浏览器上显示或者在访问时弹出文件下载对话框。 

        *      inline 表示:内嵌显示,文本和图片都可以解析,但对于文件或者视频会自动去调用成attachment,因此可以直接使用inline

        *      attachment:弹出下载框

        * URLEncoder 对象,将在响应回去的头,里面所代码filename的编码格式,转换为与客户端的一致的编码格式

        *      URLEncoder.encode(filenameValue,"utf-8"); 将Response响应到浏览器客户端为filenameValue的文件名,转变为utf-8的编码格式

        */

        resp.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(filenameValue,"utf-8"));  //设置输出(下载)的文件的默认文件名为filenameValue的值,inline表示内嵌文本和图片

        /**7. 输出文件(下载文件)

        * 7.1 通过 new,创建字节输入流 FileInputStream,读取文件

        * 7.2 通过Response域,创建Servlet的输出流,输出文件

        * */

        FileInputStream fileInputStream = new FileInputStream(realPath);

        ServletOutputStream  outputStream = resp.getOutputStream();

        int b=0;

        byte[] by = new byte[1024*8];

        while ((b=fileInputStream.read(by))!=-1) {

            outputStream.write(by, 0, b);

        }

        outputStream.flush();

        fileInputStream.close();

        outputStream.close();  //关流,response获得流会自动关闭,因此也可以不用手动关

    }

}

前端页面 jsp 代码 - /demo/WebContent/download.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%

String path=request.getContextPath();

String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>

   

       

       

       

        文件下载

   

   

       

   

   

   

   

        点击下载 文件

        点击下载 视频

   

web.xml - /demo/WebContent/WEB-INF/web.xml

  demo

 

    index.html

    index.htm

    index.jsp

    default.html

    default.htm

    default.jsp

 

 

    ServletContextName

    ServletContextValue

 

 

    Download

    com.Download

 

 

    Download

    /download

 

下载文件出现中文乱码和不显示文件名的情况

在有些情况下,如果下载中文文件,页面在下载时会出现中文乱码或不能显示文件名的情况,原因是不同的浏览器默认对下载文件的编码方式不同,比如ie是UTF-8编码方式,而火狐浏览器是Base64编码方式。

/**URLEncoder 对象,将在响应回去的头,里面所代码filename的编码格式,转换为与客户端的一致的编码格式

*  URLEncoder.encode(filenameValue,"utf-8");

*      将Response响应到浏览器客户端为filenameValue的文件名,转变为utf-8的编码格式

* */

resp.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(filenameValue,"utf-8"));

详细配置信息可以参考这篇文章:http://blog.ncmem.com/wordpress/2019/08/28/java%e6%89%b9%e9%87%8f%e4%b8%8b%e8%bd%bd/

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
LinMeng LinMeng
4年前
下载二维码至钉盘
后端生成二维码的普通文件流,前端接收后在img标签中渲染将二维码下载至钉盘通过接口获取后端返回mediaId字段,采用“dingtalkjsapi”插件中的方法下载注意:dingTalkFun中,除了corId和mediaId必传外,文件名name也是必须要传的!!!<template<divclass"onlineSign"
Easter79 Easter79
3年前
vue+axios下载pdf文件流
项目中用到流文件下载的需求,之前使用的方法一直都没问题,但是这次就是下载不下来,查了多种方法终于解决了,方式如下://下载文件downLoadFile(e){letide.target.dataset.id;letnamee.target.dataset.name;
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
3年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Easter79 Easter79
3年前
SpringMVC 文件下载时 浏览器不能正确显示另存的文件名
问题:通过打印输出流的方式把文件下载到本地,但是在firebox中下载的文件不显示文件的文件名,造成文件不能直接打开,其他浏览器可以直接打开.原因:主要是文件名称中有汉字而没有转码造成firebox浏览器不能正确显示另存的文件名解决方案://提供如下工具类将 文件名编码 就可以啦public s
Wesley13 Wesley13
3年前
Java多线程导致的的一个事物性问题
业务场景我们现在有一个类似于文件上传的功能,各个子站点接受业务,业务上传文件,各个子站点的文件需要提交到总站点保存,文件是按批次提交到总站点的,也就是说,一个批次下面约有几百个文件。      考虑到白天提交这么多文件会影响到子站点其他系统带宽,我们将分站点的文件提交到总站点这个操作过程独立出来,放到晚上来做,具体时间是晚上7:00到早上7:00。
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这