IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java文件下载/下载文件的案例 -> 正文阅读

[Java知识库]Java文件下载/下载文件的案例

需求

1.页面显示超链接
2.点击超链接后弹出下载对话框
3.完成图片文件下载

分析

超链接指向的资源如果能够被浏览器解析,则直接在浏览器中展示,如果不能解析,则弹出下载提示框。如果希望无论返回什么资源都不要解析,而是让用户下载,那么就必须使用 content-disposition 响应头告诉客户端,返回的资源(响应体的数据)以附件的形式打开。

实现步骤

1.开发前端页面,使用超链接标签,href 属性指向一个 Servlet,并且传递下载资源的名称
2.实现后端逻辑,定义一个 Servlet,获取下载资源的名称,再根据资源名称将对应的资源加载入内存中,再从内存输出到 Response对象中,再返回给客户端
2.1.获取参数
2.2.使用字节输入流读取资源文件,加载进内存中
2.3.设置响应头(content-type 和 content-disposition)
2.4.使用字节输出流写入到 Response 对象中。具体是从内存写入到 Response 的字节输出流中,再从字节输出流写入到 Response 对象中
2.5.服务器从 Response 对象中获取数据构建成响应报文发送给客户端(这步服务器自动完成)

说明:

response.setHeader("content-disposition", "attachement;filename=123.jpeg");

上述代码表示将响应头 content-disposition 的值设为 attachement;filename=123.jpeg。其中 attachement 表示响应的资源以附件形式打开;filename 是弹出的下载对话框中显示的文件名称以及文件下载后的文件名称。

示例代码

前端页面示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="/servlet_demo/download?fileName=1.jpeg">图片</a>
<a href="/servlet_demo/download?fileName=1.avi">视频</a>
</body>
</html>

服务端示例代码:

package priv.lwx.javaex.servlet_demo.web.servlet.download;
/**
 * description
 *
 * @author liaowenxiong
 * @date 2022/1/12 21:57
 */


import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doPost(request, response);
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 1.获取请求参数fileName
    String fileName = request.getParameter("fileName");
    // 2.使用字节输入流加载文件进内存
    // 2.1.获取文件的服务器路径
    String realPath = this.getServletContext().getRealPath("/image/" + fileName);
    // 2.2.获取文件的文件字节输入流(用文件字节流关联文件)
    FileInputStream fis = new FileInputStream(realPath); // 这步就完成了读取文件数据进内存的操作
    System.out.println(fis);
    // 3.设置响应头
    // 3.1.设置响应头content-type
    ServletContext context = this.getServletContext();
    // 获取文件的MIME类型
    String mimeType = context.getMimeType(fileName);
    // 告诉客户端响应体的数据类型
    response.setHeader("content-type", mimeType);
    // 3.2.设置响应头content-disposition
    response.setHeader("content-disposition", "attachement;filename=" + fileName);
    // 4.将输入流的数据写入到输出流中(类似文件复制的操作)
    // 4.1.获取字节输出流
    ServletOutputStream sos = response.getOutputStream();
    // 4.2.定义读取到的字节数据的缓冲区
    byte[] buff = new byte[1024 * 8];
    int len = 0;
    // 将字节数据读取到字节数组中,返回读取到的字节数,如果返回的字节数不是-1,说明没有读到文件末尾
    // 注意:字节输入流每次读取到字节数组中的数据会覆盖原来的旧数据
    while ((len = fis.read(buff)) != -1) {
      // 将字节数组中的字节数据写入到字节输出流中,
      sos.write(buff, 0, len);
    }
    // 5.释放资源
    fis.close();


  }
}

下载的文件中文名显示问题

如果你下载的文件名称是中文,不同浏览器版本会有不同的显示,不过都是错误的显示。

解决的办法:判断浏览器的版本,根据不同的浏览器版本对文件名进行不同的编码,再返回给客户端显示。

处理文件名称的示例代码如下:

package priv.lwx.javaex.servlet_demo.util;

import Decoder.BASE64Encoder;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * 处理下载文件的中文名无法显示的问题
 *
 * @author liaowenxiong
 * @date 2022/1/13 11:55
 */

public class DownloadUtils {
  public static String getFileName(String agent, String filename) throws UnsupportedEncodingException, UnsupportedEncodingException {
    if (agent.contains("М?IЕ")) {
      // IE浏览器
      filename = URLEncoder.encode(filename, "utf-8");
      filename = filename.replace("+", " ");
    } else if (agent.contains("Firefox")) {
      //火狐浏览器
      BASE64Encoder base64Encoder = new BASE64Encoder();
      filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
    } else {
      //其它浏览器
      filename = URLEncoder.encode(filename, "utf-8");
    }
    return filename;
  }
}

最终完整的文件下载的示例代码:

package priv.lwx.javaex.servlet_demo.web.servlet.download;
/**
 * 文件下载的示例代码
 *
 * @author liaowenxiong
 * @date 2022/1/12 21:57
 */


import priv.lwx.javaex.servlet_demo.util.DownloadUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doPost(request, response);
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 1.获取请求参数fileName
    String fileName = request.getParameter("fileName");
    // 2.使用字节输入流加载文件进内存
    // 2.1.获取文件的服务器路径
    String realPath = this.getServletContext().getRealPath("/image/" + fileName);
    // 2.2.获取文件的文件字节输入流(用文件字节流关联文件)
    FileInputStream fis = new FileInputStream(realPath); // 这步就完成了读取文件数据进内存的操作
    // System.out.println(fis);
    // 3.设置响应头
    // 3.1.设置响应头content-type
    ServletContext context = this.getServletContext();
    // 获取文件的MIME类型
    String mimeType = context.getMimeType(fileName);
    // 告诉客户端响应体的数据类型
    response.setHeader("content-type", mimeType);
    // 3.2.设置响应头content-disposition
    // 获取请求头user-agent
   /* String agent = request.getHeader("user-agent");
    // 根据浏览器版本对文件名进行不同的处理,以解决中文无法显示的问题
    fileName = DownloadUtils.getFileName(agent, fileName);*/
    response.setHeader("content-disposition", "attachement;filename=" + fileName);// filename是在下载提示框显示的文件名
    // 4.将输入流的数据写入到输出流中(类似文件复制的操作)
    // 4.1.获取字节输出流
    ServletOutputStream sos = response.getOutputStream();
    // 4.2.定义读取到的字节数据的缓冲区
    byte[] buff = new byte[1024 * 8];
    int len = 0;
    // 将字节数据读取到字节数组中,返回读取到的字节数,如果返回的字节数不是-1,说明没有读到文件末尾
    // 注意:字节输入流每次读取到字节数组中的数据会覆盖原来的旧数据
    while ((len = fis.read(buff)) != -1) {
      // 将字节数组中的字节数据写入到字节输出流中,
      sos.write(buff, 0, len);
    }
    // 5.释放资源
    fis.close();


  }
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 01:50:01  更:2022-01-14 01:51:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:51:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码