Использование нескольких шаблонных решений с Spring 3.2 и Thymeleaf 2.1.3 для электронных писем

У меня проблема с определением ClassLoaderTemplateResolver для электронных писем и одним ServletContextTemplateResolver для просмотра веб-страниц. При попытке отправить электронные письма появляется следующая ошибка:

HTTP Status 500 - Request processing failed; nested exception is
org.thymeleaf.exceptions.TemplateProcessingException: Resource resolution by ServletContext with
org.thymeleaf.resourceresolver.ServletContextResourceResolver can only be performed when context 
implements org.thymeleaf.context.IWebContext [current context: org.thymeleaf.context.Context]

Мой WebMvcConfig выглядит так:

private static final String VIEWS_PATH = "/WEB-INF/views/";
private static final String MAIL_PATH = "mail/";

@Bean
public ServletContextTemplateResolver templateResolver() {
 final ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
 resolver.setPrefix(VIEWS_PATH);
 resolver.setSuffix(".html");
 resolver.setTemplateMode("HTML5");
 resolver.setCharacterEncoding("UTF-8");
 resolver.setOrder(2);
 resolver.setCacheable(false);
 return resolver;
}

@Bean
public ClassLoaderTemplateResolver emailTemplateResolver() {
 final ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
 resolver.setPrefix(MAIL_PATH);
 resolver.setSuffix(".html");
 resolver.setTemplateMode("HTML5");
 resolver.setCharacterEncoding("UTF-8");
 resolver.setOrder(1);
 return resolver;
}

@Bean
public SpringTemplateEngine templateEngine() {
 final SpringTemplateEngine engine = new SpringTemplateEngine();
 final Set<templateresolver> templateResolvers = new HashSet<templateresolver>();
 templateResolvers.add(templateResolver());
 templateResolvers.add(emailTemplateResolver());
 engine.setTemplateResolvers(templateResolvers);
 engine.addDialect(new SpringSocialDialect());
 engine.addDialect(new SpringSecurityDialect());
 return engine;
}
</templateresolver></templateresolver>

И мой EmailService вот так:

@Service
public class EmailService {

@Autowired
private JavaMailSender mailSender;

@Autowired
private TemplateEngine templateEngine;

/*
 * Send HTML mail with inline image
 */
public void sendEmailToBookSeller(
 final ContactBookSellerForm form,
 final Locale locale) throws MessagingException {

 boolean multipart = true;


 boolean isHtml = true;

 // Prepare the evaluation context
 final Context ctx = new Context(locale);

 ctx.setVariable("message", form.getMessage());
 ctx.setVariable("bookTitle", form.getBookTitle());
 ctx.setVariable("email", form.getToEmail());
 ctx.setVariable("logo", "logo");
 ctx.setVariable("logoOnlyText", "logoOnlyText");

 // Prepare message
 final MimeMessage mimeMessage = mailSender.createMimeMessage();

 final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, multipart, "UTF-8");
 message.setSubject("Regarding your book on Mimswell - " + form.getBookTitle());
 message.setFrom(form.getFromEmail());
 message.setTo(form.getToEmail());

 // Create the HTML body using Thymeleaf
 final String htmlContent = templateEngine.process("email-buy-book.html", ctx);

 message.setText(htmlContent, isHtml);

 message.addInline("logo", new ClassPathResource("WEB-INF/views/mail/logo130130red.png"), "image/png");
 message.addInline("logoOnlyText", new ClassPathResource("WEB-INF/views/mail/logo_only_text.png"), "image/png");

 // Send mail
 this.mailSender.send(mimeMessage);
 }
}

Ошибка возникает в следующей строке:

final String htmlContent = templateEngine.process("email-buy-book.html", ctx);

Где он использует ServletContextResourceResolver вместо моего другого распознавателя. Я хочу, чтобы он использовал ClassLoaderTemplateResolver поскольку он может обрабатывать простые объекты Context вместо использования WebContext. Однако я мог бы попытаться использовать WebContext поскольку он реализует IWebContext и использует только один резольвер. Но тогда мне нужны HttpServletRequest, HttpServletResponse и ServletContext как параметры, которые кажутся беспорядочными.

Моя структура:

Любая идея, что не так в моем коде?

3 ответа

Поскольку вы (правильно) установили для ClassLoaderTemplateResolver приоритет над ServletContextTemplateResolver, Thymeleaf пытается использовать правильный порядок, но не может разрешить представление с помощью first, а затем пытается использовать последний. Я считаю, что проблема связана с параметрами префикса и суффикса, которые вы задаете в сочетании с именем вида, которое вы передаете методу templateEngine.process. Thymeleaf построит ваше имя вида, объединив суффикс + имя + суффикс, в результате получится "mail/email-buy-book.html.html". Попытайтесь передать только "электронную книгу-книгу" и посмотрите, разрешает ли она проблему.


Я отказался от этого и пошел на подход WebContext, хотя я все время нуждался в запросе, ответе и servletcontext каждый раз при отправке чего-либо. Вот как я это сделал:

1. Получите контекст сервлета:

@Autowired
ServletContext servletContext;

2. Получить запрос и ответ в качестве параметров метода sendmail:

HttpServletRequest request,
HttpServletResponse response

3. Создайте WebContext:

final WebContext ctx = new WebContext(request, response, servletContext, locale);

С этого момента он работал.


Поскольку вы используете ClassLoaderTemplateResolver, Spring использует префикс и добавляет его в WEB-INF/classes. Итак, проверить, является ли Maven (или любой другой инструмент построения, который вы используете) скопировал html файл в WEB-INF/classes/mail/email-buy-book.html. Если это не так, попробуйте скопировать его вручную и дать ему уйти. Глядя на ваш скриншот, я не вижу папку "mail" в разделе "classes", поэтому это может быть проблемой.

Кроме того, пропустите только "электронную книгу-книгу" и оставьте это расширение, как указано в @grid.

final String htmlContent = templateEngine.process("email-buy-book", ctx);

У меня есть работа с конфигурацией XML, а не с конфигурацией Java, но я не понимаю, почему это важно для вас.

licensed under cc by-sa 3.0 with attribution.