使用freemarker+itextpdf通过HTML模版导出PDF踩过的坑

使用freemarker+itextpdf通过HTML模版导出PDF踩过的坑

文章目录

  • 使用freemarker+itextpdf通过HTML模版导出PDF踩过的坑
    • 1. 在linux中路径的问题
    • 2.导出的pdf中文不显示
    • 3.springcloud gateway nullpointerexception (NettyRoutingFilter)
    • 4.分页处理
    • 5.pdf导出图片时,图片过长导致分页问题,后面空白页

1. 在linux中路径的问题

在windows中使用this.class.getClassLoader().getResource("").getPath()获取路径没问题,
在linux中提示找不到模板文件
解决办法:
如果直接读可以使用getClass().getClassLoader().getResourceAsStream(path)
想深入了解的小伙伴可以参考:jar读取资源配置文件,jar包内包外,以及包内读取目录的方法
如果想通过classpath下的templates文件夹获取可以配置freemarker。

@Configuration
public class FreeMarkerConfig {

    @Autowired
    protected FreeMarkerConfigurer configurer;

    @PostConstruct
    public void setSharedVariable() {
        configurer.setTemplateLoaderPath("classpath:/templates/");
        freemarker.template.Configuration config = null;
        try {
            config = configurer.createConfiguration();
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }
        config.setDefaultEncoding("UTF-8");
        config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        config.setLogTemplateExceptions(false);
        config.setNumberFormat("#");
        config.setDateFormat("yyyy/MM/dd");
        config.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
        configurer.setConfiguration(config);
    }
}

由于作者对freemarker不是很熟,在网上也没有找到很好的配置,所以配置可能有其他缺陷或者修正的地方,还请麻烦大佬们帮忙指出,多谢。

Template template = freemarkerConfig.getConfiguration().getTemplate(fileName + ".ftl");

这样直接getTemplate就可以获取到classpath下的templates的模板。

2.导出的pdf中文不显示

增加依赖

        
            com.itextpdf
            itext-asian
            5.2.0
        

增加类

    /**
     * 处理中文不显示和乱码问题
     */
    class ChineseFontsProvider extends XMLWorkerFontProvider {
        @Override
        public Font getFont(final String fontname, String encoding, float size, final int style) {
            try {
                BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                return new Font(bfChinese, size, style);
            } catch (DocumentException | IOException e) {
                e.printStackTrace();
            }
            return super.getFont(fontname, encoding, size, style);
        }
    }

调用时选择字体为新加的类对象

	XMLWorkerHelper.getInstance().parseXHtml(writer,document,
		new ByteArrayInputStream(htmlString.getBytes()),
		XMLWorkerHelper.class.getResourceAsStream("/default.css"),
		Charset.forName("UTF-8"),new ChineseFontsProvider());

3.springcloud gateway nullpointerexception (NettyRoutingFilter)

springcloud的版本问题,header中的ContentType为空导致。像下载文件,或者在controller中进行跳转时,都会出现这种情况。

这个bug在spring cloud gateway的github上作者已经说明的解决方案:将springcloud gateway升级至2.0.1或以上的版本即可,我之前使用的是2.0.0,对应springcloud的版本 为 Finchley.RELEASE
想深入了解的小伙伴可以参考:springcloud gateway nullpointerexception (NettyRoutingFilter)
如果因为部分原因不能换其他的版本(我就是这种情况),可以将导出pdf的流上传至oss,然后返回链接再下载。

4.分页处理

如果想在分页时做处理

    public class MyPdfPageEventHelperextends PdfPageEventHelper

可以继承PdfPageEventHelper,重写方法
并在调用

    XMLWorkerHelper.getInstance().parseXHtml(writer,document,
    	new ByteArrayInputStream(htmlString.getBytes()),
    	XMLWorkerHelper.class.getResourceAsStream("/default.css"),
    	Charset.forName("UTF-8"),new ChineseFontsProvider());

前设置writer.setPageEvent(new MyPdfPageEventHelper());

5.pdf导出图片时,图片过长导致分页问题,后面空白页

itext
取出有图片的list,通过sourceImg获取他的长和宽,在满足某些条件的时候,设置属性,并把该属性应用到freemarker中。

    collect.forEach(c -> {
        BufferedImage sourceImg= null;
        try {
            sourceImg = ImageIO.read(new URL(c.getFileUrl()).openStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (sourceImg != null) {
            int height = sourceImg.getHeight();
            int width = sourceImg.getWidth();
            if (width / height < 4 / 3) {
                c.setHtmlExtend("height: 400px");
            }
        }
    });
	

是个取巧的办法,找了很久都没有很好的解决办法,所以只能暂时使用这种,并且并不能确认100%是因为图片长导致的,因为有些比例1:1的图片,虽然很长但是会自动分页,调试了一波后使用4/3这种比较好(因需求不同,条件和css都不同),这里不是很规范,推荐写成常量判断。

最后,文章内有出错的地方麻烦大家帮忙指正,如果您有更好的解决办法请一定留言评论,说不定会帮到更多的人。多谢大家的阅读,非常感谢。

解决问题参考的非常好的文章:
java操作PDF之iText超入门
iText5使用HTML生成PDF设置重复表头和强制翻页
使用freemarker+itextpdf通过HTML模版导出PDF
可能有用的文章:
Freemarker如何使用jar中的模板

你可能感兴趣的:(学习成长解决问题)