nilsi
nilsi

Reputation: 10761

Using multiple template resolvers with Spring 3.2 and Thymeleaf 2.1.3 for emails

I have problem defining a ClassLoaderTemplateResolver for emails and one ServletContextTemplateResolver for web views. I getting the following error when trying to send emails:

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]

My WebMvcConfig looks like this:

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;
}

And my EmailService like this:

@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);
    }
}

The error occours on the following line:

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

Where it is using ServletContextResourceResolver instead of my other resolver. I want it to use ClassLoaderTemplateResolver since it can handle plain Context objects instead of having to use WebContext. However, I could try to use a WebContext instead since it implements the IWebContext and only use one resolver. But then I need a HttpServletRequest, HttpServletResponse and a ServletContext as parameters which seems to messy.

My structure :

File structure

Any idea whats wrong in my code?

Upvotes: 2

Views: 2783

Answers (3)

riddle_me_this
riddle_me_this

Reputation: 9155

Since you're using the ClassLoaderTemplateResolver, Spring is going to use the prefix and append it to WEB-INF/classes. So the thing to check is whether Maven (or whatever build tool you're using) copied the html file to WEB-INF/classes/mail/email-buy-book.html. If it didn't, try copying it manually and give it a go. Looking at your screenshot, I don't see the "mail" folder under "classes" so this could be the issue.

Also, only pass "email-buy-book" and leave out the extension as @grid mentioned.

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

I have it working with XML config and not Java config, but I don't see why that should matter for you.

Upvotes: 0

gregdim
gregdim

Reputation: 2071

Since you (correctly) set the ClassLoaderTemplateResolver to have priority over the ServletContextTemplateResolver, Thymeleaf tries to use the correct order but fails to resolve the view with former and then tries latter.
I believe that the problem is with the prefix and suffix parameters you set combined with the view name you pass to templateEngine.process method. Thymeleaf will construct your view name by concatenating suffix + viewname + suffix resulting to "mail/email-buy-book.html.html".
Try to pass only "email-buy-book" and see if it solves the problem.

Upvotes: 1

nilsi
nilsi

Reputation: 10761

I gave up this and went for the WebContext approach instead, even though i'm stuck needing the request, response and servletcontext every time sending something. This is how I did it:

1. Get the servlet context:

@Autowired
ServletContext servletContext;

2. Get the request and response as parameters to the sendmail method:

HttpServletRequest request,
HttpServletResponse response

3. Create the WebContext instead:

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

It worked from now on.

Upvotes: 1

Related Questions