Serverseitiges Java: XML und JSP zusammen verwenden

Für den Zweck dieses Artikels gehe ich davon aus, dass Sie wissen, was JavaServer Pages (JSP) und Extensible Markup Language (XML) sind, aber Sie sind sich möglicherweise nicht sicher, wie Sie sie verwenden können. Die Verwendung von JSP ist ziemlich einfach zu verteidigen. Sie können damit eine Website entwerfen, die aus Dateien besteht, die HTML-ähnlich aussehen und sich ähnlich verhalten. Der einzige Unterschied besteht darin, dass JSPs auch dynamisch agieren - beispielsweise können sie Formulare verarbeiten oder Datenbanken lesen - und Java als serverseitige Skriptsprache verwenden. Die Verwendung von XML ist schwieriger zu rechtfertigen. Während es so aussieht, als ob jedes neue Produkt dies unterstützt, scheint jedes XML für einen anderen Zweck zu verwenden.

In diesem Artikel lernen Sie, ein System mit XML auf relativ bescheidene Weise zu entwerfen. Viele Websites verfügen über umfangreiche Datensammlungen, die mehr oder weniger standardmäßig angezeigt werden. Ich werde ein System entwerfen, das XML-Dateien zum Speichern von Daten auf einem Webserver und JSP-Dateien zum Anzeigen dieser Daten verwendet.

XML versus relationale Datenbanken

"Aber warten Sie", fragen Sie sich vielleicht, "Sie verwenden XML zum Speichern von Daten? Warum nicht eine Datenbank verwenden?" Gute Frage. Die Antwort ist, dass eine Datenbank für viele Zwecke übertrieben ist. Um eine Datenbank verwenden zu können, müssen Sie einen separaten Serverprozess installieren und unterstützen, für den häufig auch ein Datenbankadministrator installiert und unterstützt werden muss. Sie müssen SQL lernen und SQL-Abfragen schreiben, die Daten von einer relationalen in eine Objektstruktur und wieder zurück konvertieren. Wenn Sie Ihre Daten als XML-Dateien speichern, verlieren Sie den Overhead eines zusätzlichen Servers. Sie erhalten auch eine einfache Möglichkeit, Ihre Daten zu bearbeiten: Verwenden Sie einfach einen Texteditor anstelle eines komplizierten Datenbank-Tools. XML-Dateien lassen sich auch einfacher sichern, mit Freunden teilen oder auf Ihre Kunden herunterladen. Sie können auch einfach über FTP neue Daten auf Ihre Site hochladen.

Ein abstrakterer Vorteil von XML besteht darin, dass es als hierarchisches und nicht als relationales Format viel einfacher zum Entwerfen von Datenstrukturen verwendet werden kann, die Ihren Anforderungen entsprechen. Sie müssen weder einen Entitätsbeziehungseditor verwenden noch Ihr Schema normalisieren. Wenn Sie ein Element haben, das ein anderes Element enthält, können Sie dieses direkt im Format darstellen, anstatt eine Verknüpfungstabelle zu verwenden.

Beachten Sie, dass für viele Anwendungen ein Dateisystem nicht ausreicht. Wenn Sie eine große Anzahl von Updates haben, kann ein Dateisystem durch gleichzeitiges Schreiben verwirrt oder beschädigt werden. Datenbanken unterstützen normalerweise Transaktionen, die Parallelität ohne Beschädigung ermöglichen. Darüber hinaus ist eine Datenbank ein hervorragendes Werkzeug, wenn Sie komplizierte Abfragen durchführen müssen, insbesondere wenn diese von Zeit zu Zeit variieren. Datenbanken erstellen Indizes und sind optimiert, um die Indizes mit einem sich ständig ändernden Datensatz auf dem neuesten Stand zu halten. Relationale Datenbanken bieten noch viele weitere Vorteile, darunter eine umfangreiche Abfragesprache, ausgereifte Authoring- und Schemadesign-Tools, bewährte Skalierbarkeit, differenzierte Zugriffssteuerung usw.

(Hinweis: Sie können die einfache Dateisperrung verwenden, um den Transaktionsserver eines armen Mannes bereitzustellen. Sie können auch ein XML-Index- und Suchwerkzeug in Java implementieren, dies ist jedoch ein Thema für einen anderen Artikel.)

In diesem Fall können Sie, wie bei den meisten publikationsbasierten Websites mit geringem bis mittlerem Volumen, Folgendes annehmen: Der größte Teil des Datenzugriffs erfolgt durch Lesen und nicht durch Schreiben. Die Daten sind zwar potenziell groß, aber relativ unverändert. Sie müssen keine komplizierten Suchvorgänge durchführen, aber wenn Sie dies tun, verwenden Sie eine separate Suchmaschine. Die Vorteile der Verwendung eines ausgereiften RDBMS verblassen, während der Vorteil der Verwendung eines objektorientierten Datenmodells zum Tragen kommt.

Schließlich ist es durchaus möglich, einen Wrapper für Ihre Datenbank bereitzustellen, der SQL-Abfragen erstellt und diese in XML-Streams übersetzt, sodass Sie beide Möglichkeiten haben. XML wird zu einem robusteren, programmiererfreundlichen Frontend für eine ausgereifte Datenbank zum Speichern und Suchen. (Das XSQL-Servlet von Oracle ist ein Beispiel für diese Technik.)

Die Anwendung: Ein Online-Fotoalbum

Jeder liebt Fotos! Die Leute lieben es, Bilder von sich selbst, ihren Freunden, ihren Haustieren und ihren Ferien zu zeigen. Das Web ist das ultimative Medium für selbstverwöhnte Shutterbugs - sie können ihre Verwandten aus Tausenden von Kilometern Entfernung nerven. Während eine vollwertige Fotoalbum-Site ein kompliziertes Objektmodell erfordern würde, werde ich mich auf die Definition eines einzelnen PictureObjekts konzentrieren. (Der Quellcode für diese Anwendung ist unter Ressourcen verfügbar.) Das Objekt, das ein Bild darstellt, benötigt Felder, die seinen Titel, das Aufnahmedatum, eine optionale Beschriftung und natürlich einen Zeiger auf die Bildquelle darstellen.

Ein Bild benötigt wiederum einige eigene Felder: den Speicherort der Quelldatei (GIF oder JPEG) sowie die Höhe und Breite in Pixel (um Sie beim Erstellen von Tags zu unterstützen). Hier gibt es einen netten Vorteil bei der Verwendung des Dateisystems als Datenbank: Sie können die Bilddateien im selben Verzeichnis wie die Datendateien speichern.

Zum Schluss erweitern wir den Bilddatensatz um ein Element, das eine Reihe von Miniaturbildern definiert, die im Inhaltsverzeichnis oder an anderer Stelle verwendet werden sollen. Hier verwende ich das gleiche Bildkonzept, das ich zuvor definiert habe.

Die XML-Darstellung eines Bildes könnte ungefähr so ​​aussehen:

 Alex On The Beach 08.08.1999 Vergeblich versuchen, eine Bräune zu bekommen alex-beach.jpg 340 200 alex-beach-sm.jpg 72 72 alex-beach-med.jpg 150 99    

Beachten Sie, dass Sie bei Verwendung von XML alle Informationen zu einem einzelnen Bild in eine einzelne Datei einfügen, anstatt sie auf drei oder vier separate Tabellen zu verteilen. Nennen wir dies eine .pixDatei - Ihr Dateisystem könnte also so aussehen:

 sommer99 / alex-beach.pix sommer99 / alex-strand.jpg sommer99 / alex-strand-sm.jpg sommer99 / alex-strand-med.jpg sommer99 / alex-schnorcheln.pix etc. 

Techniken

Es gibt mehr als eine Möglichkeit, eine Katze zu häuten, und es gibt mehr als eine Möglichkeit, XML-Daten auf Ihre JSP-Seite zu bringen. Hier ist eine Liste einiger dieser Möglichkeiten. (Diese Liste ist nicht vollständig. Viele andere Produkte und Frameworks eignen sich gleichermaßen.)

  • DOM : Sie können Klassen verwenden, die die DOM-Schnittstelle implementieren, um die XML-Datei zu analysieren und zu überprüfen
  • XMLEntryList : Sie können meinen Code verwenden, um das XML in ein java.util.ListName-Wert-Paar zu laden
  • XPath : Sie können einen XPath-Prozessor (wie Resin) verwenden, um Elemente in der XML-Datei anhand des Pfadnamens zu suchen
  • XSL : Sie können einen XSL-Prozessor verwenden, um das XML in HTML umzuwandeln
  • Cocoon : Sie können das Open Source Cocoon-Framework verwenden
  • Roll your own bean : Sie können eine Wrapper-Klasse schreiben, die eine der anderen Techniken verwendet, um die Daten in eine benutzerdefinierte JavaBean zu laden

Beachten Sie, dass diese Techniken genauso gut auf einen XML-Stream angewendet werden können, den Sie von einer anderen Quelle wie einem Client oder einem Anwendungsserver erhalten.

JavaServer-Seiten

Die JSP-Spezifikation hatte viele Inkarnationen, und verschiedene JSP-Produkte implementieren unterschiedliche, inkompatible Versionen der Spezifikation. Ich werde Tomcat aus folgenden Gründen verwenden:

  • Es unterstützt die aktuellsten Versionen der JSP- und Servlet-Spezifikationen
  • Es wird von Sun und Apache empfohlen
  • Sie können es eigenständig ausführen, ohne einen separaten Webserver zu konfigurieren
  • Es ist Open Source

(Weitere Informationen zu Tomcat finden Sie unter Ressourcen.)

Sie können gerne jede JSP-Engine verwenden, die Sie mögen, aber die Konfiguration liegt bei Ihnen! Stellen Sie sicher, dass die Engine mindestens die JSP 1.0-Spezifikation unterstützt. Es gab viele Änderungen zwischen 0,91 und 1,0. Das JSWDK (Java Server Web Development Kit) funktioniert einwandfrei.

Die JSP-Struktur

When building a JSP-driven Website (also known as a Webapp), I prefer to put common functions, imports, constants, and variable declarations in a separate file called init.jsp, located in the source code for this article.

I then load that file into each JSP file using . The directive acts like the C language's #include, pulling in the text of the included file (here, init.jsp) and compiling it as if it were part of the including file (here, picture.jsp). By contrast, the tag compiles the file as a separate JSP file and embeds a call to it in the compiled JSP.

Finding the file

When the JSP starts, the first thing it needs to do after initialization is find the XML file you want. How does it know which of the many files you need? The answer is from a CGI parameter. The user will invoke the JSP with the URL picture.jsp?file=summer99/alex-beach.pix (or by passing a file parameter through an HTML form).

However, when the JSP receives the parameter, you're still only halfway there. You still need to know where on the filesystem the root directory lies. For example, on a Unix system, the actual file may be in the directory /home/alex/public_html/pictures/summer99/alex-beach.pix. JSPs do not have a concept of a current directory while executing, so you need to provide an absolute pathname to the java.io package.

The Servlet API provides a method to turn a URL path, relative to the current JSP or Servlet, into an absolute filesystem path. The method ServletContext.getRealPath(String) does the trick. Every JSP has a ServletContext object called application, so the code would be:

String picturefile = application.getRealPath("/" + request.getParameter("file")); 

or

String picturefile = getServletContext().getRealPath("/" + request.getParameter("file")); 

which also works inside a servlet. (You must append a / because the method expects to be passed the results of request.getPathInfo().)

One important note: whenever you access local resources, be very careful to validate the incoming data. A hacker, or a careless user, can send bogus data to hack your site. For instance, consider what would happen if the value file=../../../../etc/passwd were entered. The user could in this way read your server's password file.

The Document Object Model

DOM stands for the Document Object Model. It is a standard API for browsing XML documents, developed by the World Wide Web Consortium (W3C). The interfaces are in package org.w3c.dom and are documented at the W3C site (see Resources).

There are many DOM parser implementations available. I have chosen IBM's XML4J, but you can use any DOM parser. This is because the DOM is a set of interfaces, not classes -- and all DOM parsers must return objects that faithfully implement those interfaces.

Unfortunately, though standard, the DOM has two major flaws:

  1. The API, though object-oriented, is fairly cumbersome.
  2. There is no standard API for a DOM parser, so, while each parser returns a org.w3c.dom.Document object, the means of initializing the parser and loading the file itself is always parser specific.

The simple picture file described above is represented in the DOM by several objects in a tree structure.

Document Node --> Element Node "picture" --> Text Node "\n " (whitespace) --> Element Node "title" --> Text Node "Alex On The Beach" --> Element Node "date" --> ... etc. 

To acquire the value Alex On The Beach you would have to make several method calls, walking the DOM tree. Further, the parser may choose to intersperse any number of whitespace text nodes, through which you would have to loop and either ignore or concatenate (you can correct this by calling the normalize() method). The parser may also include separate nodes for XML entities (like &), CDATA nodes, or other element nodes (for instance, the big bear would turn into at least three nodes, one of which is a b element, containing a text node, containing the text big). There is no method in the DOM to simply say "get me the text value of the title element." In short, walking the DOM is a bit cumbersome. (See the XPath section of this article for an alternative to DOM.)

From a higher perspective, the problem with DOM is that the XML objects are not available directly as Java objects, but they must be accessed piecemeal via the DOM API. See my conclusion for a discussion of Java-XML Data Binding technology, which uses this straight-to-Java approach for accessing XML data.

I have written a small utility class, called DOMUtils, that contains static methods for performing common DOM tasks. For instance, to acquire the text content of the title child element of the root (picture) element, you would write the following code:

Document doc = DOMUtils.xml4jParse(picturefile); Element nodeRoot = doc.getDocumentElement(); Node nodeTitle = DOMUtils.getChild(nodeRoot, "title"); String title = (nodeTitle == null) ? null : DOMUtils.getTextValue(nodeTitle); 

Getting the values for the image subelements is equally straightforward:

Node nodeImage = DOMUtils.getChild(nodeRoot, "image"); Node nodeSrc = DOMUtils.getChild(nodeImage, "src"); String src = DOMUtils.getTextValue(nodeSrc); 

And so on.

Once you have Java variables for each relevant element, all you must do is embed the variables inside your HTML markup, using standard JSP tags.

   

See the full source code for more details. The HTML output produced by the JSP file -- an HTML screenshot, if you will -- is in picture-dom.html.