| |
|
|
| |
Наши услуги |
|
| |
|
|
| |
Основной сферой нашей
деятельности является создание бизнес и
контент проектов расчитанных на
целевых посетителей, предоставление качественного хостинга для сайтов,
редизайн сайтов и их поддержка.
Seo
оптимизация, продвижение в рейтингах и поисковых
системах. |
|
| |
|
|
| |
Интернет торговля |
|
| |
|
|
| |
Продвижение Ваших товаров и увеличение сбыта на торговых площадках
Республики Беларусь. |
|
| |
|
|
| |
Компьютеры |
|
| |
|
|
| |
Продажа компьютеров "XEON"
под заказ.
Комплектующие ведущих фирм производителей. Бесплатная доставка.
Кредит.
Гарантия до 36 месяцев. Собственный сервисный центр. Офис в центре
Минска!
|
|
| |
|
|
| |
Партнеры |
|
| |
|
|
| |
|
|
|
|
| |
Создаем шаблоны электронных писем с помощью XML
|
Статьи - Java
|
|
| |
На сегодняшний день, возможность посылать электронные сообщения является неотъемлемой частью любого web-приложения. В основном, это очень специфические виды сообщений, как, например, сообщения, которые шлются для напоминания пользовательского пароля, приветственные сообщения, сообщения подтверждающие заказы и прочие. Хотя содержание электронных сообщений и меняется от приложения к приложению, но процесс отправки редко бывает различен. Вы просто создаете письмо, отсылаете его на почтовый сервер, и позже получатель его оттуда забирает.
Когда вы программируете на Java, то обычно для выполнения всей "черной" работы, связанной с соединением с почтовым сервером и отправкой письма, используется JavaMail API (
http://java.sun.com/products/javamail/). К сожалению, этим API крайне неудобно пользоваться (в основном из-за гибкости электронной почты как таковой), поэтому если вы собираете использовать его достаточно часто, то было куда удобнее и разумнее написать для него специальную оболочку. В зависимости от того, как его использовать, эта оболочка может быть нацелена на работу с каким-нибудь конкретным видом писем, (для отправки писем подтверждающих пароль, например) или же она будет работать как обычно, принимая тему сообщения, список получателей и тело письма в качестве аргументов.
Создав однажды подобную оболочку, вам необходимо иметь также и систему для создания самих сообщений. Возьмем, например, сообщения, напоминающие пользователю его пароль, если он его случайно забыл. Почти все электронные письма имеют поле для темы сообщения, список получателей и тело письма. Когда мы посылаем письмо, напоминающее пароль, электронный адрес получателя и сам пароль обычно извлекаются из какого-нибудь хранилища, в котором хранится информация о пользовательских аккаунтах. Поле темы и само тело сообщения должны сливаться с данными из базы данных и должны быть где-то сохранены. Одна из основных проблем при проектировании таких приложений – это решить где же все-таки лучше хранить такого рода данные. Во многих случаях, эти строки сохраняются в файлах свойств, которые содержатся отдельно от вашего исходного кода и предоставляют удобную возможность локализации, если необходимо. Такой подход используется в очень многих web-приложениях для хранения шаблонов электронных писем для отправки, однако, подход этот не совсем правильный.
Вот список основных причин, по которым использование файлов свойств не является оптимальным способом хранения строк, составляющих шаблон электронных писем:
- Файлы свойств отображаются в очень простую структуру данных – пары ключей и их значений. Это совсем не подходит в случае, если нужно привязать множество значений одному и тому же ключу. Например, электронное сообщение может иметь четырех человек в поле To: и троих в поле Cc:. Это невозможно реализовать просто с помощью файлов свойств.
- Файлы свойств имеют очень строгое форматирование своего содержимого. Каждый ключ и его значение должны находиться на одной и той же строке. Таким образом, строки могут доставить много ненужных проблем, связанных с редактированием этого файла. Например, будет очень проблематично поместить все тело сообщения электронного сообщения в одном свойстве (пара ключ=значение). И если вам нужно будет включить переносы на другую строку в пределах значения этого свойства, то вы будете вынуждены заменять их специальным символом n.
Существует альтернативный подход к созданию шаблонов электронных сообщений. Он заключается в использовании XML, и именно этот подход мы и будем рассматривать в этой статье. XML предоставляет возможность конструирования шаблонов электронных сообщений с очень гибкой структурой и, помимо этого, он не имеет таких ограничений на форматирование, какие имеют место в файлах свойств. Поэтому с его помощью мы можем очень просто сохранять достаточно большие строки. Единственный достоинство файлов свойств в том, что с ними чуть проще работать, чем с XML-документами. В случае с файлами свойств гораздо проще загрузить файл, и после этого получить доступ к свойствам, уже не обращаясь к этому файлу. С другой стороны, на XML-файл уходит куда больше времени на загрузку и обработку. Для этого также необходимо использовать одну из многочисленных библиотек для работы с XML-файлами, некоторые из которых поставляются вместе с Java.
Эта статья и сопровождающие ее примеры, призваны попытаться, как можно больше упростить для вас этот процесс, предоставляя общий фреймуорк для создания шаблонов электронных писем с помощью XML-документов и их отправки. В этом фреймуорке мы использовали пакет Common Digester из проекта Jakarta для обработки XML и JavaMail API для отправки фактических сообщений.
Шаблоны электронных сообщений
Давайте посмотрим на формат самих шаблонов электронных сообщений. Шаблоны представляют собой обычные XML-файлы, которые содержат корневой элемент и дочерние элементы этого элемента. Корневой элемент – это
. Обязательные дочерние элементы:
, и
. Опциальные элементы:
,
и
. Если вы когда-либо пользовались почтовым клиентом, то каждое из этих элементов вы легко сможете сопоставить с полями электронного письма в вашей почтовой программе. Каждого из опциальных элементов может быть несколько экземпляров в одном шаблоне. Поэтому вы можете запросто включить множество адресов для каждого из получателей этого сообщения. Позже мы рассмотрим, как это все работает, и как будет происходить обработка этого XML-шаблона сообщения. Вот пример файла-шаблона:
litvinuke@tut.by
someone@mail.ru
someoneelse@mail.ru
litvinuke@tut.by
Это тема письма
Это тело нашего электронного сообщения.
|
Настраиваемые шаблоны
Файлы свойств предоставляют одну очень полезную возможность. Она заключается в том, что вы можете использовать класс MessageFormat для замены идентификаторов-заменителей в файле свойств на реальные значения во время работы приложения. Например, если вы храните сообщения об ошибках в файле свойств, и одно из этих сообщений – это "файл не найден", то вы можете внести в этот файл следующее свойство:
file.not.found.error=Ошибка, невозможно найти файл {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 будет содержать строку "Ошибка, невозможно найти файл some_file.txt.". Подобную же функциональность мы привнесли и в нашу систему. Поскольку класс MessageFormat может работать с любыми строками, вы можете очень просто вставлять такие же идентификаторы-заменители в элементы subject и body XML-шаблона электронного сообщения.
Иногда может возникнуть необходимость вставлять персональную информацию в ваши шаблоны перед посылкой писем. Например, вам может понадобиться включить имя получателя в тело письма или, быть может, даже детальную информацию о произведенном им заказе. Наша система легко справляется с такой задачей путем обработки содержимого элементов subject и body с помощью MessageFormat. Уловка в том, что этот класс принимает только один массив аргументов, который будет использоваться для обработки как поля subject, так и тела сообщения. Так в содержимом элемента subject могут иметь место идентификаторы {0}, {2} и {3}, а в содержимом элемента body: {0}, {1} и {4}. Мы выбрали такой подход потому, что очень часто одни и те же аргументы используются в обоих полях body и subject, и это также упрощает список параметров, передаваемый в EmailSender.
Обработка шаблона
Теперь, когда мы уже создали шаблон, можно приступать к его обработке. Как вы уже знаете, существует множество библиотек, которые предназначены для работы с XML-документами. Одна из них – это Commons Digester, часть проекта Jakarta Commons, создавался изначально, как часть проекта Struts, для того, чтобы предоставить быстрый и простой путь к разбору конфигурационного файла Struts. Этот инструмент предоставляет простой подход к отображению элементов XML-файла в структуру данных, с использованием синтаксиса, схожего с XPath (
http://www.w3.org/TR/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("
Ошибка: ", e);
return
null;
}
catch (SAXException e)
{
logger.error("
Ошибка: ", e);
return
null;
}
} |
Теперь давайте рассмотрим каждую из строк этого примера. Работа с Commons Digester заключается в создании некоторого набора правил, которые впоследствии будут применены к файлу, который будет обрабатываться. Прежде чем мы приступили к заданию этих правил, мы предварительно установили флаг проверки на валидность XML-документа в false, поскольку мы не создавали и не привязывали к нашему XML-файлу никаких DTD-файлов для проверки на валидность структуры нашего шаблона. Чтобы начать обработку файла, мы создаем объект класса Digester и после этого вызываем методы для установки правил отображения данных. Сперва мы вызываем метод addObjectCreate(), который устанавливает правило создания объекта EmailTemplate, как только нам встретится элемент email. Элемент email является корневым элементом нашего шаблона, поэтому каждый файл шаблона будет отображаться в один экземпляр класса EmailTemplate.
Для элементов, которые появляются всего единожды в нашем шаблоне, мы использовали метод addBeanPropertySetter(). Он принимает два аргумента: путь к элементу, который будет обрабатываться, и set-метод, который будет отображать содержимое этого элемента в объект EmailTemplate. В первом вызове мы обозначили, что содержимое элементов, которые совпадают с заданным шаблоном ("email/subject") должно быть передано set-методу поля subject объекта класса EmailTemplate. Заданный шаблон определяет порядок вложенностей элементов, разделяемые символами /, по которому следует искать элемент. В нашем случае, заданный шаблон соответствует элементу subject, который является дочерним по отношению к элементам email. При задании подобных шаблонов поиска также можно использовать символы замены (wildcards), которые могут обеспечить более гибкие возможности поиска. Для ознакомления с подробным описанием использования и создания этих шаблонов, посмотрите JavaDoc(
http://jakarta.apache.org/commons/digester/api/index.html) для Commons Digester.
Что касается элементов, которые могут встречаться неоднократно в шаблоне электронного сообщения, то для этих свойств вызов set-методов не подходит. Вместо этого мы использовали метод addCallMethod(), который принимает содержимое элемента и вызывает специальный метод. Мы использовали версию этого метода, которая принимает три аргумента. Это шаблон на соответствие, метод, который следует вызывать, и количество аргументов, которое будет передано этому методу. Во всех трех случаях, мы указали 0 в качестве третьего аргумента, поскольку в этом случае, методу будет передано только лишь содержимое найденного элемента. В классе EmailTemplate мы написали три метода: addTo(), addCc() и addBcc(), которые добавляют список получателей сообщения из файла шаблона в коллекции класса EmailTemplate.
Как только мы установили правила для всех шести типов дочерних элементов XML-шаблона электронного сообщения, мы можем приступать непосредственно к разбору нашего файла. Для этого мы используем InputStream, связанный с файлом XML-документа, который передается в качестве аргумента методу getEmailTemplate(). Метод parse() может принимать в качестве аргумента объект File, InputSource из SAX, InputStream, Reader или строку URI, которая определяет место расположения файла, который нужно обработать. Мы выбрали версию метода parse(), которая принимает объект InputStream в качестве аргумента.
Метод parse() может выбрасывать исключения IOException или SAXException. Если возникает какое-то из этих исключений, то мы его ловим, журналируем его с помощью log4j и возвращаем null. Если не возникнет никаких исключений, то метод getEmailTemplate() возвратит новый экземпляр класса EmailTemplate, который будет сгенерирован с помощью класса Digester.
Остальная часть класса EmailTemplate
Самой значимой частью класса EmailTemplate несомненно является метод getEmailTemplate(). Все остальное просто различные свойства и методы, предназначенные скорее просто сделать работу с классом удобнее. Итак, этот класс имеет три свойства класса String: тема, тело письма, адрес отправителя, а также другие свойства, которые хранятся в структурном классе ArrayList: списки адресатов, полей CC и BCC. Для каждого из этих свойств в классе EmailTemplate предусмотрены set- и get-методы: getToAddresses(), getCcAddresses() и getBccAddresses(). JavaMail API ожидает, что вы будете передавать ему адреса в старом стиле в виде массива объектов класса InternetAddress. Эти методы заботятся также и о том, чтобы конвертировать объекты ArrayList в массив объектов, которые требует JavaMail API.
EmailSender
Теперь, когда мы успешно разобрали файл шаблона и получили готовый объект класса EmailTemplate, следующим шагом приступим к отправке электронного сообщения. Класс EmailSender включает один статический, перегруженный метод – sendEmail(). Вот его сигнатура:
public
static
void sendEmail(
String aTo,
EmailTemplate aTemplate,
String[] aArgs) |
Аргументы этого метода наверняка не требует долгих разъяснений. Первый аргумент – это поле To: (Кому) электронного сообщения. В принципе, вы можете задать это поле непосредственно в самом шаблоне сообщения, однако очень часто получатель сообщения определяется на этапе работы приложения. Например, если вы шлете сообщение-напоминание о пароле, то это сообщение должно быть адресовано именно тому пользователю, который сделал соответствующий запрос. Адрес получателя выгодно жестко прописывать в шаблоне электронного сообщения, например, тогда, когда системе нужно послать сообщение для тестирования или для каких-нибудь системных нужно. Например, предположим системе нужно сгенерировать и послать электронное сообщение, которое бы переключало последовательность выполняемых действий, каждый раз, когда послан соответствующий запрос. В этом случае конечно лучше адрес получателя жестко прописать в шаблоне сообщения.
Второй аргумент – это сам объект EmailTemplate. А третий – это список аргументов, которые будут переданы классу MessageFormat, когда он будет обрабатывать поле темы и тело сообщения. Для этого существует специальная часть кода, которая создает массив информации, которая используется для персонализации шаблона электронного сообщения. Там присутствуют также несколько других объявленных методов, которые служат для того, чтобы упростить вызов этого метода. Таким образом, вы можете вызывать его без указания получателей или вообще без каких-либо аргументов.
Тело метода sendEmail() в основном состоит из вызовов методов JavaMail API для настройки необходимых параметров и отправки сообщения. Сначала мы проверяем, не равен ли объект EmailTemplate null. Если равен, то мы ничего не делаем. Иначе первым шагом установки параметров мы создаем объект свойств Properties (улучшенный Hashtable) с установками SMTP-сервера.
После этого мы создаем объект Session из пакета JavaMail API и передаем его конструктору созданный ранее объект Properties с настройками SMTP-сервера. Объект Session нужен для того, чтобы создать объект MimeMessage, что мы и делаем. Теперь устанавливаем поле адреса From: равным адресу, определенному в объекте EmailTemplate, который мы передаем этому методу в качестве аргумента. Следующим шагом устанавливаем поле To:.
Поскольку все адреса CC: и BCC определены в пределах шаблона, их обработка не будет доставлять никаких проблем. Нужно просто, используя подходящие методы класса EmailTemplate добавить дополнительных получателей сообщения в само сообщение. Как было ранее упомянуто, мы используем MessageFormat для того, чтобы применить все аргументы, переданные методу к теме и телу сообщения. После этого нужно просто скопировать полученные тему и тело сообщения в объект сообщения. Теперь все что осталось сделать – это вызвать метод Transport.send() и передать ему объект класса MimeMessage.
Использование фреймуорка
Теперь мы рассмотрим, как нужно пользоваться этой системой. Мы рассмотрим вариант работы сервлета, хотя это должно работать и в любой другой нормальной программе. Ниже приведенный код наглядно показывает работу с нашей системой:
// Грабим шаблон электронного сообщения
InputStream template
=
getServlet()
.getServletConfig()
.getServletContext()
.getResourceAsStream(
"
/WEB-INF/email/registrationNotification.xml");
EmailTemplate notification
= EmailTemplate.getEmailTemplate(template);
// Создаем секцию электронного сообщения, содержащую фактические данные о пользователе
String[] args
= { "
Rafe" };
EmailSender.sendEmail("
rafe@rafe.us", notification, args); |
Сначала мы, используя системные функции, получаем InputStream, связанный с файлом шаблона, представленный в виде XML-документа. Поскольку мы используем сервлет, файл мы получаем из ServletContext. Существуют конечно и множество других способов получить InputStream, связанный с этим файлом, но в случае со средой сервлета, этот вариант подходит как никакой другой лучше. После этого, все что нам нужно сделать – это передать полученный объект класса InputStream методу EmailTemplate.getEmailTemplate(), который мы описывали ранее. Потом мы просто определяем массив с аргументами для настройки электронного сообщения и вызываем метод EmailSender.sendEmail().
Вместо заключения
Существует ряд улучшений, который можно привнести в данную систему. Два самые очевидные – это добавление возможности отправки как HTML, так и обычных электронных сообщений, а также добавление возможности отправки вложенных файлов вместе с сообщением. Чтобы создать такого рода сообщения, достаточно воспользоваться сообщениями типа javax.mail.MimeMultipart. |
|
|
| |
|
|
| |
Просмотров: 225
Добавлено: 5 марта 2007 |
На главную |
|
|