You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot接口返回旧Excel数据,求可行解决方案

问题原因

你用getResourceAsStream()读取文件时,这个方法会从类加载器的资源缓存中获取数据——项目启动时Tomcat会把类路径下的资源加载到内存,之后即使服务器上的文件更新了,缓存不会自动刷新,所以返回的永远是启动时的旧数据。

解决方案

根据文件存放位置,分两种常用处理方式:

方式一:直接读取服务器本地文件系统的文件(推荐)

如果Excel文件是存放在服务器的某个本地目录(而非项目的类路径/resource目录),直接通过文件系统路径读取,每次请求都会读取最新的文件内容。

修改后的代码:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

@RestController
public class DownloadController {

    // 用@Value注入文件路径,避免硬编码,可在application.properties里配置
    @Value("${excel.file.path:/opt/app/data/sample.xlsx}")
    private String excelFilePath;

    @GetMapping("/download")
    public ResponseEntity<byte[]> download() {
        File excelFile = new File(excelFilePath);
        
        // 先检查文件是否存在
        if (!excelFile.exists()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("文件不存在".getBytes());
        }

        // 用try-with-resources自动关闭流,避免资源泄漏
        try (FileInputStream is = new FileInputStream(excelFile)) {
            HttpHeaders headers = new HttpHeaders();
            // 处理文件名编码,避免中文乱码
            String encodedFileName = new String("sample.xlsx".getBytes("UTF-8"), "ISO-8859-1");
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"");
            
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
                    .body(IOUtils.toByteArray(is));
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("文件读取失败".getBytes());
        }
    }
}

注意点:

  • 把文件路径配置到application.properties里,比如excel.file.path=/opt/app/data/sample.xlsx,方便后续修改
  • 要确保Tomcat进程有该文件的读取权限
  • 文件名编码处理:用ISO-8859-1编码,避免不同浏览器下中文文件名乱码

方式二:若文件必须放在类路径下(不推荐生产环境)

如果Excel文件必须放在项目的resources目录下,生产环境可以通过禁用资源缓存或手动刷新类加载器实现,但这种方式性能差且有风险,仅建议开发环境临时用:

@GetMapping("/download")
public ResponseEntity<byte[]> download() throws IOException {
    String fileName = "/sample.xlsx";
    // 强制刷新类加载器,重新读取资源
    ClassLoader classLoader = this.getClass().getClassLoader();
    URL resource = classLoader.getResource(fileName);
    if (resource == null) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
    }
    
    // 用URL.openStream()而非getResourceAsStream(),避免缓存
    try (InputStream is = resource.openStream()) {
        // 后续header和返回逻辑同方式一
        HttpHeaders headers = new HttpHeaders();
        String encodedFileName = new String("sample.xlsx".getBytes("UTF-8"), "ISO-8859-1");
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"");
        
        return ResponseEntity.ok()
                .headers(headers)
                .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
                .body(IOUtils.toByteArray(is));
    } catch (IOException e) {
        e.printStackTrace();
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

注意:

  • 这种方式每次请求都会重新加载资源,性能不如直接读取本地文件
  • 生产环境中如果项目是打包成jar/war,resources目录里的文件是包内的,无法直接修改,所以这种场景下还是建议用方式一

内容的提问来源于stack exchange,提问作者Ankit Basrur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:15:16