使用XML创建 EMAIL 模板

xml|创建|模板

发送邮件是web应用系统的一个基本功能。一般来说,邮件都有特定的类型,比如说密码提醒,欢迎信息,订单确认或者收信确认。尽管不同应用邮件的内容各不相同,但是发送邮件的过程基本上是一样的。 构建消息,发送给邮件服务器,发送。
  当使用java开发的时候,我们常常使用JavaMail API 来连接邮件服务器发送邮件。但是这种方式过于笨重(主要由邮件的灵活性造成的),所以当你需要多次使用这种方式发送邮件的时候,最好写一个wrapper.根据使用的方式不同,wrapper可以是发送某一特定的邮件,比如说密码提醒,或者作为一种通用的模式,接受主题,接收人,邮件内容作为参数。
  一旦使用wrapper发送邮件,你需要一个自主构建消息的系统。让我们使用密码提醒作为例子。基本上所有的邮件都包含主题,内容和接收人。当我们发送密码提醒邮件的时候,用户地址和密码是从某个记录登陆信息的知识库里提取的。主题和内容需要和数据库提取的数据合并,并且被保存在某个地方。系统设计最大的问题就是在什么地方保存这种类型的字符串。在很多情形下,字串被保存在属性文件里,这种方式分离了数据和源代码,并且使本地化更加容易。我在很多web应用系统中使用了这种存储机制,但很不幸的是,这种方式有很多缺陷。
  以下是利用属性文件存储邮件字串不合适的原因:
·属性文件使用一种非常简单的数据结构-名称和值组合。当你需要很多值对应一个名称的时候这种结构就不合适了。比如,一个邮件有4个接收人,3个抄送人,使用属性文件很难解决这个问题。
·属性文件的格式非常严格。名称和值必须在同一行上,所以当你编辑文件的时候长字符串是很难处理的。比如,把一个邮件的所有内容放进属性文件是一件多么痛苦的事情。如果你希望值的内容包括换行,你必须使用
  另一种选择是使用XML作为邮件模板,这也是本篇文章所要讨论的内容。XML为你构建模板提供了极大的灵活性,并且它不会有属性文件所有的格式限制,因此这种方式很容易处理长字符串。XML主要弱势就是它处理起来比属性文件复杂。使用属性文件的时候,装载文件和装载后访问文件非常容易。而装载XML文件和使用java提供的多个XML处理库之一处理XML文件就需要更多的工作了。
    这篇文章和所附的代码提供了一个通用的模板使你能够使用XML文件创建模板并且发送邮件,希望由此能够减轻这个过程的痛苦。在这个模板里,我将使用Jakarta 项目里的Commons Digester 包来处理XML,使用JavaMail API发送邮件。

邮件模板
  让我们来看看邮件模板的格式。模板是XML文件,它包含一个根元素和一系列根的子元素。根元素是。必要的子元素是, , 和 。可选的子元素是 , , 和 。如果你使用过邮件系统,那么你可以推导出这些元素实际包含的内容。可选的元素有多个实例,所以你可以为每种类型的接收者指定多个地址。我待会会在描述消息处理的时候来解释运行机制。以下是一个模板文件的例子。
 
    rafe@rafe.us 
    someone@example.com 
    someoneelse@example.com 
    rafe@rafe.us 
    This is the subject 
    This is the body of an email message.  
 

 

可定制的模板
  属性文件的一个有用的特性是你可以使用MessageFormat 类用动态传入的值替代属性文件里的被指定参数。比如说,如果你需要在属性文件里指定errors,其中一个errors是file not found, 你可以这样写:
file.not.found.error=Error, could not find file {0}.
然后,在运行时刻,你这样使用MessageFormat:

ResourceBundle bundle = ResourceBundle.getBundle(
 "MyProperties", currentLocale); 
 Object[] arguments    = { "some_file.txt" }; 
 String newString      = MessageFormat.format(
 bundle.getString("file.not.found.error"), arguments);
 

      最后,newString 将包含Error, could not find file some_file.txt.我在这个系统里加入了类似的灵活性。 可以格式化所有的字符串,所以你可以在邮件模版的subject 和body元素里内嵌在属性文件使用的同样的令牌。
  在某种情形下,你希望在发送邮件的时候插入个人化的信息。比如,你希望在邮件内容里或者订单的内容里包含收件人的姓。本系统使用MessageFormat 来处理邮件模版的内容和主题,从而解决这个问题。处理内容和主题的时候只使用一个参数数组。这样主题里可以包含令牌{0}, {2}, {3},  内容可以包含令牌{0}, {1}, {4} 。我之所以采用这种方式是因为在很多情形下主题和内容使用相同的参数,同时这种方式也简化了传递给EmailSender所需要的参数。

处理模版
  创建完模版,下一步所要做的就是处理它。我们知道,现在有很多的XML处理包可供选择。Commons Digester是Jakarta的公共项目,最初是为了在Struts项目中快速方便的解析Struts的的配置文件而产生的。它提供了从XML文件里的元素到使用类似于XPath  语法的数据结构的映射。 好处在于为了从 XML文件里得到某个元素你不必用SAX一个节点一个节点的解析,也不必使用DOM处理树状数据结构。
  下面这个方法从XML文件里读取数据,然后把数据拷贝到EmailTemplate对象中。

public static EmailTemplate getEmailTemplate(InputStream aStream) 

    Digester digester = new Digester(); 
    digester.setValidating(false); 
 
    digester.addObjectCreate("email", EmailTemplate.class); 
 
    digester.addBeanPropertySetter("email/subject", "subject"); 
    digester.addBeanPropertySetter("email/body", "body"); 
    digester.addBeanPropertySetter("email/from", "from"); 
    digester.addCallMethod("email/to", "addTo", 0); 
    digester.addCallMethod("email/cc", "addCc", 0); 
    digester.addCallMethod("email/bcc", "addBcc", 0); 
 
    try 
    { 
        return (EmailTemplate)digester.parse(aStream); 
    } 
    catch (IOException e) 
    { 
        logger.error("Error: ", e); 
        return null; 
    } 
    catch (SAXException e) 
    { 
        logger.error("Error: ", e); 
        return null; 
    } 

  让我们来逐行研究这段代码。Commons Digester工作的原理是由你来指定解析文件的一些规则。因为没有规范邮件模版的DTD文件,所以在指定处理规则之前,我将validating flag设定为false。开始处理文件的时候,我实例化Digester对象然后调用方法建立数据映射规则。首先,我调用addObjectCreate()方法来建立创建EmailTemplate对象的规则。email是XML模版文件的根元素。因此模版文件和EmailTemplate 对象一一对应。
  我使用addBeanPropertySetter()来处理在模版文件中只出现一次的元素。这个方法有两个参数,元素的路径和要调用的赋值方法。在第一次调用的时候,我指定在文件中符合email/subject 模式的元素应该赋值给EmailTemplate 类的subject 。我们用 “/”来描速XML文件的内嵌关系。在这个例子中,符合subject模式的元素是email 子元素。为了提供更多的灵活性我们可以使用Wildcards。参考Commons Digester的JavaDoc 你可以了解详细的模式的构成方式。
  使用赋值方法处理在模版文件中出现多次的元素是不可行的。我们使用addCallMethod()来处理这种情形,这个方法从元素中取值并且调用指定的方法。我使用这个方法有三个参数的版本,它们是:匹配的模式,调用的方法,调用方法所使用的参数数量。在例子的三种情形中第三个参数都是0,说明符合模式的元素是调用方法的唯一参数。在EmailTemplate类中我定义了三个方法:addTo(), addCc(),  addBcc(),这三个方法将模版文件中的收件人列表加入到模版类的收件人集合中。
  邮件元素的六种类型的子元素的规则都被指定好之后,我开始解析这个文件。在这个例子中, 我传入getEmailTemplate 方法的输入参数InputStream 。parse方法可以解析File,SAX InputSource, InputStream,  Reader, 目标文件的URI。我使用InputStream。 由调用这个方法的代码取得XML文件并且把它转化为InputStream 。为了让这个方法更加通用,我可以用Object作为参数,并且在方法内部使用instanceof 来确定参数的类型,再用相应的方式来处理。
  方法parse 抛出IOException 或者SAXException。把这些异常传给Log4J,由它来处理,返回null. 如果没有异常抛出, 将返回由Digester创建的EmailTemplate对象。

EmailTemplate类剩下的部分
  getEmailTemplate()方法是类EmailTemplate的核心。其他的部分是一些属性值和一些辅助性的方法。有3个String 类型的属性值:内容,主题,寄件人地址,3个ArrayList属性值:to, CC, BCC 列表,这3个值都以String作为基本元素。还有相应的get,set和加入集合的方法。还有3个附加的方便的方法:getToAddresses(), getCcAddresses(), 和 getBccAddresses()。JavaMail接口需要InternetAddress 数组作为地址集合的参数,这些方法可以把对象的String数组转化为JavaMail接口需要的数组形式。

类EmailSender
  当模版文件被解析成EmailTemplate对象,下一步就是发送邮件信息。EmailSender 类包含一个静态的,重载的方法-sendEmail()。 这个方法可以通过很多种方式调用,所有的方式都是对下面这个完全参数方法的一个引用:
public static void sendEmail( 
    String aTo, 
    EmailTemplate aTemplate, 
    String[] aArgs)
 

  参数不需要过多的解释。第一个是邮件的发送地址。你可以在邮件模版里指定很多接收人地址,但是在运行时刻,大多数情况下,系统只需要一个接收人。比如说,你发送一封密码提醒的邮件,只需要指定申请密码的用户的邮件地址。在邮件模版里指定的收件人列表在某种情况下适用:作为测试,系统需要发送邮件到特定收件人列表或者发送时需要包含特定收件人列表。比如说,假设一个系统每当订单提交的时候需要通过一封邮件触发一个workflow,在这种情形下邮件模版种特定的接收人地址是有意义的。
  第二个参数是EmailTemplate自身。第三个参数是MessageFormat解析邮件主题和内容所需要的参数集。由调用这个方法的代码来创建个性化邮件模版所需要的信息数组。也有其他申明的方法简化了这个方法的调用(所以你可以在不指定收件人,或者在没有参数的情况下调用这个方法)。
  方法内部由使用JavaMail发送邮件所需要的一系列调用组成。我觉得使用JavaMail会造成许多冗余,我们来具体看一下。首先,我要通过检测来确定EmailTemplate是否为空。如果为空,什么都不能做。设定的第一步是使用SMTP server的设置创建一个Properties对象(Hashtable)。我把SMTP server的设置设定在 文件里,所以我把这个值从属性文件里读出来然后放到我创建的properties对象里去。
  接着我创建了一个JavaMail Session 对象传入Properties 对象。Session对象在创建MimeMessage对象的时候需要。这个是我待会要做的。然后我将From:的值指定到传入参数EmailTemplate对象的相应栏位。下一步我把To:的值设定到我构建的消息中。这里会有一些技巧,因为用户可以传入To: 地址,同时邮件模版里也包含一些To:地址。问题在于JavaMail 喜欢使用数组描速地址列表,所以由我来决定接收人列表的有多大,然后构建传入的参数。
  因为CC: BCC:的地址必须在模版里指定,我们可以直接来处理它们。我使用EmailTemplate类里的方法把其他的收件人加入到消息里。就像我开始提到的,我使用MessageFormat解析处理邮件主题和内容的方法所需要的参数集。做完之后,我把新的主题拷贝到消息主体里。如此处理消息的内容。剩下的就是调用Transport.send()并且传入MimeMessage 对象。

使用这个系统
  我刚才已经解释了系统的运作原理,现在我来解释如何通过 servlet来使用它,在其他程序里调用的方式是类似的。以下是代码:

// Grab the email template. 
InputStream template = 
    getServlet() 
        .getServletConfig() 
        .getServletContext() 
        .getResourceAsStream( 
            "/WEB-INF/email/registrationNotification.xml"); 
 
EmailTemplate notification = EmailTemplate.getEmailTemplate(template); 
 
// Create the section of the email containing the actual user data. 
String[] args = { "Rafe" }; 
 
EmailSender.sendEmail("rafe@rafe.us", notification, args);
 
  使用这个系统的第一步是把你的XML模版文件转化成InputStream。 因为我使用的是servlet,我从ServletContext取得这个文件。当然还有其他的方式取得这个文件,但是在servlet环境里,这种方式很好用。我只用把InputStream 传给刚才所描述的EmailTemplate.getEmailTemplate()方法就可以了。下一步,建立个性化邮件所需要的参数数组,然后调用方法EmailSender.sendEmail()。
更多
  这个系统还可以更多的优化,有两个比较明显的需要改善的地方:系统应该同时支持纯文本和HTML;支持附件。创建这种类型的信息需要使用类型javax.mail.MimeMultipart。还有在何处存储附件和如何指定附件的问题。在我的系统里,我没有在模版文件里处理附件,因为我的附件是在邮件发送的时候创建的。

 

时间: 2024-12-31 13:58:03

使用XML创建 EMAIL 模板的相关文章

Java中使用XML创建EMAIL模板

发送邮件是web应用系统的一个基本功能.一般来说,邮件都有特定的类型,比如说密码提醒,欢迎信息,订单确认或者收信确认.尽管不同应用邮件的内容各不相同,但是发送邮件的过程基本上是一样的. 构建消息,发送给邮件服务器,发送. 当使用java开发的时候,我们常常使用JavaMail API 来连接邮件服务器发送邮件.但是这种方式过于笨重(主要由邮件的灵活性造成的),所以当你需要多次使用这种方式发送邮件的时候,最好写一个wrapper.根据使用的方式不同,wrapper可以是发送某一特定的邮件,比如说密

XML创建可排序、分页的数据显示页面

xml|创建|分页|排序|数据|显示|页面 在web开发中,我们经常会遇到分页显示和排序数据记录集的情况,这在服务器端使用服务器端的代码和数据库技术是件很轻松的事情,比如:asp.php.jsp等.然而,如果要在客户端显示多条记录并且排序是一件很令人头疼的事情.下面,我们利用extensible markup language(xml,可扩展标记语言)和extensible stylesheet language transformations(xslt,可扩展样式单语言转换),并结合xml p

用XML创建可排序、分页的数据显示页面

xml|创建|分页|排序|数据|显示|页面   <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />        在Web开发中,我们经常会遇到分页显示和排序数据记录集的情况,这在服务器端使用服务器端的代码和数据库技术是件很轻松的事情,比如:ASP.PHP.JSP等.然而,如果要在客户端显示多条记录并且排序是一件很令人头疼的事情.下面,我们利用Extensible Mark

最简单的XML创建、写入操作

xml|创建 //建一個新的空的XML文檔   XmlTextWriter objXml = new XmlTextWriter(Server.MapPath("Text.xml"),null);   //格式化輸出XML文檔   objXml.Formatting = Formatting.Indented;   objXml.Indentation = 4;   //寫入XML文檔標記   objXml.WriteStartDocument();   //寫入XML文檔注釋   o

用C#与XML创建动态分层菜单

xml|菜单|创建|动态 从在复杂的B2B交易中的交换数据到为应用程序提供配置文件结构,XML在许多方面大显身手!由于XML不断地获得软件的支持,我们完全能够预见:XML的应用将不断增加.本文就介绍这样一种应用程序,它使用XML创建类似于Windows开始菜单的分层菜单系统,从而向终端用户提供更满意的Web体验. 这个应用程序将使用 C#.XML和服务器端Microsoft .Net框架,创建一个 DHTML 结构,IE4 或更高版本的浏览器可以操作它并在客户端动态显示.由于我们可以快速地访问服

在Word 2007中创建图表模板

Word 2007中内置有多种图表模板供用户选择使用,不仅如此,用户还可以根据实际需要创建自定义的图表模板,从而提供工 作效率.在Word 2007中创建图表模板的步骤如下所述: 第1步,打开Word 2007文档窗口,根据工作需要制作一张准备用于 创建模板的Word图表.图表制作方法请参阅教程<在Word 2007文档中插入图表>. 第2步,选中创建的图表,在"图表工 具/设计"功能区的"类型"选项卡中单击"另存为模板"命令,如图2

如何使用WPS演示创建在线模板文档

  现在我们常常会使用WPS制作幻灯片,这样不仅更加的生动形象,而且也会给人留下更深的印象,令人更加容易理解我们文档中所想要表达的内容. 在创建幻灯片时,对于不同的演讲内容,我们需要不同的背景模板,今天小编为大家介绍一下如何使用wps演示中的在线模板. 首页打开wps演示,一般情况下会直接显示"在线模板"页面,这时我们可以在此页面中进行查找,选择自己喜欢的模板,同时我们也可以在标签中搜索各种风格的模板,如图1所示. 图1 若打开wps后并没有显示上述页面,那么我们只需要单击左上角上的&

使用 Webix 创建 Email 客户端

Webix 是一个JavaScript UI 库,提供了多达88个UI小部件和功能丰富的 CSS/HTML5 JavaScript 控件.使用 Webix 可以有效地加快 Web 应用的开发.文本将演示了如何通过 Webix 框架,来创建一个 Email 客户端原型. 安装 Webix 可以下载 Webix 的 JS.CSS 文件,但最快的方式是使用 Webix 的 CDN, 如下: <!DOCTYPE HTML> <html> <head> <link rel=

实用!如何使用Webix创建Email客户端

Webix 是一个JavaScript UI 库,提供了多达88个UI小部件和功能丰富的 CSS/HTML5 JavaScript 控件.(分开源和商业收费版本)使用 Webix 可以有效地加快 Web 应用的开发.文本将演示了如何通过 Webix 框架,来创建一个 Email 客户端原型. 安装 Webix 可以下载 Webix 的 JS.CSS 文件,但最快的方式是使用 Webix 的 CDN, 如下: 快速开始 我们为我们的第一个应用创建第一个页面 index.html.在 <body>