Сделать стартовой  Добавить в избранное
Воскресенье, 19.05.2024, 15:59
Главная
Регистрация
Вход
Мир софта!
Приветствую Вас Гость | RSS
Mirsoft
Меню сайта
Наш опрос
Какое радио ты любиш?
Всего ответов: 29
Листинг 10. Метод, который выбирает сообщения по указанным темам (NewsFormatter.java)
// в строке topics перечислены темы, разделенные запятыми
// как в атрибуте topics="general,books,java",
// выходные данные используются только для отладки
private int selectNodes(String topics, PrintWriter out ){
Hashtable recognize = new Hashtable();
StringTokenizer st = new StringTokenizer( topics.toUpperCase(), ",");
while( st.hasMoreTokens()){
String tmp = st.nextToken().trim();
recognize.put( tmp,tmp );
}
// теперь можно использовать хэш-таблицу для
// распознавания выбранных тем сообщений
Vector v = new Vector( itemNodes.length );
int i ;
for( i = 0 ; i < itemNodes.length ; i++ ){
     Node n = itemNodes[i]; // узлы <Newsitem
     String t = ((Element)n).getAttribute("topic");
     st = new StringTokenizer(t.toUpperCase(),",");
     while( st.hasMoreElements()){
// Мы просто просматриваем хэш-таблицу, чтобы
// узнать, присутствует ли там данная тема
if( recognize.get( st.nextToken().trim() ) != null ){
     v.addElement(n);
     break;
}
     } // конец цикла while по списку тем
} // конец цикла по всем узлам
// строим новый массив из выбранных узлов
itemNodes = new Node[ v.size() ];
for( i = 0 ; i < v.size(); i++ ){
     itemNodes[i] = (Node) v.elementAt(i);
}
return itemNodes.length ;
}

    Метод findNodes, показанный в листинге 8.11, вызывается для каждого сообщения, которое должно быть помещено на страницу. Входной элемент Element - это узел NewsItem документа XML. Метод findNodes создает переменную nodeHash, которая позволяет другим методам извлекать дочерние элементы NewsItem, например <short>, из коллекции nodeHash. Ключами элементов в этой хэш-таблице являются имена узлов.

Листинг 11. Метод findNodes класса NewsFormatter (NewsFormatter.java)
// поиск узлов, которые содержат текстовые данные
private void findNodes( Element ne ){
NodeList nl = ne.getChildNodes(); // все узлы
int ct = nl.getLength();
nodeHash = new Hashtable( 2 * ct );
for( int i = 0 ; i < ct ; i++ ){
     Node n = nl.item(i);
     if( n instanceof Element ){
nodeHash.put( n.getNodeName(), n );
     }
}
}

    Заголовки и краткая версия сообщения всегда снабжаются ссылкой на полную версию. Эта ссылка встраивается в HTML-страницу с помощью методов doNewsItemHead и doNewsItemShort, как показано в листинге 8.12.

Листинг 12. Методы doNewsItemHead и doNewsItemShort (NewsFormatter.java)
// для <Newsitem > уже создана хэш-таблица
// id - это атрибут
private void doNewsItemHead( PrintWriter out, String id ){
out.print("<a href=" + handler + "?id=" + id + "&size=L >" );
out.print("<h3>"); out.print( nodeHash.get("head") );
out.println("</h3></a>");
out.println();
}
// для <Newsitem > уже создана хэш-таблица
// id - это атрибут
// для форматирования вывода используется <p>..</p>
private void doNewsItemShort( PrintWriter out, String id ){
// отметьте наличие ссылки на полную версию сообщения
out.print("<a href=" + handler + "?id=" + id + "&size=L >" );
out.print("<h3>"); out.print( nodeHash.get("head") );
out.println("</h3></a>");
Element de = (Element)nodeHash.get("date");
out.print( de.getFirstChild() );
out.println("</p>");
Element ne = (Element)nodeHash.get("short");
String wrk = ne.getFirstChild().getNodeValue().trim() ;
if( !(wrk.startsWith("<P") || wrk.startsWith("<p")) ){
out.print("<p>");
}
out.print( wrk );
if( !(wrk.endsWith("/p>") || wrk.endsWith("/P>"))){
out.print("</p>");
}
itemsCount++ ;
out.println();
}

    Как показано в листинге 8.13, метод doNewsItemLong форматирует текст заголовка с помощью тега <h3>. Было бы неплохо усовершенствовать этот метод так, чтобы он допускал возможность изменять указанный формат по мере надобности. Основной текст сообщения форматируется как абзац с помощью тега <p>. Внутри самого текста могут содержаться любые форматирующие теги HTML, но теги <p> всегда будут использоваться для полного текста сообщения.

Листинг 13. Метод doNewsItemLong выводит полную версию сообщения (NewsFormatter.java)
// для элементов <Newsitem > уже созданы хэш-таблицы
// для форматирования вывода полной версии сообщения
// используется <p>..</p>
private void doNewsItemLong( PrintWriter out ){
out.print("<h3>"); out.print( nodeHash.get("head") );
out.println("</h3>");
Element de = (Element)nodeHash.get("date");
out.print( de.getFirstChild() );
out.println("</p>");
Element ne = (Element)nodeHash.get("long");
String wrk = ne.getFirstChild().getNodeValue().trim() ;
if( !(wrk.startsWith("<P") || wrk.startsWith("<p")) ){
out.print("<p>");
}
out.print( wrk );
if( !(wrk.endsWith("/p>") || wrk.endsWith("/P>"))){
out.print("</p>");
}
itemsCount++ ;
out.println();
}

    Наконец, в листинге 8.14 представлены два служебных метода. Метод setFormatTemplate отыскивает файл и считывает его строка за строкой. Предполагается, что в файле имеется строка, начинающаяся с текста "<!-INSERT". Она разделяет разметку HTML на два раздела, которые становятся переменными headStr и footStr. Метод toString предназначен для помощи в отладке.

Листинг 14. Конец исходного кода класса NewsFormatter (NewsFormatter.java)
private void setFromTemplate(String template)
     throws IOException {
     File f = new File( newsFilePath, template );
     FileReader fr = new FileReader( f );
     BufferedReader br = new BufferedReader( fr );
     StringBuffer hsb = new StringBuffer( 100 );
     StringBuffer fsb = new StringBuffer( 100 );
     String tmp = br.readLine(); // убирает символы конца
     //строки
     while( !tmp.startsWith("<!--INSERT" )){
hsb.append( tmp ); fsb.append("\r\n");
tmp = br.readLine();
     }
     tmp = br.readLine();
     while( tmp != null ){
fsb.append( tmp ); fsb.append("\r\n");
tmp = br.readLine();
     }
     headStr = hsb.toString();
     footStr = fsb.toString();
}
public String toString(){
     StringBuffer sb = new StringBuffer("NewsFormatter item ct= ");
     sb.append( Integer.toString( itemNodes.length ));
     return sb.toString() ;
}
}

Использование класса NewsFormatter

    В этом разделе рассматриваются два способа использования класса NewsFormatter: с сервлетом общего назначения TheNewsServ и с JSP-страницами.

Код для сервлета TheNewsServ

    Сервлет TheNewsServ можно использовать для отображения одного сообщения с указанным параметром id или для отображения нескольких сообщений с заданными параметрами topic и age. В листинге 8.15 показаны инструкции импорта и статические переменные. Мы установили значения статических переменных равными заданным по умолчанию, но, разумеется, вам нужно будет заменить их на значения, отражающие ваши фактические настройки.

Листинг 15. Начало исходного кода сервлета TheNewsServ (TheNewsServ)
package com.XmlEcomBook.Chap08 ;
import java.io.*;
import java.util.* ;
import javax.servlet.*;
import javax.servlet.http.*;
public class TheNewsServ extends HttpServlet
{
static String workDir = "E:\\scripts\\CompanyNews" ;
static String newsFile = "thenews.xml" ;
static String handler = "http://localhost/servlet/thenews" ;
static String propfile = "conewserv.properties";
static String version = "v1.0";
static String pversion = "" ;
static Properties cnProp ;
static String brcrlf = "<br />\r\n" ;
static String defaultHead = "<html>\r\n" +
     "<head><title>Company News Servlet</title></head>\r\n" +
     "<body>\r\n" +
     "<h2>Here is the news</h2>\r\n" ;
static String defaultFoot = "</body></html>\r\n";

    Метод init, показанный в листинге 8.16, считывает файл свойств, значения которых могут быть использованы для замены установленных по умолчанию значений статических переменных.

Листинг 16. Метод init класса TheNewsServ (TheNewsServ.java)
public void init(ServletConfig config) throws ServletException
super.init(config);
String tmp = config.getInitParameter("workdir");
if( tmp != null ) workDir = tmp ;
tmp = config.getInitParameter("propfile");
if( tmp != null ) propfile = tmp;
System.out.println("Start TheNewsServ using " + workDir );
File f = new File( workDir, propfile );
try { cnProp = new Properties();
     cnProp.load( new FileInputStream(f) );
     tmp = cnProp.getProperty("thenewshandler");
     if( tmp != null ) handler = tmp ;
     pversion = cnProp.getProperty("version");
     if( pversion != null ){
defaultFoot = "<hr><br>News Servlet " + version
+ " properties: " + pversion + "<br>\r\n" +
"</body>\r\n</html>\r\n" ;
     }
     NewsFormatter.setHandler( handler );
     System.out.println( new Date().toString() +
" Loaded properties for TheNewsServ: " + handler );
}catch(IOException e){
System.out.println("Error loading " + e );
}
}

    Функциональность сервлета сконцентрирована в методе doGet, как видно из листинга 8.17. В запросе можно передать значения параметров, определяющих тему сообщений, максимальный "возраст" сообщений, требуемый способ представления и идентификатор сообщения. Заметим, что создается объект File, соответствующий файлу XML с сообщениями, и передается конструктору NewsFormatter. Использование объекта File гарантирует, что соблюдаются соглашения относительно разделителей для компонентов пути; NewsFormatter не открывает этот файл, но использует его имя при получении объектной модели документа для этого файла из DOMlibrary.

Листинг 17. Метод doGet (TheNewsServ.java)
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
resp.setContentType("text/html");
PrintWriter out = new PrintWriter(resp.getOutputStream());
String topics = req.getParameter("topic");
String ageStr = req.getParameter("days");
String len = req.getParameter("size" ); // "S","H" или "L"
String id = req.getParameter("id"); // запрашивается одно
// сообщение
try {
     File f = new File( workDir, newsFile );
     NewsFormatter nf = new NewsFormatter( f );
     if( id != null ){
nf.doNews( out, defaultHead,defaultFoot, id );
     }
     else {
// PrintWriter, head, foot, topics, H,S или L, age,
// skip#, mx#
nf.doNews( out, defaultHead, defaultFoot, topics, len, ageStr,0, 10 );
     }
     out.close();
}catch(Exception e){
     System.err.println("TheNewsServ.doGet " + e );
     errorMsg( out, "TheNewsServ.doGet", e );
}
}

    Обратите внимание, что конструкция try-catch в методе doGet направляет все исключения методу errorMsg, показанному в листинге 8.18. Разумеется, вам следует вставить свой адрес электронной почты в текст сообщения либо текст этого сообщения может состоять из специальной строки, которая задается в файле свойств. Методы header и footer просто выписывают стандартные теги HTML.

Листинг 18. Методы errorMsg, Header и Footer (TheNewsServ.java)
// предполагается, что ответ задан как text/html
private void errorMsg( PrintWriter out, String msg, Exception ex ){
header( out );
out.println("<h2>Error: " ); out.println( msg );
out.println("</h2><br>");
if( ex != null ){
     ex.printStackTrace( out );
}
out.println("<br>");
out.println("<a href=\"mailto:wbrogden@bga.com\">Please
     mail me" + " the error message.</a><br>");
footer( out );
}
private void header(PrintWriter out ){
out.println("<html>");
out.println("<head><title>Company News Servlet</title></head>");
out.println("<body>");
}
private void footer(PrintWriter out ){
     out.println("<hr><br>Company News Servlet " + version + " properties: <br>" );
     out.println("</body>");
     out.println("</html>");
     out.close();
}
}
Пример JSP-страницы

    Для рассматриваемого нами примера JSP-страницы новостей ее основной формой является таблица с тремя столбцами. Чтобы уменьшить размер листинга, мы предельно сократили эту страницу; на реальной странице, разумеется, содержится гораздо больше сообщений, связанных с фирмой.
    Привлекательность JSP-страниц объясняется как раз простотой включения выходных данных Java в разметку HTML. В листинге 8.19 показано начало JSP-страницы, где создается первая строка таблицы.

Листинг 19. Первая часть упрощенной JSP-страницы для отображения новостей (mockup.jsp)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>The XMLGifts News </title>
</head>
<body bgcolor="#FFFFFF">
<%@ page language="java"
import="com.XmlEcomBook.Chap08.NewsFormatter,java.io.*" %>
<%!
String newsFilePath = "e:\\scripts\\CompanyNews" ;
String newsFileName = "thenews.xml" ;
String newsHandler =
"http://localhost:8080/XMLbook/Chap08/thenews.jsp" ;
File newsFile = new File( newsFilePath, newsFileName );
public void jspInit(){
     super.jspInit();
     NewsFormatter.setHandler( newsHandler );
}
%>
<table width="89%" border="0" align="left" cellpadding="8">
<tr align="center" bgcolor="cyan">
     <td colspan="3"><font size="4">
Various Corporate Navigation Links Go Here</font>
     </td>
</tr>

    Чтобы не усложнять пример, мы жестко запрограммировали тему сообщений - музыкальные компакт-диски (листинг 8.20). Первый раз объект NewsFormatter используется для создания левого столбца таблицы, где расположены заголовки сообщений. Это делается в первую очередь, так как, когда тематика сообщений задана, объект NewsFormatter будет содержать только данные по сообщениям, соответствующим выбранной тематике.

Листинг 20. Продолжение JSP-страницы с выходными данными NewsFormatter (mockup.java)
<!-- объекты nf и pw будут использоваться для всех трех td -->
<tr valign="TOP" ><font size="3">
<td><b>News Headlines</b><br>
<%
// для выбора темы можно использовать специальную форму
String topic = "CDs" ;
NewsFormatter nf = new NewsFormatter( newsFile );
     PrintWriter pw = new PrintWriter( out );
/* Напоминаем сигнатуру метода doNews
     doNews( PrintWriter out, String hs, String fs,
String topstr, String sz, String age,
int skpN, int mxN ) */
     // заголовки - все темы
     nf.doNews( pw, "","", "", "H", null, 0, 8 );
%>
     </td>
     <td width="50%">
<%
     nf.doNews( pw, "","", topic, "L", null, 0, 1 );
%>
     </td>
     <!- столбец с краткими версиями сообщений -->
     <td width="23%">
<%= "<b>Recent news items about " + topic + "</b><br>" %>
<%
    /* Напоминаем сигнатуру метода doNews
     doNews( PrintWriter out, String hs, String fs,
String topstr, String sz, String age,
int skpN, int mxN ) */
     nf.doNews( pw, "","", topic, "S", null, 1, 8 );
%>
     </td>
     </font>
</tr>
<tr align="center" bgcolor="cyan">
     <td colspan="3"><font size="4" >
     Repeat the Navigation links here for convenience<br></font>
     </td>
</tr>
<tr>
     <td colspan="3" align='center'><font face='arial, helvetica' size='3'>
©2000 XMLGifts.com<sup>SM</sup>
     <br /></font>
     </td>
</tr>
</table>
</body>
</html>

Добавление свежих новостей

    Важной особенностью этого приложения является возможность добавления новых сообщений без нарушения нормальной работы web-сайта. Эту функцию иллюстрирует верхний правый угол рис. 8.1. Вместо того чтобы модифицировать DOM в памяти сервера, сервлет CompanyNewsServ записывает модифицированную версию исходного файла XML на диск. Этот обновленный файл сообщений будет автоматически загружен в очередной раз при вызове DOM из библиотеки DOMlibrary.

Сервлет CompanyNewsServ

    Форма HTML для обновления страницы новостей создается и управляется сервлетом CompanyNewsServlet. Начальный вход в сервлет осуществляется с помощью HTML-страницы, в которой имеется обычная форма HTML для ввода имени автора и пароля. Пример такой страницы представлен в файле CoNewsUpdate.html, который находится на прилагаемом к книге компакт-диске. Сервлет отыскивает имя автора в файле свойств, проверяя таким образом, что этот человек имеет право на добавление новых сообщений.
    В листинге 8.21 показан файл свойств для работы на сервере localhost. Заметим, что имя автора является именем свойства, а пароль - его значением.

Листинг 21. Файл свойств, используемый сервлетом CompanyNewsServ (conewserv.properties)
# properties for CompanyNewsServ
handler=http://localhost/servlet/conewserv
thenewshandler=http://localhost/servlet/thenews
newsfile=thenews.xml
version=June 15, 2000
wbrogden=xmlrules

    В листинге 8.22 показаны инструкции импорта, статические переменные и метод init для сервлета CompanyNewsServ.

Листинг 22. Начало кода метода CompanyNewsServ (ComanyNewsServ.java)
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 CompanyNewsServ extends HttpServlet
{
static String workDir = "E:\\scripts\\CompanyNews" ;
static String propfile = "conewserv.properties" ;
static String newsFile = "thenews.xml" ;
static String handler = "http://localhost/servlet/conewserv" ;
static String version = "v0.12";
static String pversion = "" ;
static Properties cnProp ;
static String brcrlf = "<br />\r\n" ;
public void init(ServletConfig config) throws ServletException
{
     super.init(config);
     String tmp = config.getInitParameter("workdir");
     if( tmp != null ) workDir = tmp ;
     tmp = config.getInitParameter("propfile");
     if( tmp != null ) propfile = tmp ;
     System.out.println("Start CompanyNewsServ using " + workDir );
     File f = new File( workDir, propfile );
     try { cnProp = new Properties();
cnProp.load( new FileInputStream(f) );
tmp = cnProp.getProperty("handler");
if( tmp != null ) handler = tmp ;
tmp = cnProp.getProperty("newsfile");
if( tmp != null ) newsFile = tmp ;
pversion = cnProp.getProperty("version");
System.out.println("Loaded properties for
     CompanyNewsServ: " + handler + " file:" + newsFile );
     }catch(IOException e){
System.out.println("Error loading " + e );
     }
}

    Метод doGet, как показано в листинге 8.23, проверяет введенные пользователем имя и пароль, сравнивая их с данными в файле свойств, загруженном при инициализации сервлета. Если обнаруживается, что имя соответствует паролю, вызывается метод generateForm, создающий форму HTML для ввода текста нового сообщения.

Листинг 23. Метод doGet создает форму для ввода нового сообщения (CompanyNewsServ.java)
public void doGet(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException
{
resp.setContentType("text/html");
PrintWriter out = new PrintWriter(resp.getOutputStream());
String username = req.getParameter("username");
String password = req.getParameter("password");
String action = req.getParameter("action");
String tmp = cnProp.getProperty(username);
boolean userok = false ;
if( tmp != null ){
     userok = tmp.equals( password );
}
header( out );
if( userok ){
     generateForm( out, username, password );
}
else {
     out.println("<p>User: " + username + " password: " + password + " not found.</p>" );
}
footer( out );

    Заполненная форма посылается методу doPost. Как показано в листинге 8.24, различные текстовые элементы извлекаются и передаются объекту NewsUpKeep с помощью метода addItem.

Листинг 24. Метод doPost собирает данные из формы (CompanyNewsServ.java)
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
resp.setContentType("text/html");
PrintWriter out = new PrintWriter(resp.getOutputStream());
String username = req.getParameter("username");
String password = req.getParameter("password");
String action = req.getParameter("action");
String head = req.getParameter("head");
String date = req.getParameter("date");
String topics = req.getParameter("topics");
String shrtStr = req.getParameter("short").trim();
String longStr = req.getParameter("long").trim();
DOMlibrary library = DOMlibrary.getLibrary();
File f = new File( workDir, newsFile );
try {
     NewsUpKeep nup = new NewsUpKeep( f );
     nup.addItem( head, date, topics, username, shrtStr, longStr );
     header( out );
     out.println("NewsUpKeep is " + nup + "<br />");
     footer( out );
}catch( Exception e){
errorMsg( out, "CompanyNewsServ.doPost ", e );
}
}

    Форма HTML для ввода новых сообщений создается методом generateForm, как показано в листинге 8.25. Заметим, что имя пользователя и пароль вставлены в форму в виде скрытых значений.

Листинг 25. Метод generateForm создает форму для ввода (CompanyNewsServ.java)
private void generateForm( PrintWriter out, String name, String pw ){
out.println("<h2>Enter Company News Item Data</h2>");
out.println("<form method=\"POST\" action= \"" + handler + "\" >");
out.println("Headline - 80 char max<br />");
out.println("<input type=\"text\" maxlength=\"80\" size=
     \"60\"" + " name=\"head\" ><br />" );
out.println("Dated <br />");
out.println("<input type=\"text\" maxlength=\"50\" size=
     \"40\"" + " name=\"date\" value=
     \"" + new Date().toString() + "\" ><br />" );
out.println(
"Topics separated by commas - please stick to the official list.<br />");
out.println("<input type=\"text\" maxlength=\"80\" size=
     \"60\"" + " name=\"topics\" ><br />" );
out.println("Short version <br />");
out.println("<textarea cols=\"60\" rows=\"3\" name=
     \"short\" >");
out.println("</textarea><br />");
out.println("Long version <br />");
out.println("<textarea cols=\"60\" rows=\"10\" name=\"long\" >");
out.println("</textarea><br />");
out.println("<input type=\"hidden\" name=\"username\" value=
     \"" + name + "\"><br>" );
out.println("<input type=\"hidden\" name=\"password\" value=
     \"" + pw + "\" ><br>");
out.println(
     "<input type=\"submit\" name=\"action\" value=
\"Submit\" ><br />" );
out.println("</form></center>");
}

    Наконец, в сервлете имеются обычные вспомогательные методы, показанные в листинге 8.26. Естественно, вам нужно будет заменить адрес в тексте сообщения на свой собственный либо предоставить переменную типа String, которая инициализируется в файле свойств.

Листинг 26. Служебные методы в сервлете CompanyNewsServ (CompanyNewsServ.java)
// предполагается, что ответ был задан как text/html
private void errorMsg( PrintWriter out, String msg, Exception ex ){
     header( out );
     out.println("<h2>Error: " ); out.println( msg );
     out.println("</h2><br>");
     if( ex != null ){
ex.printStackTrace( out );
     }
     out.println("<br>");
     out.println("<a href=\"mailto:wbrogden@bga.com\">" +
"Please mail me the error message.</a><br>");
     footer( out );
}
private void header(PrintWriter out ){
     out.println("<html>");
     out.println("<head><title>Company News
Servlet</title></head>");
     out.println("<body>");
}
private void footer(PrintWriter out ){
     out.println("<hr><br>Company News Servlet " + version +
" properties: <br>" );
     out.println("</body>");
     out.println("</html>");
     out.close();
}
}
Форма входа
Календарь новостей
«  Май 2024  »
ПнВтСрЧтПтСбВс
  12345
6789101112
13141516171819
20212223242526
2728293031
Поиск
Друзья сайта
Статистика

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

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