Spring自定义SpringTemplateEngine Bean未被Service使用,模板渲染失败
问题描述
尝试使用指定模板发送邮件时,调用templateEngine.process未抛出异常,但未对模板进行渲染处理,仅返回模板名称字符串(如activationEmail.html),最终收到的邮件内容就是该字符串。
POM依赖
<dependencies> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- Spring Doc --> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.1.0</version> </dependency> <!-- Eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- LOMBOK --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.26</version> </dependency> </dependencies>
配置类
@Configuration public class EmailConfiguration { @Bean public SpringTemplateEngine springTemplateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.addTemplateResolver(htmlTemplateResolver()); return templateEngine; } @Bean public ClassLoaderTemplateResolver htmlTemplateResolver(){ ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver(); emailTemplateResolver.setPrefix("classpath:/templates/"); emailTemplateResolver.setSuffix(".html"); emailTemplateResolver.setTemplateMode(TemplateMode.HTML); emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name()); return emailTemplateResolver; } }
控制器
@PostMapping("/send") public boolean sendEmail(@RequestParam("lang") String language, @RequestBody EmailRequestDTO payload) throws NotifierEmailException { emailService.sendSimpleMailMessage(payload, language); return true; }
服务类
@Service public class EmailService { private static final String ENCODING = "UTF-8"; private final JavaMailSender emailSender; public final TemplateEngine template = new SpringTemplateEngine(); @Autowired public EmailService(JavaMailSender emailSender) { this.emailSender = emailSender; } public void sendSimpleMailMessage(EmailRequestDTO emailRequestDTO, String language) throws NotifierEmailException { try { var locale = Locale.forLanguageTag(language); // Prepare the evaluation context final Context thymeleafContext = new Context(locale); emailRequestDTO.getAttributes().forEach(thymeleafContext::setVariable); // Prepare message using a Spring helper final MimeMessage mimeMessage = emailSender.createMimeMessage(); final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, ENCODING); message.setSubject(emailRequestDTO.getSubject()); message.setFrom(emailRequestDTO.getEmailFrom()); message.setTo(emailRequestDTO.getEmailTo()); // Create the HTML body using Thymeleaf /* This line here returns a string with the template name that I passed! */ final String htmlContent = template.process("activationEmail.html", thymeleafContext); message.setText(htmlContent, true); // Send mail emailSender.send(mimeMessage); } catch (Exception exception) { throw new NotifierEmailException(HttpStatus.INTERNAL_SERVER_ERROR, exception.getMessage()); } } }
补充说明
未通过application.properties配置Thymeleaf,模板文件放置在classpath:/templates/目录下,执行日志显示邮件内容为activationEmail.html,实际收到的邮件仅显示该字符串。
解决方案
问题核心是服务类中手动创建了SpringTemplateEngine实例,而非使用配置类中已配置好的Bean。你直接new SpringTemplateEngine()得到的实例没有添加任何模板解析器,Thymeleaf找不到对应模板文件,因此直接返回了模板名称。
修改步骤
- 删除服务类中手动创建的
template字段 - 通过
@Autowired注入配置类中定义的TemplateEngine(或SpringTemplateEngine)
修改后的服务类代码:
@Service public class EmailService { private static final String ENCODING = "UTF-8"; private final JavaMailSender emailSender; private final TemplateEngine templateEngine; @Autowired public EmailService(JavaMailSender emailSender, TemplateEngine templateEngine) { this.emailSender = emailSender; this.templateEngine = templateEngine; } public void sendSimpleMailMessage(EmailRequestDTO emailRequestDTO, String language) throws NotifierEmailException { try { var locale = Locale.forLanguageTag(language); final Context thymeleafContext = new Context(locale); emailRequestDTO.getAttributes().forEach(thymeleafContext::setVariable); final MimeMessage mimeMessage = emailSender.createMimeMessage(); final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, ENCODING); message.setSubject(emailRequestDTO.getSubject()); message.setFrom(emailRequestDTO.getEmailFrom()); message.setTo(emailRequestDTO.getEmailTo()); // 使用注入的模板引擎处理模板,无需加.html后缀(配置类已设置) final String htmlContent = templateEngine.process("activationEmail", thymeleafContext); message.setText(htmlContent, true); emailSender.send(mimeMessage); } catch (Exception exception) { throw new NotifierEmailException(HttpStatus.INTERNAL_SERVER_ERROR, exception.getMessage()); } } }
额外注意点
- 调用
process方法时,只需传入模板名称activationEmail即可,配置类中已设置后缀.html,无需重复添加 - 确保
classpath:/templates/activationEmail.html文件确实存在,且内容符合Thymeleaf语法规范
内容的提问来源于stack exchange,提问作者Alfredo Marin
相关产品推荐
相关产品推荐

