1 问题描述
以下为PDF导出的部分代码,主要是获取resources下的字体文件。字体文件放置在resources下的/static/fonts目录下,最初设想是先获取字体文件所在目录,再获取目录下文件,主要代码如下:
/**
* 构建字体
*/
private static ConverterProperties buildConvertProperties() throws IOException {
ConverterProperties converterProperties = new ConverterProperties();
// 获取字体文件路径
File fontsDirectory = getClassPathStaticFile(ExportConfig.getFontPath());
if (!ObjectUtils.isEmpty(fontsDirectory)) {
// 获取字体文件
File[] fontFiles = fontsDirectory.listFiles();
FontProvider fontProvider = new FontProvider();
if (fontFiles != null && fontFiles.length != 0) {
for (File file : fontFiles) {
FontProgram fontProgram = FontProgramFactory.createFont(file.getAbsolutePath(), true);
fontProvider.addFont(fontProgram);
}
converterProperties.setFontProvider(fontProvider);
}
}
return converterProperties;
}
/**
* 获取字体文件路径
*/
public static File getClassPathStaticFile(String classPath) throws FileNotFoundException {
try {
ClassPathResource classPathResource = new ClassPathResource(classPath);
return classPathResource.getFile();
} catch (Exception e) {
log.error("获取字体路径错误:" + classPath, e);
throw new FileNotFoundException("字体获取失败");
}
}
在idea中,可以正常获取到字体目录。如果打包后,进行调用,则将会报错FileNotFoundException。这是因为打包后Spring试图访问文件系统路径,但无法访问JAR中的路径。
2023-03-07 17:30:21.602 [http-nio-8085-exec-4] ERROR com.cbex.partyconstruction.common.PdfExportUtil - 获取字体路径错误:/static/fonts
java.io.FileNotFoundException: class path resource [static/fonts] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/E:/zhdjtest/zhdj/boot/zhdj.jar!/static/fonts
at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:217) ~[spring-core-5.2.4.RELEASE.jar:5.2.4.RELEASE]
at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:154) ~[spring-core-5.2.4.RELEASE.jar:5.2.4.RELEASE]
at com.cbex.partyconstruction.common.PdfExportUtil.getClassPathStaticFile(PdfExportUtil.java:115) [zhdj.jar:?]
at com.cbex.partyconstruction.common.PdfExportUtil.buildConvertProperties(PdfExportUtil.java:92) [zhdj.jar:?]
at com.cbex.partyconstruction.common.PdfExportUtil.exportPdfToClient(PdfExportUtil.java:79) [zhdj.jar:?]
at com.cbex.partyconstruction.common.PdfExportUtil.exportPdfToClient(PdfExportUtil.java:49) [zhdj.jar:?]
2 解决方法
2.1 配置文件全路径
通过文件全路径(绝对路径)读取文件信息。代码修改如下:
/**
* 构建字体
*/
private static ConverterProperties buildConvertProperties() throws IOException {
ConverterProperties converterProperties = new ConverterProperties();
// 获取字体文件路径
File fontsDirectory = getClassPathStaticFile(ExportConfig.getFontPath());
if (!ObjectUtils.isEmpty(fontsDirectory)) {
// 获取字体文件
File[] fontFiles = fontsDirectory.listFiles();
FontProvider fontProvider = new FontProvider();
if (fontFiles != null && fontFiles.length != 0) {
for (File file : fontFiles) {
FontProgram fontProgram = FontProgramFactory.createFont(file.getAbsolutePath(), true);
fontProvider.addFont(fontProgram);
}
converterProperties.setFontProvider(fontProvider);
}
}
return converterProperties;
}
/**
* 获取字体文件路径
*/
public static File getClassPathStaticFile(String classPath) throws FileNotFoundException {
try {
// classPath为磁盘的绝对路径
return new File(FileUtil.getAbsolutePath(classPath));
} catch (Exception e) {
log.error("获取字体路径错误:" + classPath, e);
throw new FileNotFoundException("字体获取失败");
}
}
- 直接将文件放至目标服务器上,配置文件中字体路径设置为绝对路径
- 通过maven-assembly-plugin将文件打包到tar包中,但不打进jar包中。配置文件中同样将字体路径设置为绝对路径。相比上一种方式,可以避免部署时遗漏字体文件。
// 在assembly.xml文件中配置以下信息
<fileSet>
<directory>${basedir}/target/classes/static/fonts</directory>
<outputDirectory>static/fonts</outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
2.2 使用文件流
使用文件流的方式进行获取。
- 优点:字体文件在jar包中,打包后的包可独立运行,不用借助外部文件
- 缺点:此方法需要配置具体的文件名,如果文件较多,会不太友好
/**
* 构建字体
*/
private static ConverterProperties buildConvertProperties() throws IOException {
ConverterProperties converterProperties = new ConverterProperties();
// 获取字体文件名
List<String> fontName = ExportConfig.getFontName();
// 获取字体文件所在目录
String fontPath = ExportConfig.getFontPath();
FontProvider fontProvider = new FontProvider();
if (CollUtil.isNotEmpty(fontName)) {
for (String name : fontName) {
// 获取文件流
InputStream stream = PdfExportUtil.class.getClassLoader ().getResourceAsStream(StrUtil.format(FONT_PATH_NAME, fontPath, name));
assert stream != null;
final byte[] bytes = IOUtils.toByteArray(stream);
FontProgram fontProgram = FontProgramFactory.createFont(bytes, true);
fontProvider.addFont(fontProgram);
}
converterProperties.setFontProvider(fontProvider);
}
return converterProperties;
}