Reputation: 461
I have an emailService implementation in my Java Spring Boot project. To send email, I use JavaMailSender. In my service I need an access to HttpServletRequest
and HttpServletResponse
in order to instantiate WebContext. Now I am passing these 2 - request and response through my mailsender
methods what sounds like a bad idea. I would like to have them in my service so I can call methods in my mailsender
with only 2 variables: what email template to use and a map of variables that will be printed on that email. Is there a way to instantiate request and response in my service? Can I somehow autowire them in the service? Thats how my service looks like:
@Service
@Qualifier("MailSender")
public class MailSenderService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private ServletContextTemplateResolver emailTemplateResolver;
public boolean sendMail(HttpServletRequest request, HttpServletResponse
response, HashMap<String, String> info, String template) throws
MessagingException, IOException{
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
final MimeMessageHelper message = new
MimeMessageHelper(mimeMessage,true, "UTF-8"); // true = multipart
message.setFrom("[email protected]");
message.setTo("[email protected]");
message.setSubject("This is the message subject");
TemplateEngine engine = new TemplateEngine();
engine.setTemplateResolver(emailTemplateResolver);
WebContext ctx = new WebContext(request, response,
request.getServletContext(), request.getLocale());
ctx.setVariable("info", info);
try{
String messageContent= engine.process(template, ctx);
mimeMessage.setContent(tt, "text/html; charset=utf-8");
}catch(Exception e){
e.printStackTrace();
}
this.mailSender.send(mimeMessage);
return true;
}
}
Upvotes: 0
Views: 4005
Reputation: 461
So this is how i solved it with annotations. Big thanks to M. Deinum !
I finally got it all working. I am not using XML. I work with Spring Boot but if I want to configure something, its all in my configuration methods. For everyone lost like I was, here is my configuration of templateEngine in my @Configuration class:
@Bean
public ClassLoaderTemplateResolver emailTemplateResolver(){
ClassLoaderTemplateResolver emailTemplateResolver = new
ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("/WEB-INF/emails/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setCharacterEncoding("UTF-8");
emailTemplateResolver.setOrder(1);
return emailTemplateResolver;
}
@Bean
public TemplateEngine templateEngine(){
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(emailTemplateResolver());
return templateEngine;
}
With this configuration I can just @Autowire
private TemplateEngine templateEngine;
In my service and now I do not need request, response. Everything works with Context
Upvotes: 0
Reputation: 124526
For starters your MailSenderService
shouldn't be bothered with creating the TemplateEngine
nor know about how to resolve templates, that should be transparant. See this turorial on the Thymeleaf website.
Assuming that you are using XML for bean configuration and Spring 4 add the following. (you probably already have an instance of the ServletContextTemplateResolver
configured).
<bean id="webTemplateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="templateMode" value="HTML5" />
<property name="characterEncoding" value="UTF-8" />
<property name="order" value="2" />
</bean>
<!-- THYMELEAF: Template Engine (Spring3-specific version) -->
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolvers">
<set>
<ref bean="emailTemplateResolver" />
<ref bean="webTemplateResolver" />
</set>
</property>
</bean>
Now in your MailSenderService
you can simply inject the TemplateEngine
.
@Service
@Qualifier("MailSender")
public class MailSenderService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private TemplateEngine engine;
public boolean sendMail(HttpServletRequest request, HttpServletResponse response, HashMap<String, String> info, String template) throws MessagingException, IOException{
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
final MimeMessageHelper message = new
MimeMessageHelper(mimeMessage,true, "UTF-8"); // true = multipart
message.setFrom("[email protected]");
message.setTo("[email protected]");
message.setSubject("This is the message subject");
WebContext ctx = new WebContext(request, response,
request.getServletContext(), request.getLocale());
ctx.setVariable("info", info);
try{
String messageContent= engine.process(template, ctx);
mimeMessage.setContent(tt, "text/html; charset=utf-8");
}catch(Exception e){
e.printStackTrace();
}
this.mailSender.send(mimeMessage);
return true;
}
}
Instead of request.getLocale()
simply use LocaleContextHolder.getLocale()
and put all the properties you need in your template in your info
variable. With this you could rewrite your method to the following.
public boolean sendMail(Map<String, String> info, String template) throws MessagingException, IOException{
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
final MimeMessageHelper message = new
MimeMessageHelper(mimeMessage,true, "UTF-8"); // true = multipart
message.setFrom("[email protected]");
message.setTo("[email protected]");
message.setSubject("This is the message subject");
Context ctx = new Context(LocaleContextHolder.getLocale());
ctx.setVariable("info", info);
try{
String messageContent= engine.process(template, ctx);
mimeMessage.setContent(tt, "text/html; charset=utf-8");
}catch(Exception e){
e.printStackTrace();
}
this.mailSender.send(mimeMessage);
return true;
}
NO need anymore for a HttpServletRequest
and HttpServletResponse
. Just a plain service. Generally you don't want that your service layer depends on the web as that is what you effectivly did in your solution.
Upvotes: 1
Reputation: 19990
You should be able to autowire HttpServletRequest
, though the same doesn't work for HttpServletResponse
.
eg.
@Autowired HttpServletRequest request; // works
@Autowired HttpServletResponse response; // doesn't work
There is some discussion about that here -- though in the end it looks like you may have to pass the response manually.
Upvotes: 1
Reputation: 88
If the class is request scoped you can autowire it as follows :
@Autowired private HttpServletRequest request;
Cheers..
Upvotes: 1