Java中利用XML建设EMAIL模板
副标题#e#
发送邮件是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文件,它包括一个根元素和一系列根的子元素。根元素是。须要的子元素是, , 和 。可选的子元素是 , , 和 。假如你利用过邮件系统,那么你可以推导出这些元素实际包括的内容。可选的元素有多个实例,所以你可觉得每种范例的吸收者指定多个地点。我待会会在描写动静处理惩罚的时候来表明运行机制。以下是一个模板文件的例子。
[email protected]
[email protected]
[email protected]
[email protected]
This is the subject
This is the body of an email message.
#p#副标题#e#
可定制的模板
属性文件的一个有用的特性是你可以利用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所需要的参数。
处理惩罚模版
#p#分页标题#e#
建设完模版,下一步所要做的就是处理惩罚它。我们知道,此刻有许多的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)
#p#分页标题#e#
参数不需要过多的表明。第一个是邮件的发送地点。你可以在邮件模版里指定许多吸收人地点,可是在运行时刻,大大都环境下,系统只需要一个吸收人。好比说,你发送一封暗码提醒的邮件,只需要指定申请暗码的用户的邮件地点。在邮件模版里指定的收件人列表在某种环境下合用:作为测试,系统需要发送邮件到特定收件人列表可能发送时需要包括特定收件人列表。好比说,假设一个系统每当订单提交的时候需要通过一封邮件触发一个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("[email protected]", notification, args);
利用这个系统的第一步是把你的XML模版文件转化成InputStream。 因为我利用的是servlet,我从ServletContext取得这个文件。虽然尚有其他的方法取得这个文件,可是在servlet情况里,这种方法很好用。我只用把InputStream 传给适才所描写的EmailTemplate.getEmailTemplate()要领就可以了。下一步,成立本性化邮件所需要的参数数组,然后挪用要领EmailSender.sendEmail()。
更多
这个系统还可以更多的优化,有两个较量明明的需要改进的处所:系统应该同时支持纯文本和HTML;支持附件。建设这种范例的信息需要利用范例javax.mail.MimeMultipart。尚有在那里存储附件和如何指定附件的问题。在我的系统里,我没有在模版文件里处理惩罚附件,因为我的附件是在邮件发送的时候建设的。