发送邮件(Spring+Velocity)


最近有需实现邮件发送的功能,为了让邮件界面和业务数据分离,故采用Velocity模板引擎。需引入velocity的时候,在Maven配置文件中添加如下依赖:

<dependency>     <groupId>velocity</groupId>     <artifactId>velocity</artifactId>     <version>1.5</version> </dependency> <dependency>     <groupId>velocity-tools</groupId>     <artifactId>velocity-tools</artifactId>     <version>2.0-beta1</version> </dependency>

接着在Spring的配置文件中定义添加如下配置:

<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">     <property name="velocityProperties">         <props>             <prop key="resource.loader">file</prop>             <prop key="file.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>             <prop key="file.resource.loader.cache">false</prop>             <prop key="file.resource.loader.modificationCheckInterval">3</prop>             <prop key="input.encoding">UTF-8</prop>             <prop key="output.encoding">UTF-8</prop>         </props>     </property> </bean>  <bean id="javaMailSender"  class="org.springframework.mail.javamail.JavaMailSenderImpl">           <property name="host">               <value>${mail.host}</value>           </property>         <property name="port">             <value>${mail.port}</value>         </property>           <property name="javaMailProperties">               <props>                   <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>                   <prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop>               </props>           </property>           <property name="username">               <value>${mail.username}</value>           </property>           <property name="password">               <value>${mail.password}</value>           </property>   </bean>

需要在spring配置文件中加入如下配置:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">     <property name="location">         <value>classpath:config.properties</value>     </property> </bean>

并在src/main/resources目录下的config.properties文件中加入配置:

mail.host=mail.ylmob.com mail.port=25 mail.username=pay@ylmob.com mail.password=************* mail.smtp.auth=true mail.smtp.timeout=25000

有时习惯查看源码,但是Maven私服上面并没有源码,只能下载velocity-1.5.zip,并在解压,按照图中的指示操作就可以附加源码:

发送邮件(Spring+Velocity)

附加源码之后,选中你想看源码的类,按下F3键,就进入源码中。

org.apache.velocity.runtime.RuntimeConstants中定义了key值信息,部门key值如下:

    /**      * Key used to retrieve the names of the resource loaders to be used. In a properties file they may appear as the following:      *      * <p>resource.loader = classpath</p>      */     String RESOURCE_LOADER = "resource.loader";      /** The public handle for setting a path in the FileResourceLoader. */     String FILE_RESOURCE_LOADER_PATH = "file.resource.loader.path";      /** The public handle for turning the caching on in the FileResourceLoader. */     String FILE_RESOURCE_LOADER_CACHE = "file.resource.loader.cache";

    定义模板的输入和输出模板编码的配置是:

<prop key="input.encoding">UTF-8</prop> <prop key="output.encoding">UTF-8</prop>

    配置检查模板更改时间间隔:

<prop key="file.resource.loader.modificationCheckInterval">3</prop>

    配置是否启用模板缓存:

<prop key="file.resource.loader.cache">false</prop>

    配置模板路径:   

<prop key="file.resource.loader.path">${path}</prop>

   配置模板加载器类型:

<prop key="resource.loader">file</prop>

    配置加载器类:

<prop key="file.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>

    定义一个用于发送邮件接口IMailSenderService,具体代码如下:

package com.astep.yunpay.service;  import java.util.Map;  /**  * @Author DJM  * @CreateDate:2015-05-06 13:57:20  * @UpdateDate:2015-05-06 13:57:20  * @Deprecated:Send e-mail  */ public interface IMailSenderService {      public void sendMailWithVelocityTemplate(String mailSubject, String templateLocation, Map<String, Object> velocityContext);          }

再写一个实现IMailSenderService接口的实现类MailSenderService,具体代码如下:

package com.astep.yunpay.service.impl;  import java.util.Map;  import javax.annotation.Resource; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage;  import org.apache.velocity.app.VelocityEngine; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; import org.springframework.ui.velocity.VelocityEngineUtils;  import com.astep.yunpay.service.IMailSenderService; import com.astep.yunpay.service.ISsPropertyService;  /**  * @Author DJM  * @CreateDate:2015-05-06 13:57:20  * @UpdateDate:2015-05-06 13:57:20  * @Deprecated:Send e-mail  */ @Service("mailSenderService") public class MailSenderService implements IMailSenderService {          @Autowired     private ISsPropertyService    ssPropertyService;          @Resource     private JavaMailSender javaMailSender;          @Resource     private VelocityEngine velocityEngine;          @Override     public void sendMailWithVelocityTemplate(String mailSubject, String templateLocation, Map<String, Object> velocityContext){                  MimeMessage mailMessage = javaMailSender.createMimeMessage();                     MimeMessageHelper messageHelper;         try {             messageHelper = new MimeMessageHelper(mailMessage, true, "utf-8");             // 设置邮件接收人             if(ssPropertyService.getByKey("system.mail.to")==null||ssPropertyService.getByKey("system.mail.to").equals("")){                 return;             }             messageHelper.setTo(ssPropertyService.getByKey("system.mail.to").trim().split(";"));             // 设置邮件发送人             messageHelper.setFrom(ssPropertyService.getByKey("mail.from").trim());             messageHelper.setSubject(mailSubject);             String mailText = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, templateLocation, "utf-8", velocityContext);             messageHelper.setText(mailText, true);             javaMailSender.send(mailMessage);         } catch (MessagingException e) {             e.printStackTrace();         }              }  }

    需要在代码中注意代码中,

messageHelper.setFrom(ssPropertyService.getByKey("mail.from").trim());

   可以自由配置为shabi@shabi.com、laopozhaoxue@laopo.com、meinv@img.com等,只会影响下图中红色框框中的显示部分,邮件实际上是由pay@ylmob.com发送的。假如我们配置duoshengwa@laopo.com,红色框框中显示将是duoshengwa,就相当于给pay@ylmob.com穿上一层皮,即使发垃圾邮件,一般也不会被别人知道。随便说句,“mail.from”和”system.mail.to”系统后台配置的属性,存放于数据库中的数据。

    发送邮件(Spring+Velocity)

    这次需求是每天早晨八点发送排名前十位的内容提供商的排名以及金额统计详细和应用排名以及金额统计详细邮件。有了MailSenderService类,只需要传入邮件主题、模板文件的路径和一个Map<String, Object>类型的对象model,源码中的注释对model给出了说明

@param model the Map that contains model names as keys and model objects as values
package com.astep.yunpay.task;  /**  * @Author DJM  */ public interface ITopTenCpAndAppDailyCensusSendEmailTaskService {      public void email(); }

实现该接口的类为:

package com.astep.yunpay.task.impl;  import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map;  import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service;  import com.astep.common.util.CalculateUtil; import com.astep.common.util.DateUtil; import com.astep.common.util.DigitUtil; import com.astep.yunpay.service.IMailSenderService; import com.astep.yunpay.service.ISsPropertyService; import com.astep.yunpay.service.comprehensive.IComprehensiveService; import com.astep.yunpay.task.ITopTenCpAndAppDailyCensusSendEmailTaskService;  /**  * @Author DJM  * @Date:2015年03月18日  * @Time:上午11:10:25  * @Description:邮件发送每日TOP10的CP和应用统计报表  */ @Service public class TopTenCpAndAppDailyCensusSendEmailTaskService implements ITopTenCpAndAppDailyCensusSendEmailTaskService {          @Autowired     ISsPropertyService     ssPropertyService;          @Autowired     IComprehensiveService    comprehensiveService;          @Autowired     private IMailSenderService mailSenderService;          private static boolean    isRunning    = false;          @Scheduled(cron = "0 0 8 * * *") //开发调试所采用的调度时间     //@Scheduled(cron = "0/30 * * * * *") //开发调试所采用的调度时间     public void email() {         if (isRunning) {             return;         }         isRunning = true;                  Map<String, Object> velocityCpParameter = new HashMap<String, Object>();         velocityCpParameter = enchaseParameter(velocityCpParameter, false);         mailSenderService.sendMailWithVelocityTemplate("每日TOP10的CP统计报表", "velocity/VelocityTemplateOfTopTenCpDailyCensusMail.vm", velocityCpParameter);                  Map<String, Object> velocityAppParameter = new HashMap<String, Object>();         velocityAppParameter = enchaseParameter(velocityAppParameter, true);         mailSenderService.sendMailWithVelocityTemplate("每日TOP10的APP统计报表", "velocity/VelocityTemplateOfTopTenAppDailyCensusMail.vm", velocityAppParameter);                  isRunning = false;     }          public Map<String, Object> enchaseParameter(Map<String, Object> velocityParameter, boolean isGourpApp){         velocityParameter.put("mailPlatformFlag", ssPropertyService.getByKey("mail.platform.flag") == null ? "": ssPropertyService.getByKey("mail.platform.flag"));         velocityParameter.put("date", DateUtil.formatDate(DateUtil.addDays(new Date(), -1)));         velocityParameter.put("comprehensiveList", getComprehensiveList(isGourpApp));         velocityParameter.put("summationMap", getSummationMap(getComprehensiveList(isGourpApp)));         return velocityParameter;     }          public List<Map<String, Object>> getComprehensiveList(boolean isGourpApp){         Map<String, Object> condition = new HashMap<String, Object>();         Date addTimeStart = DateUtil.getDayBegin(DateUtil.addDays(new Date(), -1));         Date addTimeEnd = DateUtil.getDayEnd(addTimeStart);         if(!isGourpApp){             condition.put("screening", true);         }         condition.put("screeningTop", true);         condition.put("addTimeStart", addTimeStart);         condition.put("addTimeEnd", addTimeEnd);         List<Map<String, Object>> comprehensiveList = new ArrayList<Map<String, Object>>();          comprehensiveList =    comprehensiveService.census(condition, "cpDailyCensus");         return comprehensiveList;     }          public Map<String, Object> getSummationMap(List<Map<String, Object>> comprehensiveList){         Map<String, Object> summationMap = new HashMap<String, Object>();         int coSuccessSummation=0, poSuccessSummation=0, moSuccessSummation=0, mrSuccessSummation=0;         if(comprehensiveList!=null && comprehensiveList.size()>0){             for(Map<String, Object> record: comprehensiveList){                 coSuccessSummation+=DigitUtil.obtainWithoutDecimal(record.get("coS"));                 poSuccessSummation+=DigitUtil.obtainWithoutDecimal(record.get("poS"));                 moSuccessSummation+=DigitUtil.obtainWithoutDecimal(record.get("moS"));                 mrSuccessSummation+=DigitUtil.obtainWithoutDecimal(record.get("mrS"));             }         }         summationMap.put("coSuccessSummation", coSuccessSummation);         summationMap.put("poSuccessSummation", poSuccessSummation);         summationMap.put("moSuccessSummation", moSuccessSummation);         summationMap.put("mrSuccessSummation", mrSuccessSummation);         summationMap.put("summationPercent", CalculateUtil.quotient(mrSuccessSummation, poSuccessSummation));                  return summationMap;     }          public String toYuan(Object object){         int number = DigitUtil.obtainWithoutDecimal(object);         Integer result = number/100;         return result.toString();     } }

velocity模板文件为:

##author: DJM <!DOCTYPE html> <html>   <head>     <meta charset="utf-8">     <meta http-equiv="X-UA-Compatible" content="IE=edge">     <meta name="viewport" content="width=device-width, initial-scale=1">     <title>每日TOP10的APP统计报表</title>     <style>         #include("velocity/css/bootstrap.css")     </style>   </head>   <body>       <h3><span class="label label-success">${mailPlatformFlag}-每日TOP10的APP统计报表(${date})</span></h3>       <div class="panel panel-danger">           <div></div>           <div>             <table class="table table-bordered table-hover">                 <tr>                     <td title="时间">时间</td>                     <td title="应用名称">应用名称</td>                     <td title="所属CP">所属CP</td>                     <td title="确认订单金额">确认订单金额</td>                     <td title="PO成功金额">PO成功金额</td>                     <td title="MO成功金额">MO成功金额</td>                     <td title="MR成功金额">MR成功金额</td>                     <td title="计费转化率">计费转化率</td>                 </tr>             #foreach($comprehensive in ${comprehensiveList})                 <tr>                     <td>${comprehensive.censusDay}</td>                     <td title="${comprehensive.appId}">${comprehensive.appName}</td>                     <td>${comprehensive.shortName}</td>                     #set($coS=${comprehensive.coS}/100)                     <td>${coS}元</td>                     #set($poS=${comprehensive.poS}/100)                     <td>${poS}元</td>                     #set($moS=${comprehensive.moS}/100)                     <td>${moS}元</td>                     #set($mrS=${comprehensive.mrS}/100)                     <td>${mrS}元</td>                     #if(${comprehensive.mrS} <= 0 || ${comprehensive.poS} <= 0)                         <td>0%</td>                     #else                         #set($comprehensivePercent=${comprehensive.mrS}*10000/${comprehensive.poS}/100)                         <td>${comprehensivePercent}%</td>                     #end                 </tr>             #end                 <tr>                     <td>合计</td>                     <td>-</td>                     <td>-</td>                     #set($coSuccessSummation=${summationMap.coSuccessSummation}/100)                     <td>${coSuccessSummation}元</td>                     #set($poSuccessSummation=${summationMap.poSuccessSummation}/100)                     <td>${poSuccessSummation}元</td>                     #set($moSuccessSummation=${summationMap.moSuccessSummation}/100)                     <td>${moSuccessSummation}元</td>                     #set($mrSuccessSummation=${summationMap.mrSuccessSummation}/100)                     <td>${mrSuccessSummation}元</td>                     <td>${summationMap.summationPercent}%</td>                 </tr>             </table>           </div>       </div>       <h3>           <span class="glyphicon glyphicon-link" aria-hidden="true"></span>           <span class="label label-info"><a href="http://p.918ja.com:9020/login.do">进入移动支付统一合作平台</a></span>       </h3>   </body> </html>

    使用#include命令引入bootstrap.css文件:

<style>             #include("velocity/css/bootstrap.css") </style>

  发送的邮件内容为:

发送邮件(Spring+Velocity)