описание сцены
Используя Springboot для реализации функции загрузки файла, код выглядит следующим образом
String fileName = "template.xls";
res.setHeader("Content-disposition", "attachment;fileName=" + fileName);
res.setContentType("application/vnd.ms-excel;charset=UTF-8");
res.setCharacterEncoding("UTF-8");
File file = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "excelTemplate/template.xls");
FileInputStream input = new FileInputStream(file);
OutputStream out = res.getOutputStream();
byte[] b = new byte[2048];
int len;
while ((len = input.read(b)) != -1) {
out.write(b, 0, len);
}
input.close();
Загрузите файл, который находится под ресурсами, и используйте IDEA, чтобы начать отладку при локальном тестировании, можно успешно загрузить файл на локальный и открыть обычный файл.
сообщение об ошибке
После завершения локальной отладки проект упаковывается в пакет jar, а затем развертывается на сервере для запуска.В это время снова перейдите по ссылке для скачивания и получите поврежденный файл размером 0 КБ, проверьте журнал приложений сервера и получите следующее сообщение об ошибке; Template.xls не может быть преобразован в абсолютный путь к файлу, поскольку он не находится в файловой системе.
причина
После запроса данных я обнаружил, что проблема возникла в методе ResourceUtils.getFile(), я пришел к исходному коду этого метода и нашел место, где было напечатано вышеуказанное сообщение об ошибке.
if (!"file".equals(resourceUrl.getProtocol())) {
throw new FileNotFoundException(description + " cannot be resolved to absolute file path because it does not reside in the file system: " + resourceUrl);
}
Видно, что если протокол текущего файла не файлового типа, то возникнет эта ошибка. В среде отладки файл существует в виде файла, поэтому к нему можно получить доступ с помощью ResourceUtils.getFile(), но в виде jar-пакета после упаковки форма файла больше не существует, а может только читаться в потоке.
Решение
ClassPathResource classPathResource = new ClassPathResource("excelTemplate/template.xls");
InputStream input = classPathResource.getInputStream();
Просто прочитайте метод ResourceUtils.getFile() и измените его для чтения из ClassPathResource. Обратите внимание, что URL-адрес здесь не должен иметь префикс classpath:.