spring发送email二
发送邮件时,比如激活邮件、订单邮件等等往往都需要动态数据的填入,比如客户名、订单号,或者密码。类似于web设计:
邮件的模板:是一个可能具有html格式或类似的模板,是View的角色;
邮件的数据:是Model的角色,填入模板,形成最后的邮件内容。
一个与用户交互加多的系统,邮件的种类是“啥都有的”:各种提醒,各种状态告知,。。。
所以基于配置做法相对比较能够统一模式以及省时省力。
我的做法是使用Velocity定义邮件,通过提供良好设计的API,和配置规定实现。最后使用代码大致如下:
?
?/**
? * 激活服务加密解密功能支持
? */
?private Encryptor encryptor;
?
?/**
? * 激活邮件功能支持
? */
?private VelocityMailSupport velocityMailSupport;
????? public void xxxx(User user) {?
????????????? Map model = new HashMap();
????????????? model.put("user", user);
????????????? model.put("token", encryptor.encode(user));
???????? ?????velocityMailSupport.sendMime(user.getRealname(),? user.getEmail(), ?model);
?}
velocityMailSupport是一个包含了模板和邮件标题信息的JavaMailSender实现类,sendMime是提供的简易方法,发送具有html样式的代码。
同时,velocityMailSupport本身使用的内嵌的JavaMailSender是自己实现的PooledMailSender(异步邮件发送)。经过实战使用效果良好。
附件是核心代码(不是上面的示例代码)和配置:
VelocityMailSupport.java -- 提供给程序使用,通过Spring配置注入到被需要的类中,利用本类可方便发送由Velocity模板生成的邮件内容。客户程序可以组合或继承本类,使具有发送邮件功能。
PoolMailSender.java --对Springframework MailSender和JavaMailSender的装饰, 实现装饰器模式。PooledMailSender将要发送邮件进行排队,按FIFO方式发送得到的邮件消息。
applicationContext-mail-template.xml -- 配置所有的邮件模板的VelocityMailSupport实例,比如激活,找回密码等具体velocity模板和邮件subject
applicationContext-mail.xml -- 基础配置applicationContext-mail-template.xml依赖于它
mail_template.properties -- 配置模板位置和subject文本
VelocityMailSupport.java
Java代码
- public?class?VelocityMailSupport?implements?MailSender,?JavaMailSender{????????//?-----------------------------------------????????????private?Properties?mailHeaders?=?new?Properties();????????/**??????*?邮件发送者,包括发送者姓名和地址,用于设置在邮件的from栏目中??????*/??????private?String?from;????????/**??????*?邮件主题??????*/??????private?String?subject;????????/**??????*?邮件内容模板地址/名称??????*/??????private?String?templateName;????????/**??????*?velocity引擎??????*/??????private?VelocityEngine?velocityEngine;????????/**??????*?mail发送器??????*/??????private?MailSender?mailSender;????????//?-----------------------------------------????????????/**??????*?日志??????*/??????protected?static?final?Log?log?=?LogFactory??????????????.getLog(VelocityMailSupport.class);????????????//?-----------------------------------------????????/**??????*?使用提供的数据,套入velocity模板,生成最后文本信息。??????*???????*?大部分情况下,这个信息应该就是邮件的内容。??????*/??????public?String?renderText(Map?model)?throws?VelocityException?{??????????return?VelocityEngineUtils.mergeTemplateIntoString(getVelocityEngine(),??????????????????getTemplateName(),?model);??????}??????????????//?-----------------------------------------??????//省略getter和setter??????/**??????*???????*?发送Mime邮件简易方法。??????*???????*?以Mime的方式发送邮件,这主要是为能够支持发送html或类似功能(非简单文本)的邮件??????*???????*?@param?nameOfTo?邮件接收收人姓名?或?昵称??????*?@param?emailOfTo?邮件接收人邮件地址??????*?@param?model?邮件velocity模板中变量的值??????*?@throws?MailException??????*/??????public?void?sendMime(String?nameOfTo,?String?emailOfTo,?Map<String,?Object>?model)?throws?MailException?{??????????sendMime(nameOfTo?+?"<"?+?emailOfTo?+?">",?model);??????}??????????????/**??????*??发送Mime邮件简易方法。??????*???????*?以Mime的方式发送邮件,这主要是为能够支持发送html或类似功能(非简单文本)的邮件??????*???????*?@param?to?邮件接收人邮件地址以及可能的收件人姓名或昵称??????*?@param?model?邮件velocity模板中变量的值??????*/??????public?void?sendMime(String?to,?Map<String,?Object>?model)?throws?MailException?{??????????sendMime(mergeSimpleMessage(to,?model));??????}??????????????/**??????*?发送Mime邮件简易方法。??????*???????*?以Mime的方式发送SimpleMailMessage,这主要是为能够支持发送html或类似功能(非简单文本)的邮件??????*???????*?@param?simpleMessage??????*?@throws?MailException??????*/??????public?void?sendMime(SimpleMailMessage?simpleMessage)?throws?MailException?{??????????send(toMimeMessage(simpleMessage));??????}??????????????//----------------------------------------------????????????public?SimpleMailMessage?mergeSimpleMessage(String?to,?Map<String,?Object>?model)?{??????????//render?text?of?mail?from?velocity?template?with?the?data??????????String?text?=?null;??????????try?{??????????????text?=?renderText(model);??????????}?catch?(VelocityException?e)?{??????????????log.error(e);??????????????e.printStackTrace();??????????}????????????????????//mail?message?setting??????????SimpleMailMessage?message?=?new?SimpleMailMessage();??????????message.setSubject(getSubject());??????????message.setFrom(getFrom());??????????message.setTo(to);??????????message.setText(text);??????????return?message;??????}????????????/**??????*???????*?@param?simpleMailMessage??????*?@return??????*/??????public?MimeMessage?toMimeMessage(SimpleMailMessage?simpleMailMessage)?{??????????MimeMessage?mimeMessage?=?createMimeMessage();????????????MimeMailMessage?mmm?=?new?MimeMailMessage(mimeMessage);??????????simpleMailMessage.copyTo(mmm);??????????return?mmm.getMimeMessage();????????????????????}????????//----------------------------------------------??????//?MailSender接口实现?-?代理到配置的实际mailSender?--仅发布一个代理方法,其它省略??????public?void?send(SimpleMailMessage?simpleMessage)?throws?MailException?{??????????getMailSender().send(simpleMessage);??????}??????????//----------------------------------------------??????????????protected?void?injectMailHeader(MimeMessage?mm){??????????for?(Object?name?:?mailHeaders.keySet())?{??????????????try?{??????????????????mm.setHeader((String)name,?mailHeaders.getProperty((String)name));??????????????}?catch?(MessagingException?e)?{??????????????????e.printStackTrace();??????????????}??????????}????????????????}????}//end?
Java代码
- public?class?PooledMailSender?implements?MailSender,?JavaMailSender,??????????Runnable?{????????//?-------------------------------------????????/**??????*?实际发送邮件的邮件发送器,可以是MailSender,或JavaMailSender??????*/??????private?MailSender?mailSender;????????????//?-------------------------------------????????????/**??????*?日志??????*/??????protected?static?final?Log?log?=?LogFactory??????????????.getLog(PooledMailSender.class);??????????????/**??????*?邮件排队点号、发送线程,??????*/??????private?Thread?thread;????????/**??????*?邮件排队队列??????*/??????private?Queue<Object>?queue?=?new?LinkedBlockingQueue<Object>();????????????/**??????*?锁,仅此而已??????*????????*?@see?#run()??????*?@see?#add(Object)??????*/??????private?Object?mutex?=?new?Object();????????//?-------------------------------------????????/**??????*?构造本类对象,同时启动侦听邮件的到达。??????*???????*?如果要阻止侦听和发送,应该调用close方法,在Spring的Context中"最好"配置destroy-method="close",不过这不是必须的。??????*???????*/???????public?PooledMailSender()?{??????????thread?=?new?Thread(this);??????????thread.setDaemon(true);??????????thread.start();??????}????????//?-------------------------------------????????????/**??????*?邮件发送循环,它被作为thread?runnable的run实现。??????*???????*?@see?#add(Object)??????*???????*/??????public?void?run()?{??????????while?(!isClose())?{??????????????if?(!isEmpty())?{??????????????????Object?object?=?poll();??????????????????try?{??????????????????????//执行实际发送??????????????????????doSend(object);??????????????????}?catch?(Exception?ex)?{??????????????????????log.error(ex);??????????????????????ex.printStackTrace();??????????????????}??????????????}??????????????//等~直到add方法的通知!??????????????synchronized?(mutex)?{??????????????????try?{??????????????????????mutex.wait();??????????????????}?catch?(InterruptedException?e)?{??????????????????}??????????????}??????????}??????}????????//?-------------------------------------????????public?MailSender?getMailSender()?{??????????return?mailSender;??????}????????/**??????*?设置实际的邮件发送器??????*???????*?@param?mailSender??????*/??????public?void?setMailSender(MailSender?mailSender)?{??????????this.mailSender?=?mailSender;??????}??????????//?-------------------------------------????????/**??????*?关闭PooledMailSender!??????*???????*?关闭的PooledMailSender不可再接收和发送邮件??????*/??????public?void?close()?{??????????queue.clear();??????????queue?=?null;??????}????????/**??????*?已经关闭???????*???????*?关闭的PooledMailSender不可再接收和发送邮件??????*???????*?@return??????*/??????public?boolean?isClose()?{??????????return?queue?==?null;??????}????????//?-------------------------------------??????//?邮件排队机操作方法代理????????protected?boolean?isEmpty()?{??????????return?queue?!=?null?&&?queue.isEmpty();??????}????????????/**??????*?邮件加入排队机??????*???????*?@param?obj??????*?@see?#run()??????*/??????protected?void?add(Object?obj)?{??????????Assert.notNull(queue);??????????queue.add(obj);??????????//我来了!??????????synchronized?(mutex)?{??????????????mutex.notify();??????????}??????}????????protected?Object?poll()?{??????????Assert.notNull(queue);??????????return?queue.poll();??????}????????protected?Object?peek()?{??????????Assert.notNull(queue);??????????return?queue.peek();??????}????????????//?-------------------------------------??????//?MailSender接口实现-将邮件放入排队机????????????public?void?send(SimpleMailMessage?simpleMessage)?throws?MailException?{??????????add(simpleMessage);??????}????????public?void?send(SimpleMailMessage[]?simpleMessages)?throws?MailException?{??????????for?(SimpleMailMessage?message?:?simpleMessages)?{??????????????add(message);??????????}??????}??????????????????//?-------------------------------------??????//?JavaMailSender接口实现-将邮件放入排队机????????????public?void?send(MimeMessage?mimeMessage)?throws?MailException?{??????????add(mimeMessage);??????}????????public?void?send(MimeMessage[]?mimeMessages)?throws?MailException?{??????????for?(MimeMessage?message?:?mimeMessages)?{??????????????add(message);??????????}??????}????????public?void?send(MimeMessagePreparator?mimeMessagePreparator)??????????????throws?MailException?{??????????add(mimeMessagePreparator);??????}????????public?void?send(MimeMessagePreparator[]?mimeMessagePreparators)??????????????throws?MailException?{??????????for?(MimeMessagePreparator?preparator?:?mimeMessagePreparators)?{??????????????add(preparator);??????????}??????}????????public?MimeMessage?createMimeMessage()?{??????????return?((JavaMailSender)?mailSender).createMimeMessage();??????}????????public?MimeMessage?createMimeMessage(InputStream?contentStream)??????????????throws?MailException?{??????????return?((JavaMailSender)?mailSender).createMimeMessage(contentStream);??????}????????//?-------------------------------------??????//?实际发送代理方法????????????public?void?doSend(Object?object)?{??????????if?(object?instanceof?SimpleMailMessage)?{??????????????doSend((SimpleMailMessage)?object);??????????}?else?if?(object?instanceof?MimeMessage)?{??????????????doSend((MimeMessage)?object);??????????}?else?if?(object?instanceof?MimeMessagePreparator)?{??????????????doSend((MimeMessagePreparator)?object);??????????}??????}????????public?void?doSend(SimpleMailMessage?simpleMessage)?throws?MailException?{??????????mailSender.send(simpleMessage);??????}????????????public?void?doSend(MimeMessage?mimeMessage)?throws?MailException?{??????????((JavaMailSender)?mailSender).send(mimeMessage);??????}????????public?void?doSend(MimeMessagePreparator?mimeMessagePreparator)??????????????throws?MailException?{??????????((JavaMailSender)?mailSender).send(mimeMessagePreparator);??????}??????}?