# autopoi word 模板找不到问题
autopoi 基于 word 模板提示文件找不到问题解决
# 异常栈
autopoi 在 springboot 打成 jar 导出 word 提示模板找不到:
D:\deploy\server\soft\soft.jar!\BOOT-INF\classes!\template\template-11.docx (系统找不到指定的路径。)
java.io.FileNotFoundException: D:\deploy\server\soft\soft.jar!\BOOT-INF\classes!\template\template-11.docx (系统找不到指定的路径。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at org.jeecgframework.poi.cache.manager.FileLoade.getFile(FileLoade.java:47)
at org.jeecgframework.poi.cache.manager.POICacheManager$1.load(POICacheManager.java:48)
at org.jeecgframework.poi.cache.manager.POICacheManager$1.load(POICacheManager.java:45)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3529)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2278)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2155)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2045)
at com.google.common.cache.LocalCache.get(LocalCache.java:3951)
# 解决方法
//导出模板代码
document = WordExportUtil.exportWord07("template/template-11.docx", map);
//修改为 通过ClassPathResource加载模板文件
InputStream fis = null;
XWPFDocument document = null;
try {
//加载模板
ClassPathResource resource = new ClassPathResource("template/template-11.docx");
fis = resource.getInputStream();
document = new MyXWPFDocument(fis);
} catch (Exception e) {
log.error("读取模板失败", e);
} finally {
try {
assert fis != null;
fis.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
//根据模板生成word文件
WordExportUtil.exportWord07(document, map);
# 问题解析
为什么使用 document = WordExportUtil.exportWord07("template/template-11.docx", map);
会报错,提示文件找不到?查看以下源码:
public byte[] getFile(String url) {
FileInputStream fileis = null;
ByteArrayOutputStream baos = null;
try {
// 先用绝对路径查询,再查询相对路径
try {
fileis = new FileInputStream(url);
} catch (FileNotFoundException e) {
//这里虽然对springboot 打成jar获取文件进行了处理
String path = PoiPublicUtil.getWebRootPath(url);
//但是springboot下,FileInputStream的方式是读取不到jar里边的静态文件,需要调整为 ClassPathResource 读取静态文件
//FileInputStream方式可以对放在磁盘某个位置的文件进行读取,比如:d盘 D://opt 但是对jar里边的文件是读取不到的
fileis = new FileInputStream(path);
}
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = fileis.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
return baos.toByteArray();
} catch (FileNotFoundException e) {
LOGGER.error(e.getMessage(), e);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
} finally {
try {
if (fileis != null)
fileis.close();
if (fileis != null)
baos.close();
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
}
LOGGER.error(fileis + "这个路径文件没有找到,请查询");
return null;
}
总结: FileInputStream 只能读取文件系统中的文件,而不是 JAR 包中的资源。
# 拓展
springboot 下如果加载文件,可以通过下面几种方式:
# 1. ResourceLoader
简介:ResourceLoader 是 Spring 的通用资源加载器接口,允许你根据不同的路径前缀加载不同类型的资源。它支持从多种位置加载资源,包括类路径、文件系统、URL 等。
灵活性:支持通过不同的前缀加载资源,如:
classpath: 表示从类路径加载资源。
file: 表示从文件系统中加载资源。
http: 或其他 URL 表示通过 URL 访问资源。
用法:当你需要根据资源的位置动态加载资源时,ResourceLoader 更加灵活。通过它,你可以根据路径前缀自动选择资源的加载方式。
@Autowired
private ResourceLoader resourceLoader;
public void loadResource() {
// 从类路径加载
Resource resource1 = resourceLoader.getResource("classpath:template/template-11.docx");
// 从文件系统加载
Resource resource2 = resourceLoader.getResource("file:/path/to/file.txt");
// 从 URL 加载
Resource resource3 = resourceLoader.getResource("http://example.com/file.txt");
}
# 优点:
- 灵活:可以根据前缀自动识别并加载不同类型的资源。
- 统一接口:你不需要关心资源从哪里加载,它统一提供了
Resource
接口。
# 缺点:
- 如果你只想加载类路径资源,
ResourceLoader
可能显得过于通用。
# 2. ClassPathResource
- 简介:
ClassPathResource
是专门用于从类路径加载资源的工具,继承自DefaultResourceLoader
。它只适用于加载位于类路径下的资源,通常用于加载项目中的文件(如配置文件、模板文件等),尤其是打包后的 JAR 文件中的资源。 - 用法:如果你明确知道资源在类路径下,并且不需要支持其他类型的资源路径,可以直接使用
ClassPathResource
。
public void loadResource() {
ClassPathResource resource = new ClassPathResource("template/template-11.docx");
InputStream inputStream = resource.getInputStream();
// 读取文件内容
}
# 优点:
- 简单明了:专门用于类路径资源加载,适合明确在类路径下的资源。
- 轻量级:相对比
ResourceLoader
更加轻量,只用于类路径资源。
# 缺点:
- 局限性:只能加载类路径资源,不能处理文件系统或 URL 资源。
# 区别总结:
特性 | ResourceLoader | ClassPathResource |
---|---|---|
用途 | 通用的资源加载器,支持多种资源加载方式 | 专门用于加载类路径资源 |
支持的资源类型 | 类路径、文件系统、URL 等 | 仅限类路径资源 |
灵活性 | 高,支持动态路径前缀加载 | 低,固定为类路径资源加载 |
适用场景 | 需要根据不同路径加载不同类型资源时 | 明确知道资源在类路径下时 |
# 什么时候用哪一个?
ResourceLoader
:当你需要灵活地从多种来源(类路径、文件系统、URL)加载资源时,使用ResourceLoader
。ClassPathResource
:当你只需要从类路径加载资源(如加载项目中的模板文件、配置文件)时,使用ClassPathResource
会更直接简单。
← 暂无 poi 生成word统计图表 →