I want to create service that will send email messages to recipients. This message should be presented as a table which is filled from entity fields. I’m using Spring Boot Mail.
Solved this task with StringBuilder.
Simple MailSender configuration:
@Bean public JavaMailSender getJavaMailSender() { JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); mailSender.setHost("smtp.gmail.com"); mailSender.setPort(587); mailSender.setUsername("my.gmail@gmail.com"); mailSender.setPassword("password"); Properties props = mailSender.getJavaMailProperties(); props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.starttls.enable", "true"); props.put("mail.debug", "true"); return mailSender; }
Entity:
@Entity ... public class Mark { @Column(name = "account_login") private String accountLogin; @Id @Column(name = "account_view_id") private String accountViewId; @Column(name = "mark_text") private String text; @Column(name = "report_date") private LocalDate reportDate; //tostring, getters, setters, constructors }
Method in one of the service to send email:
public void send(String subject, String htmlMsg, String sendTo) { MimeMessage message = mailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(message, false, "utf-8"); message.setContent(htmlMsg, "text/html"); helper.setTo(sendTo); helper.setSubject(subject); mailSender.send(message); } catch (MessagingException e) { log.error(e.toString()); } }
Service which generates html table:
@Service public class TableGenerationService { @Autowired private Mark markRepository; public String generateReportMessage(List<Mark> marks) { StringBuilder stringBuilder = generateCommonHtmlHead(); for (Mark mark : marks) { stringBuilder.append("<tr>"); stringBuilder.append("<td>").append(mark.getAccountLogin()).append("</td>"); stringBuilder.append("<td>").append(mark.getText()).append("</td>"); stringBuilder.append("<td>").append(mark.getId()).append("</td>"); stringBuilder.append("<td>").append(message.getReportDate()).append("</td>"); stringBuilder.append("</tr>"); } generateCommonFooter(stringBuilder); return stringBuilder.toString(); } private StringBuilder generateCommonHtmlHead() { StringBuilder stringBuilder = new StringBuilder(); return stringBuilder.append("<head>") .append("<h1>Status<h1>") .append("</head>") .append("<body>") .append("<table border=1>") .append("<tr>") .append("<th>Author id</th><th>Authour Name</th><th>Content</th><th>Date</th>") .append("</tr>"); } private void generateCommonFooter(StringBuilder stringBuilder) { stringBuilder.append("</table></body>"); } public String generateReportMessage() { List<Mark> all = markRepository.findAll(); return generateReportMessage(all); } }
I tested this and it works kinda good. But I think StringBuilder is not good idea for this task. Are there other tools for generating html tables? Should i use thymeleaf/freemarker? What if i want to add css to table? This solution with StringBuilder will be hard to read. Or if no other tools are available, how can I improve the solution with StringBuilder?
Advertisement
Answer
I generally use Apache FreeMarker for such tasks, and here’s why you should use the template engine too:
- You already realized that it would be hard to read if you add additional content such as CSS styles;
- Your content presentation is coupled with the logic, you build it manually, looping through data etc. – FreeMarker (or another template engine) does that for you;
- It is way easier to update the template and upgrade the data model than to modify the code every time;
- You will need a basic configuration and implementation for creating the content with templates and data models that you can reuse instead of duplicating or adding the code for building various specifics manually.
Here is a pretty good example to get started (has an example for tables too): https://www.dariawan.com/tutorials/spring/spring-boot-freemarker-crud-example/