หน้าเว็บ

วันเสาร์ที่ 5 มกราคม พ.ศ. 2556

สร้าง template email ด้วย freemarker template engine : java


เนื่องจาก project ผมเป็น maven
1. add dependency ใน pom.xml
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>[2.3.19,2.4)</version>
</dependency>

2. add applicationContext.xml file  ชื่อ applicationContext-freemarker.xml ไว้ที่ WEB-INF
/WEB-INF/applicationContext-freemarker.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
    <bean id="freemarkerConfiguration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
        <description>Using the Config directly so we can use it outside the web tier</description>
        <property name="templateLoaderPaths">
            <list>
                <!-- บอกว่า template นั้นเก็บไว้ที่ classpath:templates -->
                <value>classpath:templates/</value>
            </list>
        </property>
        <property name="freemarkerSettings">
            <props>
                <prop key="datetime_format">dd MMM yyyy</prop>
                <prop key="number_format">#,##0.##</prop>
                <prop key="whitespace_stripping">true</prop>
                <prop key="locale">th_TH</prop>
            </props>
        </property>
        <property name="freemarkerVariables">
            <map>
                <entry key="xml_escape" value="fmXmlEscape" />
                <entry key="html_escape" value="fmHtmlEscape" />
            </map>
        </property>
        <property name="defaultEncoding" value="UTF-8"></property>
    </bean>
</beans>
3. สร้าง template file ที่เป็น html  ซึ่งไฟล์นี้จะมีนามสกุลเป็น .ftl เก็บไว้ที่ classpath:templates/drugStatusMailTemplate.ftl
จะสังเกตเห็นได้ว่า  ใน template จะมีตัวแปร ${ } อยู่  ซึ่งจะเอาไว้แทนค่าต่างๆ ตามที่ต้องการ  เมื่อมีการเรียกใช้งาน Service
และอีกอย่างจะสังเกตเห็นได้ว่าผมใช้ css เป็น inline  เพราะว่าผมได้ลองทดสอบดูใน gmail แล้วว่า  ไม่สามารถเขียน css แบบอื่นได้  เนื่องจากมันจะไม่ทำงาน  ยกเว้นการเขียนแบบ inline เท่านั้น
<?xml version="1.0" encoding="UTF-8"?>
<html lang="th">
    <body>
        <div class="mail-template-wrapper">
            <div style='padding :10px; font-family : arial; font-size : 11pt;'>
                <div style='font-weight : bold; margin-bottom : 10px; font-size : 11pt;'>เรียน คุณ ${notifier}</div>
                <div style='background-color:#fcfcfc; width:750px; border:1px dotted #ccc; padding:10px; position:relative;'>
                    <div style='background : #2D8AEE; border : 1px solid #154DB1; padding :10px;'>
                        <div style='font-weight : bold; color : #fff; font-size : 12pt;'>
                            ระบบยากำพร้าและยาขาดแคลนอย่างบูรณาการ และระบบติดตามผล
                        </div>    
                    </div>
                    <div style='margin-top : 5px; margin-bottom : 15px;'>
                        แจ้งเตือนสถานะปัญหายาขาดแคลน ใน 
                        <span style='font-weight : bold;'>${date}</span> 
                    </div>

                    <div class="body-content">
                        <table style="font-size : 10pt; background : #fff; border:1px dotted #ccc; padding:10px; width  : 750px">
                            <tr>
                                <td align="right" style="font-weight : bold; width : 120px;">ชื่อยาสามัญ : </td>
                                <td>${genericName}</td>
                            </tr>
                            <tr>
                                <td align="right" style="font-weight : bold;">ชื่อทางการค้า : </td>
                                <td>${tradeName}</td>
                            </tr>
                            <tr>
                                <td align="right" style="font-weight : bold;">ความแรง : </td>
                                <td>${strength}</td>
                            </tr>
                            <tr>
                                <td align="right" style="font-weight : bold;">รูปแบบ : </td>
                                <td>${style}</td>
                            </tr>
                            <tr>
                                <td align="right" style="font-weight : bold;">ขนาด : </td>
                                <td>${scale}</td>
                            </tr>
                            <tr>
                                <td align="right" style="font-weight : bold;">ผู้ผลิต/ผู้จำหน่าย : </td>
                                <td>${distributorCompany}</td>
                            </tr>
                            <tr>
                                <td align="right" style="font-weight : bold;">เลขทะเบียน : </td>
                                <td>${registerNumber}</td>
                            </tr>
                            <tr>
                                <td align="right" style="font-weight : bold;">สาเหตุการขาดยา : </td>
                                <td>${deficientCause}</td>
                            </tr>
                            <tr>
                                <td align="right" style="font-weight : bold;">วันที่แจ้ง : </td>  
                                <td>${notifyDate}</td>
                            </tr>       
                        </table>
                        <div style="margin-top : 15px; font-weight : bold; font-size : 14pt;">สถานะตอนนี้คือ 
                            <span style="color : red;">${status}</span>
                        </div>
                    </div>
                </div> 
            </div>
        </div>
    </body>
</html>
4. สร้าง interface freemarkerService ขึ้นมา
        เนื่องจากว่าเรามี template หลายตัวและมีโครงสร้างเหมือน ๆ กัน  แต่ชนิดข้อมูลต่างกัน  ผมเลย define interface  กลางขึ้นมาตัวนึง  เพื่อให้ interface ตัวอื่นๆ extends ไป
FreeMarkerService.java
package com.blogspot.na5cent.template;

import freemarker.template.TemplateException;
import java.io.IOException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Locale;

/**
 *
 * @author Redcrow
 */
public interface FreeMarkerService<T> {

    public static final String DATE_FORMAT = "EEEE ที่ dd เดือนMMMM พ.ศ. yyyy";
    public static final Format dateFormatter = new SimpleDateFormat(DATE_FORMAT, new Locale("th", "TH"));

    public String loadMailTemplate(T template) throws TemplateException, IOException;
}
        สร้าง interface ตัวใหม่ขึ้นมาเพื่อ extends FreeMarkerService<T>

FreeMarkerNotifyDrugStatusService.java
package com.blogspot.na5cent.template;

import com.blogspot.na5cent.email.template.DrugStatusMailTemplate;

/**
 *
 * @author Redcrow
 */
public interface FreeMarkerNotifyDrugStatusService extends FreeMarkerService<drugstatusmailtemplate> {

}

DrugStatusMailTemplate.java
package com.blogspot.na5cent.email.template;

import com.blogspot.na5cent.model.Deficient;

/**
 *
 * @author Redcrow
 */
public class DrugStatusMailTemplate{

    private String[] email;
    private String title;
    private String note;
    private Deficient deficient;

    //getter and setter
}

5. สร้าง class ที่ implement  FreeMarkerNotifyDrugStatusService มาใช้งาน
FreeMarkerNotifyDrugStatusServiceImpl.java
package com.blogspot.na5cent.template.impl;

import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.io.StringWriter;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
import com.blogspot.na5cent.email.template.DrugStatusMailTemplate;
import com.blogspot.na5cent.model.Deficient;
import com.blogspot.na5cent.model.DeficientStatus;
import com.blogspot.na5cent.model.template.FreeMarkerNotifyDrugStatusService;

/**
 *
 * @author Redcrow
 */
@Service
public class FreeMarkerNotifyDrugStatusServiceImpl implements FreeMarkerNotifyDrugStatusService {

    private static final Logger LOG = LoggerFactory.getLogger(FreeMarkerNotifyDrugStatusServiceImpl.class);
     
    //อ้างถึง configuration file ใน /WEB-INF/applicationContext-freemarker.xml 
    @Autowired
    private FreeMarkerConfigurationFactoryBean fMConf;

    @Override
    public String loadMailTemplate(DrugStatusMailTemplate mail) throws TemplateException, IOException {
        //ดึง html template drugStatusMailTemplate.ftl มาใช้งาน
        Template template = fMConf.getObject().getTemplate("drugStatusMailTemplate.ftl");
        StringWriter sw = new StringWriter();
        Map map = new HashMap();

        //แทนค่าตัวแปรใน template นั้น  ห้ามเป็น null ****
        map.put("notifier", mail.getDeficient().getNotifier());
        map.put("date", dateFormatter.format(new Date()));
        map.put("genericName", mail.getDeficient().getGenericName());
        map.put("tradeName", mail.getDeficient().getTradeName());
        map.put("strength", mail.getDeficient().getStrength());
        map.put("style", mail.getDeficient().getStyle());
        map.put("scale", mail.getDeficient().getScale());
        map.put("distributorCompany", mail.getDeficient().getDistributorCompany());
        map.put("registerNumber", mail.getDeficient().getRegistrationNumber());
        map.put("deficientCause", mail.getDeficient().getDeficientCause());
        map.put("notifyDate", dateFormatter.format(mail.getDeficient().getNotifyDate()));
        map.put("status", mail.getDeficient().getStatus().getDescription());

        template.process(map, sw);
        return sw.getBuffer().toString(); //return html string ที่ถูกแทนค่าแล้ว
    }
}
6. เรียกใช้ FreeMarkerNotifyDrugStatusService เมื่อต้องการส่ง email
package com.blogspot.na5cent.model.email;

import com.blogspot.na5cent.model.email.template.DrugStatusMailTemplate;
import freemarker.template.TemplateException;
import java.io.IOException;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import com.blogspot.na5cent.model.template.FreeMarkerNotifyDrugStatusService;

/**
 *
 * @author Redcrow
 */
@Component
public class DrugStatusEmail{
    
    //เรียกใช้งาน service email
    @Autowired
    private JavaMailSenderImpl mailSender;
    //เรียกใช้งาน service freemarker
    @Autowired
    private FreeMarkerNotifyDrugStatusService freeMarkerService;

    public void send(DrugStatusMailTemplate template) throws MessagingException, TemplateException, IOException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        //set email ปลายทาง
        helper.setTo(template.getEmail());
        //set หัวข้อ email
        helper.setSubject("รายงานสถานะ ระบบยากำพร้าและยาขาดแคลนอย่างบูรณาการ และระบบติดตามผล");
        
        //คืนค่ากลับมาเป็น html template 
        String body = freeMarkerService.loadMailTemplate(template);

        helper.setText(body, true);
        mailSender.send(message);//ส่ง email
    }
}

เมื่อส่งออกไปถึง Gmail ก็จะแสดงผลลัพธ์ดังรูปข้างบนครับ
...
...
...
DrugStatusMailTemplate template = new DrugStatusMailTemplate();
template.setEmail(mailList);
template.setTitle(title);
template.setNote(note);
template.setDeficient(selected);

DrugStatusEmail email = JSFSpringUtils.getBean(DrugStatusEmail.class);
boolean success = false;
try {
    email.send(template);
    success = true;
} catch (MessagingException | TemplateException | IOException ex) {
    LOG.warn(null, ex);
    success = false;
} finally {
    if (success) {
        Notifications.message(Notifications.INFO, "การส่ง email แจ้งสถานะ", "สำเร็จ");
        reset();
    } else {
        Notifications.message(Notifications.WARN, "การส่ง email แจ้งสถานะ", "ล้มเหลว");
    }
}
...
...
...


ไม่มีความคิดเห็น:

แสดงความคิดเห็น