How to get HttpServletRequest object in Spring Schedular (#Schedule)? - spring

I am trying to send a mail using spring scheduler. In that I need HttpServletRequest object to create webContext, so that I can send mail using thyme leaf.
Anyone know the answer of this. Thanks in advance. Code is as follows,
#Async
private void sendNotification(String toField, Users user, int currentMonth)
throws Exception {
// Prepare the evaluation context
#SuppressWarnings("deprecation")
**//here i need request object**
final WebContext ctx = new WebContext(request, request.getSession()
.getServletContext(), request.getLocale());
ctx.setVariable("eagletId", user.getEagletId());
ctx.setVariable("name", user.getFirstName());
ctx.setVariable("setSentDate", new Date());
ctx.setVariable("department", user.getDepartment());
ctx.setVariable("batch", user.getBatch());
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(user.getEmail());
// create html body using thymeleaf
final String htmlContent = this.templateEngine.process("email.html",
ctx);
helper.setText(htmlContent, true);
mailSender.send(message);
}

Related

How to use MockMVC test the controller which use org.apache.commons.fileupload?

My Controller use " org.apache.commons.fileupload " realized the file UPload.
see it:
#PostMapping("/upload")
public String upload2(HttpServletRequest request) throws Exception {
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter = upload.getItemIterator(request);
boolean uploaded = false;
while (iter.hasNext() && !uploaded) {
FileItemStream item = iter.next();
if (item.isFormField()) {
item.openStream().close();
} else {
String fieldName = item.getFieldName();
if (!"file".equals(fieldName)) {
item.openStream().close();
} else {
InputStream stream = item.openStream();
// dosomething here.
uploaded = true;
}
}
}
if (uploaded) {
return "ok";
} else {
throw new BaseResponseException(HttpStatus.BAD_REQUEST, "400", "no file field or data file is empty.");
}
}
and my MockMvc code is
public void upload() throws Exception {
File file = new File("/Users/jianxiaowen/Documents/a.txt");
MockMultipartFile multipartFile = new MockMultipartFile("file", new FileInputStream(file));
HashMap<String, String> contentTypeParams = new HashMap<String, String>();
contentTypeParams.put("boundary", "----WebKitFormBoundaryaDEFKSFMY18ehkjt");
MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post(baseUrl+"/upload")
.content(multipartFile.getBytes())
.contentType(mediaType)
.header(Origin,OriginValue)
.cookie(cookie))
.andReturn();
logResult(mvcResult);
}
my controller is right , it has successed in my web project,
but I want to test it use MvcMock, it has some mistake, see :
can someOne can help me?
"status":"400","msg":"no file field or data file is empty.","data":null
I don't know why it says my file is empty.
my English is poor, thank you very much if someone can help me.
The MockMvc can be used for integration testing for controllers using Apache Commons Fileupload too!
Import the org.apache.httpcomponents:httpmime into your pom.xml or gradle.properties
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.13</version>
</dependency>
Update the code to use MultipartEntityBuilder to build the multipart request on the client, and then serialize the entity into bytes, which is then set in the request content
public void upload() throws Exception {
File file = new File("/Users/jianxiaowen/Documents/a.txt");
String boundary = "----WebKitFormBoundaryaDEFKSFMY18ehkjt";
// create 'Content-Type' header for multipart along with boundary
HashMap<String, String> contentTypeParams = new HashMap<String, String>();
contentTypeParams.put("boundary", boundary); // set boundary in the header
MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
// create a multipart entity builder, and add parts (file/form data)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
HttpEntity multipartEntity = MultipartEntityBuilder.create()
.addPart("file", new FileBody(file, ContentType.create("text/plain"), file.getName())) // add file
// .addTextBody("param1", "value1") // optionally add form data
.setBoundary(boundary) // set boundary to be used
.build();
multipartEntity.writeTo(outputStream); // or getContent() to get content stream
byte[] content = outputStream.toByteArray(); // serialize the content to bytes
MvcResult mvcResult = mockMvc.perform(
MockMvcRequestBuilders.post(baseUrl + "/upload")
.contentType(mediaType)
.content(content) // finally set the content
.header(Origin,OriginValue)
.cookie(cookie)
).andReturn();
logResult(mvcResult);
}
Can you try the below?
mockMvc.perform(
MockMvcRequestBuilders.multipart(baseUrl+"/upload")
.file(multiPartFile)
).andReturn();
Update:
You need to update the controller to handle the MultipartFile:
#PostMapping("/upload")
public String upload2(#RequestParam(name="nameOfRequestParamWhichContainsFileData")
MultipartFile uploadedFile, HttpServletRequest request) throws Exception {
//the uploaded file gets copied to uploadedFile object.
}
You need not use another library for managing file uploads. You can use the file upload capabilities provided by Spring MVC.

Instantiate IWebContext inside JmsListener in Spring

I have a Spring app running as a rest api.
Let's assume that at some point, a message with some info is generated and stored in a AWS SQS queue.
When JMSListener is called, Im trying to generate a pdf report with thymeleaf and openhtmltopdf. I'm having troubles while instantiating IWebContext because it needs HttpServletRequest, HttpServletResponse, and Locale as params. Locale is not a problem as I could include it as a part of the SQS message, but I'm stuck with REQ and RES.
Code i'm using:
IWebContext ctx = new WebContext(¿REQUEST?, ¿RESPONSE?, servletContext, locale, mapParams);
String processedHtml = templateEngine.process(template, ctx);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.useSVGDrawer(new BatikSVGDrawer());
builder.useFastMode();
builder.withHtmlContent(processedHtml, baseUrl);
builder.toStream(bos);
builder.run();
return bos.toByteArray();
} catch (Exception e) {
logger.error("xxx");
}
As it is being called inside #JmsListener(destination = "${aws.sqs.queue.name}") annotated method, I cannot use none of the following options:
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
Because:
RequestContextHolder.getRequestAttributes()
is always null.
Thanks and regards.
I don't think you should be using an IWebContext for this. Instead, just use org.thymeleaf.context.Context.

send mail through spring boot application

I am creating spring boot application where I have to send newly generated response string for each transaction to user as a text file attachment
so what will be the proper way to do this
any help would be appreciated
Try this below code:
#Override
public void sendMessageWithAttachment(
String to, String subject, String text, String pathToAttachment) {
// ...
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(text);
FileSystemResource file
= new FileSystemResource(new File(pathToAttachment));
helper.addAttachment("Invoice", file);
emailSender.send(message);
// ...
}

Couldn't prepare mail with inline image using Thymeleaf templateEngine?

I am trying to send a html email with an inline-image attached using spring mvc and Thymeleaf. My code works without attaching the image. I get the html email successfully without image. But When I added the following line to my code I get the below error message.
Without this line code works and I get the email without image:
message.addInline(image.getName(), imageSource, image.getContentType());
This is the method:
public void sendUserRegisterEmail(String receiver, String receiverEmailAddress){
MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
Path path = Paths.get("/assets/dist/img/dialog_tv_logo-white-01.png");
String fileName = "dialog_tv_logo-white-01.png";
String originalFileName = "dialog_tv_logo-white-01.png";
String contentType = "image/png";
byte[] content = null;
try {
content = Files.readAllBytes(path);
} catch (final IOException e) {
}
MultipartFile image = new MockMultipartFile(fileName,
originalFileName, contentType, content);
Locale locale = Locale.getDefault();
final Context ctx = new Context(locale);
ctx.setVariable("name", receiver);
ctx.setVariable("subscriptionDate", new Date());
ctx.setVariable("imageResourceName", image.getName());
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
message.setSubject(USER_REGISTER_MESSAGE_SUBJECT);
message.setTo(receiverEmailAddress);
message.setFrom(SENDER_EMAIL_ADDRESS);
final String htmlContent = emailTemplateEngine.process("email-inlineimage", ctx);
message.setText(htmlContent, true /* isHtml */);
final InputStreamSource imageSource = new ByteArrayResource(image.getBytes());
message.addInline(image.getName(), imageSource, image.getContentType());
}
};
sendEmail(preparator);
}
Following error message I get when the image prepare line is added:
org.springframework.mail.MailPreparationException: Could not prepare mail; nested exception is java.lang.IllegalStateException: Not in multipart mode - create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag if you need to set alternative texts or add inline elements or attachments.
Can any one figure out what is the issue here?
Finally able to fix the error after a lot of effort. Changing the following line fixed the issue. Create MimeMessageHelper by passing true
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);

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 :
Any idea whats wrong in my code?
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.
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.
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.

Resources