1. 程式人生 > >java郵件傳送和簡訊傳送(一)

java郵件傳送和簡訊傳送(一)

最近剛完成一個任務-付款提醒郵件的傳送,對於java郵件的傳送有了更深刻的認識,的確java提供的郵件傳送機制的確讓郵件傳送這個問題變得靈活而又簡單。並且由於專案組其他人負責了簡訊的傳送,巧的是這個郵件傳送的藉口與簡訊傳送的藉口都被封裝到了訊息傳送的藉口,我也順便學習了一下簡訊傳送的原理,呵呵,算是一箭雙鵰吧。

    那先來說說郵件傳送。按照按介面程式設計的習慣,當然先要定義一個郵件傳送的介面,再實現其介面,完成郵件傳送Service層的程式碼。這個順序我想大家沒什麼反對意見吧。

    首先咱們先定義一個訊息傳送介面,它是郵件傳送與簡訊傳送的上層介面。

[java] view plaincopyprint?
  1. /**  
  2.  * 功能:  系統訊息傳送服務 <p>  
  3.  * 用法: 
  4.  * @version 1.0 
  5.  */
  6. publicinterface MessageService {  
  7. /** 
  8.  * 根據訊息模板表中的訊息編號取得訊息模板,填充,傳送 
  9.  *  
  10.  * @param bmtCode  訊息模板表中的訊息編號
     
  11.  * @param params 填充模板內容的引數 
  12.  * @param to  訊息的接收人 
  13.  * @throws CheckException 模板不存在,或是傳送訊息出現異常 
  14.  */
  15. publicvoid sendMessage(String bmtCode,Map params, String... to) throws CheckException;  
  16. }  

    再來定義一下郵件傳送器介面,由於我這裡是通過velocity模板傳送郵件的,所以如下定義了介面:

[java] view plaincopyprint?
  1. /** 
  2.  * 郵件傳送器 
  3.  * @usage        
  4.  */
  5. publicinterface TempletEmailSender {  
  6. /** 
  7.      * @param from  發件人郵箱 
  8.      * @param to    收件人郵箱 
  9.      * @param subject   郵件主題 
  10.      * @param templet   模板 
  11.      * @param paramMap  模板引數資訊
     
  12.      * @throws CheckException 
  13.      */
  14. publicvoid sendEmailByTemplet(String from, String to, String subject,String templet, Map<String, Object> paramMap) throws CheckException;  
  15. /** 
  16.      * @param from  發件人郵箱 
  17.      * @param to    收件人郵箱(多個) 
  18.      * @param subject   郵件主題 
  19.      * @param templet   模板 
  20.      * @param paramMap  模板引數資訊 
  21.      * @throws CheckException 
  22.      */
  23. publicvoid sendEmailByTemplet(String from, String[] to, String subject,String templet, Map<String, Object> paramMap) throws CheckException;  
  24. /** 
  25.      * @param mail 郵件物件 
  26.      * @param templet 模板     
  27.      * @param paramMap  模板引數資訊 
  28.      * @throws CheckException 
  29.      */
  30. publicvoid sendEmailByTemplet(Mail mail,String templet, Map<String, Object> paramMap) throws CheckException;  
  31. }  

    接著實現郵件傳送的介面:

[java] view plaincopyprint?
  1. /** 
  2.  * 郵件傳送器預設實現 
  3.  */
  4. publicclass TempletEmailSenderImpl implements TempletEmailSender{  
  5. @Autowired
  6. @Qualifier("emailSenderImpl_commons")  
  7. private EmailSender emailSender;  
  8. @Override
  9. publicvoid sendEmailByTemplet(String from, String to,String subject, String templet, Map<String, Object> paramMap) throws CheckException {  
  10.         sendEmailByTemplet(from, new String[]{to}, subject, templet, paramMap);  
  11.     }  
  12. @Override
  13. publicvoid sendEmailByTemplet(String from, String[] to, String subject, String templet, Map<String, Object> paramMap) throws CheckException {  
  14. // 解析模板
  15.         String content ;  
  16. try {  
  17.             content = VelocityParserUtil.getInstance().parseVelocityTemplate(templet, paramMap);  
  18.         } catch (Throwable t) {  
  19. thrownew CheckException(t);  
  20.         }  
  21.         emailSender.sendEmail(from, to, subject, content);  
  22.     }  

    大家看到了上面的實現裡注入了EmailSender,它也是一個介面,它的實現裡注入了JavaMail提供的郵件傳送介面。定義了兩層是為了區分有模板的傳送和無模板的傳送。我們來看看它是什麼樣的:

[java] view plaincopyprint?
  1. /** 
  2.  * 郵件傳送器 
  3.  * @usage        
  4.  */
  5. publicinterface EmailSender {  
  6. /** 
  7.      * 傳送郵件 
  8.      * @param from 發件人 
  9.      * @param to 收件人 
  10.      * @param subject 郵件主題 
  11.      * @param mailBody  郵件內容 
  12.      * @throws CheckException 引數校驗失敗或傳送郵件失敗時,丟擲此異常 
  13.      */
  14. void sendEmail(String from, String to, String subject, String mailBody) throws CheckException;  
  15. /** 
  16.      * 傳送郵件 
  17.      * @param from 發件人 
  18.      * @param to 多個收件人 
  19.      * @param subject 郵件主題 
  20.      * @param mailBody  郵件內容 
  21.      * @throws CheckException 引數校驗失敗或傳送郵件失敗時,丟擲此異常 
  22.      */
  23. void sendEmail(String from, String[] to, String subject, String mailBody) throws CheckException;  
  24. /** 
  25.      * 傳送郵件 
  26.      * @param mail 郵件 
  27.      * @throws CheckException 引數校驗失敗或傳送郵件失敗時,丟擲此異常 
  28.      */
  29. void sendEmail(Mail mail) throws CheckException;  
  30. }  

    接著實現這個EmailSender介面:

[java] view plaincopyprint?
  1. **  
  2.  * JAVA MAIL實現  
  3.  */  
  4. publicclass EmailSenderImpl implements EmailSender,InitializingBean{  
  5. /** 
  6.      * Logger for this class 
  7.      */
  8. privatestaticfinal Logger logger = Logger.getLogger(EmailSenderImpl.class);  
  9. @Autowired
  10. private ConfigService configService;  
  11. private JavaMailSenderImpl sender; // 實際的傳送實現
  12. @Override
  13. publicvoid sendEmail(String from, String to, String subject, String mailBody) throws CheckException {  
  14.         sendEmail(from, new String[]{to}, subject, mailBody);  
  15.     }  
  16. @Override
  17. publicvoid sendEmail(String from, String[] to, String subject, String mailBody) throws CheckException {  
  18. // 構造MAIL物件
  19.         Mail mail = new Mail();  
  20.         mail.setFrom(from);  
  21.         mail.setTo(to);  
  22.         mail.setSubject(subject);  
  23.         mail.setContent(mailBody);  
  24.         sendEmail(mail);  
  25.     }  
  26. @Override
  27. publicvoid sendEmail(Mail mail) throws CheckException {  
  28. // 檢查必要引數
  29. if (mail == null ){  
  30. thrownew CheckException("mail can not be null.");  
  31.         }  
  32. if (ArrayUtils.isEmpty(mail.getTo())){  
  33. thrownew CheckException("收件人不能為空");  
  34.         }  
  35.         MimeMessageHelper helper = null;  
  36. try {  
  37.             helper = new MimeMessageHelper(sender.createMimeMessage(), true"UTF-8");  
  38. // 發件人
  39. if (mail.getFrom() != null) {  
  40. if (mail.getFromName() == null) {  
  41.                     helper.setFrom(mail.getFrom());  
  42.                 } else {  
  43.                     helper.setFrom(mail.getFrom(), mail.getFromName());  
  44.                 }  
  45.             }  
  46. // 收件人
  47.             helper.setTo(mail.getTo());  
  48. // 抄送人
  49. if (mail.getCc() != null) {  
  50.                 helper.setCc(mail.getCc());  
  51.             }  
  52. // 密送人
  53. if (mail.getBcc() != null) {  
  54.                 helper.setBcc(mail.getBcc());  
  55.             }  
  56. // 郵件主題
  57.             helper.setSubject(mail.getSubject());  
  58. // 郵件內容
  59.             helper.setText(mail.getContent(), mail.isHtmlFormat());  
  60. // 附件
  61. if (mail.getAttachments() != null) {  
  62. for ( MailAttachment attachment : mail.getAttachments()) {  
  63.                     helper.addAttachment(attachment.getFileName(),attachment.getFile());  
  64.                 }   
  65.             }  
  66. // 傳送時間
  67.             helper.setSentDate(new Date());  
  68.         } catch (UnsupportedEncodingException e) {  
  69.             logger.error("sendEmail(Mail)", e);  
  70. thrownew CheckException(e) ;  
  71.         } catch (MessagingException e) {  
  72.             logger.error("sendEmail(Mail)", e);  
  73. thrownew CheckException(e) ;  
  74.         }  
  75. // 傳送
  76. try {  
  77.             sender.send(helper.getMimeMessage());  
  78.         } catch (MailException e) {  
  79.             logger.error("sendEmail(Mail)", e);  
  80. thrownew CheckException(e) ;  
  81.         }  
  82.     }  
  83. @Override
  84. publicvoid afterPropertiesSet() throws Exception {  
  85.         sender = new JavaMailSenderImpl();  
  86. // configService讀出引數
  87.         Properties pros = new Properties();  
  88.         pros.setProperty("mail.smtp.user", configService.getConfig(BasePropertyID.MAIL_SMTP_USER_ID));  
  89.         pros.setProperty("mail.smtp.host", configService.getConfig(BasePropertyID.MAIL_SMTP_HOST_ID));  
  90.         pros.setProperty("mail.smtp.port", configService.getConfig(BasePropertyID.MAIL_SMTP_PORT_ID));  
  91.         pros.setProperty("mail.smtp.connectiontimeout", configService.getConfig(BasePropertyID.MAIL_SMTP_CONNECTIONTIMEOUT_ID));  
  92.         pros.setProperty("mail.smtp.timeout", configService.getConfig(BasePropertyID.MAIL_SMTP_TIMEOUT_ID));  
  93.         pros.setProperty("mail.smtp.from", configService.getConfig(BasePropertyID.MAIL_SMTP_FROM_ID));  
  94.         pros.setProperty("mail.smtp.auth", configService.getConfig(BasePropertyID.MAIL_SMTP_AUTH_ID));  
  95.         sender.setJavaMailProperties(pros);  
  96.         sender.setPassword(configService.getConfig(BasePropertyID.MAIL_SMTP_PASSWORD_ID));  
  97.     }  
  98. public ConfigService getConfigService() {  
  99. return configService;  
  100.     }  
  101. publicvoid setConfigService(ConfigService configService) {  
  102. this.configService = configService;  
  103.     }  

    O(∩_∩)O~大家又注意到了 這個介面實現裡又注入了一個介面ConfigService 它是去讀取郵件傳送的相關配置資訊,如上所示:

     // configService讀出引數
  Properties pros = new Properties();

  pros.setProperty("mail.smtp.user", configService.getConfig(BasePropertyID.MAIL_SMTP_USER_ID));
  pros.setProperty("mail.smtp.host", configService.getConfig(BasePropertyID.MAIL_SMTP_HOST_ID));
  pros.setProperty("mail.smtp.port", configService.getConfig(BasePropertyID.MAIL_SMTP_PORT_ID));
  pros.setProperty("mail.smtp.connectiontimeout", configService.getConfig(BasePropertyID.MAIL_SMTP_CONNECTIONTIMEOUT_ID));
  pros.setProperty("mail.smtp.timeout", configService.getConfig(BasePropertyID.MAIL_SMTP_TIMEOUT_ID));
  pros.setProperty("mail.smtp.from", configService.getConfig(BasePropertyID.MAIL_SMTP_FROM_ID));
  pros.setProperty("mail.smtp.auth", configService.getConfig(BasePropertyID.MAIL_SMTP_AUTH_ID));
    
  sender.setJavaMailProperties(pros);
  sender.setPassword(configService.getConfig(BasePropertyID.MAIL_SMTP_PASSWORD_ID));

  而且由於涉及到引數的資料成員較多,就將他們一起封裝到了Mail類:

[java] view plaincopyprint?
  1. /**  
  2.  * 功能: 封裝郵件物件  <p>  
  3.  * 用法: 
  4.  * @version 1.0 
  5.  */
  6. publicclass Mail {  
  7. /** 
  8.      * 發件人 
  9.      */
  10. private String from;  
  11. /** 
  12.      * 發件人(顯示) 
  13.      */
  14. private String fromName;  
  15. /** 
  16.      * 收件人 
  17.      */
  18. private String[] to;  
  19. /** 
  20.      * 抄送 
  21.      */
  22. private String[] cc;  
  23. /** 
  24.      * 祕密抄送 
  25.      */
  26. private String[] bcc;  
  27. /** 
  28.      * 郵件主題 
  29.      */
  30. private String subject;  
  31. /** 
  32.      * 郵件內容 
  33.      */
  34. private String content;  
  35. /** 
  36.      * 附件 
  37.      */
  38. private MailAttachment[] attachments;  
  39. /** 
  40.      * 是否以HTML格式傳送 
  41.      */
  42. boolean isHtmlFormat = true;  
  43. //getter與setter方法省略
  44. }  

   好了 整個介面都實現了,其實排除了你傳送郵件提供給郵件傳送介面的幾個引數,剩下的也就是呼叫java提供的郵件傳送的API和一些郵件傳送必備的配置資訊,必不是很難懂吧。大家肯定注意到了郵件傳送介面的velocity模板解析方法:

    content = VelocityParserUtil.getInstance().parseVelocityTemplate(templet, paramMap);

    它具體的實現如下所示:

[java] view plaincopyprint?
  1. /** 
  2.  * 功能:解析velocity模板 
  3.  * <p> 
  4.  * 用法: 
  5.  *  
  6.  * @version 1.0 
  7.  */
  8. publicclass VelocityParserUtil {  
  9. /** 
  10.      * Logger for this class 
  11.      */
  12. privatestaticfinal Logger logger = Logger.getLogger(VelocityParserUtil.class);  
  13. privatestatic VelocityParserUtil instance = new VelocityParserUtil();  
  14. private VelocityEngine engine = null;  
  15. private VelocityParserUtil() {  
  16. // init engine
  17.         engine = new VelocityEngine();  
  18. try {  
  19.             engine.init();  
  20.         } catch (Exception e) {  
  21.             logger.warn("VelocityParserUtil() - exception ignored", e); //$NON-NLS-1$
  22.         }  
  23.     }  
  24. /** 
  25.      * 返回VelocityParserUtil例項 
  26.      * @return 
  27.      */
  28. publicstatic VelocityParserUtil getInstance() {  
  29. return instance;  
  30.     }  
  31. /** 
  32.      * 解析velocity模板 
  33.      * @param vtl 
  34.      * @param model 
  35.      * @return String  
  36.      * @throws ParseErrorException 
  37.      * @throws MethodInvocationException 
  38.      * @throws ResourceNotFoundException 
  39.      * @throws IOException 
  40.      */
  41. public String parseVelocityTemplate(String vtl, Map model)  
  42. throws ParseErrorException, MethodInvocationException,  
  43.             ResourceNotFoundException, IOException {  
  44. if (logger.isDebugEnabled()) {  
  45.             logger.debug("parseVelocityTemplate(String, Map) - start"); //$NON-NLS-1$
  46.         }  
  47.         VelocityContext velocityContext = new VelocityContext(model);  
  48.         StringWriter result = new StringWriter();  
  49.         engine.evaluate(velocityContext, result, null, vtl);  
  50.         String returnString = result.toString();  
  51. if (logger.isDebugEnabled()) {  
  52.             logger.debug("parseVelocityTemplate(String, Map) - end"); //$NON-NLS-1$
  53.         }  
  54. return returnString;  
  55.     }  
  56. }  

   我們會在其他的Service中去呼叫郵件傳送的介面,只需要在業務層裡構造好郵件傳送的介面所需引數,我們的郵件就可以傳送出去了。還有一點請大家注意,我這裡主要強調的是運用velocity模板傳送郵件,介面所需要的引數templat大家不要誤解為velocity模板的檔名,它其實velocity檔案的檔案流,是一個已經被讀入的字串。大家可以參考一下測試用例,大致可以明白是怎麼回事了。

[java] view plaincopyprint?
  1. publicclass TempletEmailSenderTest extends BaseTestBaseForJUnit4{  
  2. @Autowired
  3. @Qualifier("templetEmailSenderImpl_commons")  
  4. private TempletEmailSender sender;  
  5. //    @Test
  6. publicvoid sendEmailByTemplet() throws CheckException{  
  7.   String templet = "$!{user}提醒您付款$!{amount}元";  
  8.   Map paramMap = new HashMap();  
  9.   paramMap.put("user""吳欣");  
  10.   paramMap.put("amount""99.9");  
  11.   sender.sendEmailByTemplet("[email protected]""[email protected]""模板郵件", templet, paramMap);  
  12.  }  

    整個郵件的傳送大家是否明瞭了呢,呵呵!

    後面我們會將這個介面向上抽象,為了實現我們簡訊傳送的實現,下一篇敬請期待哦