Сделать стартовой  Добавить в избранное
Воскресенье, 19.05.2024, 18:42
Главная
Регистрация
Вход
Мир софта!
Приветствую Вас Гость | RSS
Mirsoft
Меню сайта
Наш опрос
Оцените мой сайт
Всего ответов: 21

Электронный магазин на Java и XML. Новости на сайте

Разработка системы показа новостей

    Мы хотим предложить посетителям нашего web-сайта последние новости фирмы в компактном и удобном для чтения формате. Помните, что обычно в вашем распоряжении имеется всего лишь несколько секунд, чтобы привлечь внимание к вашему сайту случайного посетителя, который просто "прогуливается" по сети. Мы хотим, чтобы посетителю было понятно, как найти на сайте подробную информацию, если его что-то заинтересовало, как войти в систему каталога и, будем надеяться, что-нибудь приобрести.
    Если вы подумаете, какими характеристиками должна обладать система показа новостей, в ваш список, вероятно, войдут следующие пункты:

  • гибкий способ отображения;
  • удобный ввод данных;
  • минимальная нагрузка на сервер.

    Наряду с обеспечением этих свойств при разработке системы вы, в первую очередь, должны будете решить, какие элементы и атрибуты XML использовать для представления данных, затем сделать выбор между моделями DOM и SAX (механизмами отображения данных для пользователя) и, наконец, определить механизм добавления новых сообщений.

Гибкость отображения

    Поскольку мы решили остановиться на XML как на исходной среде хранения данных, мы можем обеспечить гибкость отображения посредством хранения данных, необходимых для всех доступных способов представления информации. Мы имеем в виду следующее: вероятно, вы замечали, что на разных коммерческих web-сайтах новости компании представлены обычно одним из трех способов:

  • заголовки новостей со ссылкой на полный текст;
  • несколько наиболее интригующих строк со ссылкой на полный текст;
  • полный текст сообщения.

    Существуют и другие форматы сообщений: электронный информационный бюллетень, печатная копия информационного бюллетеня, корпоративные сообщения. Для этих форматов также применимы описанные выше три способа (заголовок, краткое сообщение и полный текст). Первая наша задача при разработке системы отображения новостей - создать такой документ XML, который поддерживал бы все три формата.

Элементы текстов сообщений

    Хотя в области искусственного интеллекта и понимания компьютером естественных языков сделаны большие успехи, никто не рассчитывает, что компьютер напишет хороший заголовок, проанализировав текст сообщения. Поэтому приходится согласиться с тем, что нужен человек, который для каждого способа представления новостей создаст отдельный заголовок. В сообщении обычно указывается дата, а иногда рядом еще и место, где произошло то событие, о котором идет речь, например: "Остин, Техас, 1 января 2000". Эта задача тоже должна выполняться человеком.
    Некоторые сообщения очень выигрывают, когда сопровождаются графикой, звуковыми клипами или ссылками на другие сайты, поэтому продумайте, как сконструировать документ XML, чтобы его можно было дополнить различными элементами, способствующими увеличению привлекательности страницы новостей. Мы решили, что было бы слишком сложно и неудобно снабжать систему показа новостей в нашем примере всеми возможными "украшениями". Поэтому мы будем хранить тексты сообщений для второго и третьего способов (краткое и полное сообщение), используя тег XML <[[CDATA...]]>.
    Поскольку анализаторы XML не пытаются анализировать текст, содержащийся внутри раздела CDATA, в этот раздел вы можете поместить любую разметку HTML, не сбивая с толку анализатор.
    Элементы, содержащие дату, заголовок, краткое сообщение и полный текст, показаны в листинге 8.1.

Листинг 1. Дата, заголовок, короткое и полное сообщения (thenews.xml)

<date>Austin, TX, Jun 14 2000</date>
<head>Best Seller at a Great Price</head>
<short>
<![CDATA[Due to a special deal with the publisher, we can now offer
<i>Dryer Lint Art</i>
at 50% off the retail price.]]>
</short>
<long>
<![CDATA[This books starts with simple Dryer Lint projects suitable for the novice and advances through easy stages tothe (literally)
<b>monumental</b>
recreation of famous monuments in that most flexible of craft materials, dryer lint. Even though you may never attempt major constructions like the Statue of Liberty project documented in the final chapter, your projects will benefit by a study of this famous creation. Includes UML diagrams.]]>
</long>

    Другим аспектом гибкости является способность выборочно представлять сообщения в соответствии с темой, интересующей посетителя. Предполагая, что спектр возможных интересов посетителей сайта XMLGifts.com очень широк, мы хотим показать каждому посетителю те новости, которые связаны с его излюбленной темой, и в том месте сайта, куда он с наибольшей вероятностью заглянет. В такой структуре неизбежны перекрывающиеся области; например, книга о музыкальной группе может оказаться интересной как для покупателей книг, так и для покупателей музыкальных компакт-дисков. Следовательно, каждое сообщение должно быть снабжено одной или несколькими пометками, которые указывают, к каким тематическим категориям можно его отнести; а формат представления новостей должен допускать переключения между различными темами сообщений.
    Для того чтобы пометить сообщение и отнести его тем самым к определенной категории, мы можем использовать элемент или атрибут. Следуя советам, приведенным в разделе "Элементы или атрибуты?" главы 2, можно заключить, что в данном случае лучше использовать атрибуты, так как тема сообщения - это данные о содержимом элемента, и мы предполагаем, что количество тем сообщений будет ограниченным.

Расположение сообщений в зависимости от их новизны

    Самые свежие новости должны располагаться первыми. Так как документ XML автоматически сохраняет порядок следования элементов, новые элементы должны добавляться к началу документа. Более того, было бы неплохо предусмотреть возможность отображения только самых свежих новостей. Следовательно, нам нужен способ представления "возраста" сообщений.
    После долгих колебаний между многочисленными способами представления даты, которые позволили бы нам отображать только недавние сообщения, мы остановились на использовании простого целочисленного представления количества дней, прошедших с 1 января 1970 года. Для этого значение типа long, возвращаемое методом System.currentTimeMillis(), делится на количество миллисекунд в сутках, и полученное число становится значением атрибута timestamp тега Newsitem. Альтернативные варианты - использование классов Java DateFormat или Calendar - были отвергнуты, так как они подразумевают создание большого количества объектов, а мы хотим, чтобы показ новостей создавал минимальную нагрузку на сервер.

Информация для управления сообщениями

    Поскольку вы или ваши служащие будут обновлять страницу новостей в режиме подключения к сети, было бы полезно отслеживать, кто какое сообщение написал. (Например, чтобы знать, кто должен получать нагоняй за допущенную ошибку.) Для этого используется атрибут <author> элемента <Newsitem>. Сервлет обновления сообщений, описанный в разделе "Добавление свежих новостей" этой главы, обладает простым механизмом контроля доступа, в котором используются имя автора и пароль; этот то самое имя автора, которое становится значением атрибута author.
    Чтобы создать документ HTML, в котором заголовок содержит ссылку на полную версию текста, нужно использовать уникальный идентификатор. Мы, например, выбрали простейший вариант: при создании каждого сообщения <NewsItem> ему присваивается серийный номер, который и становится значением его атрибута id.

Корневой элемент документа

    Мы отслеживаем некоторые параметры, используемые во всем файле, с помощью атрибутов, которые задаются в корневом элементе документа, Newsfile. Очередной атрибут id - это просто nextid. Присваивание нового значения каждому следующему атрибуту nextid является обязанностью программы, добавляющей новые сообщения или, в случае редактирования в автономном режиме, автора элемента Newsitem.
    Корневой элемент также является подходящим местом для хранения атрибутов, связанных с различными заданными по умолчанию параметрами отображения. В приведенном ниже примере имеется только один такой атрибут, longtemplate, который идентифицирует заданный по умолчанию файл - шаблон HTML, используемый для форматирования сообщений.
    В листинге 8.2 показано, как используются все перечисленные теги.

Листинг 2. Элемент <Newsfile> с одним элементом <Newsitem> (thenews.xml)

<?xml version="1.0" standalone="yes" ?>
<!-выходные данные NewsUpKeep -->
<Newsfile longtemplate="tmlong.html" nextid="1010" >
<Newsitem timestamp="11045" topic="CDs" author="wbrogden" id="1008" >
<head>Your Favorite Music Now Available</head>
<date>Austin, Feb 1, 2000</date>
<short>
<![CDATA[XMLGifts proudly announces the availability of the CD that has all the geeks singing, <i>It's Dot Com Enough for Me.</i>]]>
</short>
<long>
<![CDATA[<p>
<i>It's Dot Com Enough For Me.</i>
now in stock!</p>
<p>All those great songs created during breaks in all-night coding sessions - now recorded by top Silicon Valley garage bands on our private label. <i>It's Dot Com Enough for Me</i> will have you singing along - or maybe laughing till the Jolt cola spurts out your nose. Seventeen songs from geeks at Sun, Microsoft, Apple, Cisco, and other top tech outfits. </p>]]>
</long>
</Newsitem>
</Newsfile>

Простота ввода данных

    Поскольку мы выбрали простой формат новостей, показанный в листинге 8.2, ввод данных осуществляется тоже достаточно просто. Система, основанная на формах HTML и сервлетах, описанная в разделе "Добавление свежих новостей" этой главы, позволяет добавлять новые сообщения через Интернет.
    Тем не менее легкость ввода данных никак не связана с контролем за качеством самого текста. Для достижения лучших результатов следует убедиться, что темы, согласно которым классифицируются сообщения, и стиль текста всегда согласуются между собой. Также необходимо составить список требований и рекомендаций по составлению текстов сообщений и убедиться в том, что эти списки доступны всем служащим фирмы, уполномоченным размещать сообщения на сайте.

Минимальная нагрузка на сервер

    Поскольку мы надеемся, что посещаемость нашего сайта будет достаточно велика, мы хотим, чтобы отображение главной страницы выполнялось по возможности просто, то есть чтобы страница быстро загружалась, а ее генерирование не требовало больших затрат ресурсов со стороны сервера. Рассмотрим следующие альтернативные варианты отображения новостей.

  • Статические страницы новостей (Static News Pages). Статические страницы быстро загружаются, и главная страница благодаря XML может формироваться заново при появлении нового сообщения. Однако использование статических страниц исключает возможность их индивидуальной настройки для постоянных посетителей.
  • Страницы новостей, генерируемые сервлетами (Servlet-Generated News Pages). Сервлеты Java могут генерировать все, что потребуется; при этом предполагается, что они используют файлы с шаблонами HTML для регулировки многочисленных атрибутов внешнего вида сайта.
  • JSP-страницы (JavaServer Pages). Преимущество JSP-страниц перед сервлетами заключается в том, что для изменения внешнего вида страницы web-дизайнеру не нужно уметь программировать на Java.

    При выборе методов обработки следует сделать выбор между моделями SAX и DOM, а также между анализаторами XML, проверяющими либо не проверяющими допустимость документа. Модель SAX подразумевает работу анализатора для доступа к каждой странице. При использовании модели DOM доступ к страницам осуществляется быстрее, но зато все приходится хранить в памяти. Предполагая, что количество новостей будет не больше нескольких сотен, затраты ресурсов на хранение всей модели DOM в памяти не окажутся слишком значительными, поэтому мы считаем, что в данном случае модель DOM является безусловно оптимальным вариантом.
    Мы не видим никаких причин в использовании анализатора, проверяющего допустимость документа. Так как новые сообщения будут создаваться автоматически, вероятность ошибки форматирования весьма невелика. Кроме того, вряд ли ошибки, связанные с недопустимостью документа, могут смутить пользователя.

Система показа новостей

    Окончательный вариант устройства системы показа новостей изображается блок-схемой, приведенной на рис. 8.1. Обработка информации, происходящая на сервере, представлена в правой части блок-схемы, а обработка в автономном режиме - в левой части. Исходный файл XML может редактироваться как в режиме подключения к сети, так и автономно, но предпочтительным является режим подключения, так как он позволяет автоматически задавать атрибуты id и timestamp.


Рис. 1. Обработка сообщений

    Объектная модель документа поддерживается в памяти с помощью класса DOMlibrary, который был описан в главе 7. Обновление исходного файла XML в режиме подключения выполняется сервлетом CompanyNewsServ и классом NewsUpKeep, которые обсуждаются далее в этой главе. Формирование web-страниц новостей на основе текстов сообщений осуществляется сервлетами или JSP-страницами, использующими класс NewsFormatter, который обсуждается в следующем разделе. Для создания информационных бюллетеней и печатной версии требуются другие форматы, которые легко написать, основываясь на приведенных ниже примерах.

Внешний вид web-страницы

    Прежде чем мы углубимся в рассмотрение кода нашей системы показа новостей, давайте посмотрим, как может выглядеть разрабатываемая страница. На рис. 8.2 показана web-страница, посвященная новостям фирмы, в контексте более крупного сайта. Мы не включили в нее навигационный интерфейс и другие элементы, которые должны присутствовать в реальном сайте.


Рис. 2. Web-страница новостей, генерируемая с помощью JSP-страницы

    JSP-страница, используя класс NewsFormatter, который подробно описывается в следующем разделе, сгенерировала показанную на рисунке страницу на основе файла XML. В левой части экрана приводятся заголовки последних новостей по всем темам. Самое свежее сообщение приводится полностью в центре страницы. Справа показаны новости в кратком изложении, но первая из них (полная версия которой расположена по центру) пропущена. При щелчке мышью на заголовке или кратком изложении сообщения появляется полная версия этого сообщения.

Класс NewsFormatter

    Ключевым классом Java для формирования новостных сообщений является класс NewsFormatter. Как показано в листинге 8.3 и следующих листингах, класс NewsFormatter включает в себя объект File, который указывает на исходный файл XML. Класс NewsFormatter использует класс DOMlibrary, описанный в главе 7, чтобы получить объект Document, содержащий все данные из файла XML. Конструктор получает список узлов NodeList, содержащий все узлы Newsitem, и задействует его для создания массива с названием itemNodes. Этот массив требуется для решения различных задач форматирования.

Листинг 3. Начало кода класса NewsFormatter

package com.XmlEcomBook.Chap08;
import com.XmlEcomBook.DOMlibrary ;
import java.io.*;
import java.util.* ;
import javax.servlet.*;
import javax.servlet.http.*;
import org.w3c.dom.* ;
public class NewsFormatter
{
static String handler ; // сервлет для отображения одного
//сообщения
public static void setHandler(String s){handler=s; }
// переменные экземпляра
File newsFile ;
String newsFileName ;
String newsFilePath ;
String headStr, footStr ;
Node[] itemNodes ;
Element docRoot ;
Hashtable nodeHash ; // хэш-таблица элементов <Newsitem,
//ключами которых служат имена тегов
int maxNitems, skipNitems;
int itemsCount = 0 ;
public NewsFormatter( File f ) throws IOException {
     newsFile = f ;
     newsFileName = f.getAbsolutePath() ;
     int p = newsFileName.lastIndexOf( File.separatorChar );
     if( p > 0 ){ newsFilePath = newsFileName.substring(0,p);
     }
     else { System.out.println("NewsFormatter path problem");
     }
     DOMlibrary library = DOMlibrary.getLibrary();
     Document doc = library.getDOM( newsFileName );
     if( doc == null ){
throw new FileNotFoundException( newsFileName );
     }
     docRoot = doc.getDocumentElement();
     NodeList newsItemNodes = doc.getElementsByTagName("Newsitem");
     int ct = newsItemNodes.getLength();
     itemNodes = new Node[ ct ];
     for( int i = 0 ; i < ct ; i++ ){
itemNodes[i] = newsItemNodes.item( i );
     }
}

    Вы, должно быть, помните из главы 7, что класс DOMlibrary перезагружал файл XML, если время его последней модификации изменялось. Поскольку в нашем случае объект Document не меняется в результате действия класса NewsFormatter, он может использоваться совместно любым количеством сервлетов и доступ к нему нужно синхронизировать.
    У нас имеются две версии метода doNews. Версия, приведенная в листинге 8.4, используется для вывода нескольких сообщений в виде заголовков новостей, краткого и полного форматов изложения. Эта версия метода обеспечивает следующие возможности: выбор сообщений по их тематике и времени появления, пропуск указанного количества сообщений и ограничение общего количества отображаемых сообщений. Строки hs и fs - необязательные параметры, которые обеспечивают некоторые небольшие дополнительные возможности форматирования.
    Метод doNews проверяет наличие параметров типа Srting, которые ограничивают выбор сообщений определенными тематическими или временными рамками. Если параметр topstr отличен от null и не пуст, вызывается метод selectNodes, который ограничивает полный список сообщений набором новостей, соответствующим заданной тематике. Аналогично, если указана строка age, вызывается метод limitAge. Если какой-либо из этих методов сокращает список сообщений до нуля, метод doNews сразу же прекращает свое выполнение. Другие параметры контролируют максимальное количество новостей на странице и относительный номер сообщения, с которого начинается их просмотр.

Листинг 4. Метод doNews выбирает способ представления сообщений (NewsFormatter.java)

// hs и fs - это верхние и нижние колонтитулы,
// используемые в краткой и полной версиях сообщения
// в элементе <Newsfile также можно задать шаблоны
// PrintWriter, hs, fs, topics, H,S или L, age, mx#
// skpN используется для того, чтобы пропустить первые N
// сообщений (предполагается, что они печатаются где-то в
// другом месте страницы). Для того чтобы напечатать все
// сообщения, задайте параметр skpN равным 0
// возвращает количество напечатанных сообщений
public int doNews( PrintWriter out, String hs, String fs, String topstr, String sz, String age, int skpN, int mxN ){
headStr = hs ; footStr = fs ;
skipNitems = skpN ; maxNitems = mxN ;
itemsCount = 0 ;
if( topstr != null && topstr.length() > 0 ){
     if( selectNodes(topstr, out )== 0 ) return 0 ;
}
if( age != null && age.length() > 0 ){
     if( limitAge( age, out ) == 0 ) return 0 ;
}
char szch ;
if( sz == null || sz.length() == 0 ) szch = 'L' ;
// по умолчанию полная версия
else szch = sz.toUpperCase().charAt(0);
switch( szch ) {
     case 'H' :
doHeadlineNews( out ); break ;
     case 'S' :
doShortNews( out ); break ;
     case 'L' :
     default :
doLongNews(out );
}
return itemsCount ;
}

    Метод doNews, показанный в листинге 8.5, отыскивает сообщение по указанному атрибуту id и форматирует полную версию сообщения. Оставшийся метод класса NewsFormatter предназначен для поддержки двух методов doNews.

Листинг 5. Версия doNews для одного выбранного сообщения (NewsFormatter.java)

// по указанному идентификатору находит сообщение и
// печатает его - всегда в полной версии
public int doNews( PrintWriter out, String hs, String fs, String id ){
     headStr = hs ; footStr = fs ;
     itemsCount = 0 ;
     Node n = null ; //
     for( int i = 0 ; i < itemNodes.length ; i++ ){
n = itemNodes[i]; // узлы <Newsitem
String nid = ((Element)n).getAttribute("id");
if( id.equals( nid )){
     break ;
}
     } /* если не нашлось сообщения с указанным идентификатором id, то будет напечатано самое старое из имеющихся*/
     findNodes((Element) n ); // отыскивает дочерние узлы
// элемента <Newsitem
     doNewsItemLong( out ); // для элемента <Newsitem с
// указанным идентификатором
     return itemsCount ;
}

    Мы решили, что заголовки сообщений всегда будут форматироваться как маркированные списки (unordered lists) HTML. Это очень упрощает метод doHeadlineNews, показанный в листинге 8.6.

Листинг 6. Метод, форматирующий список заголовков новостей (NewsFormatter.java)

// Заголовок всегда форматируется как <UL> со ссылкой
public void doHeadlineNews(PrintWriter out){
out.println( "<ul>" );
for( int i = skipNitems ; i < itemNodes.length ; i++ ){
     if( i >= maxNitems ) break ;
     Node n = itemNodes[i]; // узлы <Newsitem
     String id = ((Element)n).getAttribute("id");
     findNodes((Element) n ); // отыскивает дочерние узлы
// элемента <Newsitem
     out.print("<li><a href=" + handler + "?id=" + id + "&size=L >" );
     out.print( nodeHash.get("head") );
     out.println("</a></li>");
}
out.println("</ul>");
}

    Метод doShort, показанный в листинге 8.7, проверяет наличие заданного по умолчанию шаблона форматирования короткой версии сообщения, а затем выводит эту версию на страницу. Обратите внимание на то, что из каждого элемента (сообщения) извлекается его атрибут id, прежде чем будет вызван метод doNewsItemShort. Этот идентификатор впоследствии присоединяется к каждому элементу, представляющему собой краткую версию, в качестве ссылки на полный текст сообщения.

Листинг 7. Метод doShortNews (NewsFormatter.java)

public void doShortNews(PrintWriter out){
NamedNodeMap attrib = docRoot.getAttributes();
Node n = attrib.getNamedItem( "shorttemplate") ;
String template = null ;
if( n != null ) template = n.getNodeValue();
if( headStr == null && template != null && template.length() > 2 ){
     try {
setFromTemplate( template );
     }catch(IOException ie ){
System.out.println("Unable to read " + template );
     }
}
out.println( headStr );
for( int i = skipNitems ; i < itemNodes.length ; i++ ){
     if( i >= maxNitems ) break ;
     n = itemNodes[i]; // узлы <Newsitem
     String id = ((Element)n).getAttribute("id");
     findNodes((Element) n ); // отыскивает дочерние узлы
// элемента <Newsitem
     doNewsItemShort( out, id );
}
out.println( footStr );
}

    Как показано в листинге 8.8, метод doLongNews проверяет наличие заданного по умолчанию шаблона форматирования полной версии сообщения, после чего выполняет цикл по всем сообщениям в массиве itemNodes.

Листинг 8. Метод doLongNews выводит полный текст сообщения (NewsFormatter.java)

public void doLongNews(PrintWriter out){
NamedNodeMap attrib = docRoot.getAttributes();
Node n = attrib.getNamedItem( "longtemplate");
String template = null ;
if( n != null ) template = n.getNodeValue();
if( headStr == null &&
template != null &&
template.length() > 2 ){
     try {
setFromTemplate( template );
System.out.println("Template set ok " + headStr + footStr );
     }catch(IOException ie ){
System.out.println("Unable to read " + template );
     }
}
out.println( headStr );
for( int i = skipNitems ; i < itemNodes.length ; i++ ){
     if( i >= maxNitems ) break ;
     n = itemNodes[i];
     findNodes((Element) n );
     doNewsItemLong( out );
}
out.println( footStr );
}

    В листинге 8.9 показан метод limitAge, который вызывается всегда, когда в методе doNews присутствует строка, задающая максимально допустимый "возраст" новостей. После проверки корректности целочисленного значения, содержащегося в строке age, этот метод заново компонует массив itemNodes, помещая туда только выбранные сообщения.

Листинг 9. Метод, выбирающий сообщения по дате их создания (NewsFormatter.java)

// накладывает ограничение на "возраст" сообщений -
// допускаются только наиболее свежие новости. Возвращает
// количество допущенных сообщений, это может быть ноль.
private int limitAge(String age, PrintWriter out ){
int days = 100 ;
try {
     days = Integer.parseInt( age );
     if( days <= 0 ) days = 1 ;
}catch(NumberFormatException nfe){
     return itemNodes.length ; // без изменений
}
int today =(int)( System.currentTimeMillis() / ( 24 * 60 * 60 * 1000));
int oldest = today - days ;
Vector v = new Vector( itemNodes.length );
int nidate = today ; // на случай проблем при анализе
int i ;
for( i = 0 ; i < itemNodes.length ; i++ ){
     Node n = itemNodes[i]; // узлы <Newsitem
     String t = ((Element)n).getAttribute("timestamp");
     try { nidate = Integer.parseInt( t );
     }catch(Exception nfe){ // неверный формат числа или
     // пустой указатель
System.out.println( "NewsFormatter.limitAge " + nfe );
     }
if( nidate >= oldest ){
     v.addElement( n );
     }
}
itemNodes = new Node[ v.size() ]; // может быть ноль
for( i = 0 ; i < v.size(); i++ ){
     itemNodes[i] = (Node) v.elementAt(i);
}
return itemNodes.length ;
}

    Причина сложности метода selectNodes заключается в том, что и параметр topics этого метода, задающий выбор тем сообщений, и атрибут topic каждого сообщения могут содержать как одну, так и несколько тем, разделенных запятыми. Как показано в листинге 8.10, мы строим хэш-таблицу recognize для ускорения распознавания тем.

Форма входа
Календарь новостей
«  Май 2024  »
ПнВтСрЧтПтСбВс
  12345
6789101112
13141516171819
20212223242526
2728293031
Поиск
Друзья сайта
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

| Copyright MyCorp © 2024 | Используются технологии uCoz |
<