Skip to content
欢迎扫码关注公众号

设置下载时的默认文件名

今天用 EasyExcel 导出 Excel 文件,通过 ApiFox 调用接口保存时默认文件名为 response.zip ,于是查了下如何在响应中设置默认文件名。

经调查,默认的文件名是通过 Header 中 Content-Disposition 的值决定的,其格式为

http
Content-Disposition: <disposition-type>; <parameter-name>="<parameter-value>"; ...

其中 <parameter-value> 的值通常需要 URL 编码。

如果是下载文件,则 <disposition-type> 值为 attachment

http
Content-Disposition: attachment; filename="example.txt"

如果文件名中含有中文等特殊字符,则需要改成如下格式:

http
Content-Disposition: attachment; filename*=UTF-8''%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt
  • filename*= 参数指定编码类型和编码值。
  • UTF-8 表示使用 UTF-8 编码
  • '' 表示空格分隔符
  • %E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt 是文件名的编码值

在 Java 中可以通过 ContentDisposition 对象构建这个字符串:

java
ContentDisposition disposition = ContentDisposition.builder("attachment")
        .filename("测试文件.txt", StandardCharsets.UTF_8)
        .build();
System.out.println(disposition.toString());

奇怪的是,在 ApiFox 中不支持这种,反而支持不做 URL 编码的格式:

http
Content-Disposition: attachment; filename="测试文件.txt"

为了兼容,最后将其修改为了如下格式:

http
Content-Disposition: attachment; filename="测试文件.txt"; filename*=UTF-8''%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt

另外每种文件对应的 Content-Type 是不一样的,比如 xls 文件对应的是 application/vnd.ms-excelpdf 对应的是 application/pdf

可以参考下 org.springframework.boot.web.server.MimeMappings.DEFAULT 中的值,不过这里的并不全。

最终的代码如下:

java
import cn.hutool.core.io.file.FileNameUtil;
import org.springframework.boot.web.server.MimeMappings;
import org.springframework.http.HttpHeaders;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

public class HttpUtil {

    public static void setDownloadFileName(HttpServletResponse response, String filename) throws UnsupportedEncodingException {
        // 设置 Content-Disposition
        String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString())
                // 替换空格(+)为 %20
                .replace("+", "%20");
        String disposition = "attachment; "
                + "filename=\"" + encodedFilename + "\"; "
                + "filename*=UTF-8''" + encodedFilename;
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, disposition);
        response.setHeader(HttpHeaders.CONTENT_TYPE, getContentTypeByFilename(filename));
    }

    public static String getContentTypeByFilename(String filename) {
        return Optional.ofNullable(MimeMappings.DEFAULT.get(FileNameUtil.getSuffix(filename)))
                // 默认二进制流
                .orElse("application/octet-stream");
    }
}

在 EasyExcel 的导出处理前调用上面的 setDownloadFileName 方法:

java
// 设置文件名
String sheetName = "消费明细";
String fileName = String.format("%s_%s.xls", sheetName, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
HttpUtil.setDownloadFileName(response, fileName);

// 导出文件
EasyExcel.write(response.getOutputStream(), BrandBillDetailVO.class)
        .excelType(ExcelTypeEnum.XLS)
        .sheet(sheetName)
        .doWrite(bills);

Page Layout Max Width

Adjust the exact value of the page width of VitePress layout to adapt to different reading needs and screens.

Adjust the maximum width of the page layout
A ranged slider for user to choose and customize their desired width of the maximum width of the page layout can go.

Content Layout Max Width

Adjust the exact value of the document content width of VitePress layout to adapt to different reading needs and screens.

Adjust the maximum width of the content layout
A ranged slider for user to choose and customize their desired width of the maximum width of the content layout can go.