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

如何在JHipster应用中配置Thymeleaf PDF模板解析器并区分使用

解决方法:给邮件和PDF分别配置独立的TemplateEngine

我之前在JHipster项目里也碰到过一模一样的需求,其实核心就是把两个模板解析器分别绑定到不同的TemplateEngine实例上,这样用的时候直接指定对应的Engine就行,完全不会搞混。

1. 完善Thymeleaf配置类

修改你的ThymeleafConfiguration,添加两个命名的TemplateEngine Bean,每个Bean只关联对应的解析器:

@Configuration
public class ThymeleafConfiguration {

    // 邮件模板解析器:对应templates/mails/目录
    @Bean
    public ClassLoaderTemplateResolver emailTemplateResolver() {
        ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
        resolver.setPrefix("classpath:/templates/mails/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode(TemplateMode.HTML);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setCheckExistence(true); // 检查模板是否存在,避免找不到时报错
        return resolver;
    }

    // PDF模板解析器:对应templates/pdf/目录
    @Bean
    public ClassLoaderTemplateResolver pdfTemplateResolver() {
        ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
        resolver.setPrefix("classpath:/templates/pdf/");
        resolver.setSuffix(".html");
        // 生成PDF建议用严格的HTML或XML模式,避免渲染问题
        resolver.setTemplateMode(TemplateMode.HTML);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setCheckExistence(true);
        return resolver;
    }

    // 邮件专用TemplateEngine
    @Bean(name = "emailTemplateEngine")
    public SpringTemplateEngine emailTemplateEngine() {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.addTemplateResolver(emailTemplateResolver());
        // 如果邮件模板需要Spring方言(比如sec:authentication),可以在这里添加
        // engine.addDialect(new SpringSecurityDialect());
        return engine;
    }

    // PDF专用TemplateEngine
    @Bean(name = "pdfTemplateEngine")
    public SpringTemplateEngine pdfTemplateEngine() {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.addTemplateResolver(pdfTemplateResolver());
        // 如果PDF模板需要布局方言或其他扩展,在这里添加
        // engine.addDialect(new LayoutDialect());
        return engine;
    }
}

2. 在邮件服务中使用邮件TemplateEngine

在你的邮件发送服务类里,通过@Qualifier指定注入"emailTemplateEngine",然后直接用它渲染邮件模板:

@Service
public class MailService {

    private final SpringTemplateEngine emailTemplateEngine;

    // 构造注入时指定要使用的TemplateEngine
    public MailService(@Qualifier("emailTemplateEngine") SpringTemplateEngine emailTemplateEngine) {
        this.emailTemplateEngine = emailTemplateEngine;
    }

    public void sendWelcomeEmail(String username) {
        Context context = new Context();
        context.setVariable("username", username);
        
        // 直接传模板名称(对应templates/mails/welcome.html)
        String emailContent = emailTemplateEngine.process("welcome", context);
        
        // 后续的邮件发送逻辑(比如用JavaMailSender发送)
        // ...
    }
}

3. 在PDF生成服务中使用PDF TemplateEngine

同样,在PDF生成类里注入"pdfTemplateEngine",渲染PDF模板后再转成PDF文件:

@Service
public class PdfGeneratorService {

    private final SpringTemplateEngine pdfTemplateEngine;

    public PdfGeneratorService(@Qualifier("pdfTemplateEngine") SpringTemplateEngine pdfTemplateEngine) {
        this.pdfTemplateEngine = pdfTemplateEngine;
    }

    public byte[] generateInvoicePdf(Invoice invoice) {
        Context context = new Context();
        context.setVariable("invoice", invoice);
        context.setVariable("totalAmount", invoice.calculateTotal());
        
        // 渲染PDF模板(对应templates/pdf/invoice.html)
        String htmlContent = pdfTemplateEngine.process("invoice", context);
        
        // 用PDF库(比如iText 7)把HTML转成PDF
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            PdfWriter writer = new PdfWriter(outputStream);
            PdfDocument pdfDoc = new PdfDocument(writer);
            Document doc = new Document(pdfDoc);
            
            HtmlConverter.convertToDocument(htmlContent, doc);
            doc.close();
            
            return outputStream.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("Failed to generate PDF", e);
        }
    }
}

为什么这样做?

每个TemplateEngine实例只绑定了自己对应的解析器,所以调用process()方法时,只会去对应的模板目录查找文件,完全不会出现解析器混用的问题。这种方式在JHipster项目里非常清晰,也方便后续扩展(比如给PDF模板添加专门的方言)。

最后确认一下你的模板文件路径:

  • 邮件模板放在 src/main/resources/templates/mails/
  • PDF模板放在 src/main/resources/templates/pdf/

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:44:32