Java côté serveur: utilisation conjointe de XML et de JSP

Aux fins de cet article, je vais supposer que vous savez ce que sont les pages JavaServer (JSP) et le langage de balisage extensible (XML), mais vous ne savez peut-être pas comment les utiliser. L'utilisation de JSP est assez facile à défendre. Il vous permet de concevoir un site Web construit à partir de fichiers qui ressemblent et agissent beaucoup comme du HTML. La seule différence est que les JSP agissent également de manière dynamique - par exemple, ils peuvent traiter des formulaires ou lire des bases de données - en utilisant Java comme langage de script côté serveur. L'utilisation de XML est plus difficile à justifier. Bien qu'il semble que chaque nouveau produit le prenne en charge, chacun semble utiliser XML dans un but différent.

Dans cet article, vous apprendrez à concevoir un système utilisant XML de manière assez modeste. De nombreux sites Web disposent de vastes collections de données qui s'affichent de manière plus ou moins standard. Je vais concevoir un système qui utilise des fichiers XML pour stocker des données sur un serveur Web et des fichiers JSP pour afficher ces données.

XML contre bases de données relationnelles

«Mais attendez», vous demandez-vous, «vous utilisez XML pour stocker des données? Pourquoi ne pas utiliser une base de données? Bonne question. La réponse est que pour de nombreuses raisons, une base de données est exagérée. Pour utiliser une base de données, vous devez installer et prendre en charge un processus serveur distinct, ce qui nécessite souvent également l'installation et la prise en charge d'un administrateur de base de données. Vous devez apprendre SQL et écrire des requêtes SQL qui convertissent les données d'une structure relationnelle en une structure objet et inversement. Si vous stockez vos données sous forme de fichiers XML, vous perdez la surcharge d'un serveur supplémentaire. Vous bénéficiez également d'un moyen simple de modifier vos données: utilisez simplement un éditeur de texte plutôt qu'un outil de base de données compliqué. Les fichiers XML sont également plus faciles à sauvegarder, à partager avec vos amis ou à télécharger pour vos clients. Vous pouvez également facilement télécharger de nouvelles données sur votre site, en utilisant FTP.

Un avantage plus abstrait de XML est que, étant un format hiérarchique plutôt que relationnel, il peut être utilisé d'une manière beaucoup plus simple pour concevoir des structures de données qui correspondent à vos besoins. Vous n'avez pas besoin d'utiliser un éditeur de relations d'entité ni de normaliser votre schéma. Si vous avez un élément qui contient un autre élément, vous pouvez le représenter directement dans le format, plutôt que d'utiliser une table de jointure.

Notez que pour de nombreuses applications, un système de fichiers ne suffira pas. Si vous avez un volume élevé de mises à jour, un système de fichiers peut être confus ou corrompu par des écritures simultanées; Les bases de données prennent généralement en charge les transactions, ce qui permet la concurrence sans corruption. De plus, une base de données est un excellent outil si vous devez effectuer des requêtes complexes, surtout si elles varient de temps en temps. Les bases de données créent des index et sont optimisées pour maintenir les index à jour avec un ensemble de données en constante évolution. Les bases de données relationnelles présentent également de nombreux autres avantages, notamment un langage de requête riche, des outils de création et de conception de schémas matures, une évolutivité éprouvée, un contrôle d'accès précis, etc.

(Remarque: vous pouvez utiliser un simple verrouillage de fichier pour fournir un serveur de transaction pour un pauvre. Et vous pouvez également implémenter un outil d'indexation et de recherche XML en Java, mais c'est un sujet pour un autre article.)

Dans ce cas, comme dans la plupart des sites Web basés sur la publication à volume faible à moyen, vous pouvez supposer ce qui suit: la plupart des accès aux données sont des lectures, pas des écritures; les données, bien que potentiellement volumineuses, sont relativement stables; vous n'aurez pas besoin de faire des recherches compliquées, mais si vous le faites, vous utiliserez un moteur de recherche distinct. Les avantages de l'utilisation d'un SGBDR mature s'estompent, tandis que l'avantage d'utiliser un modèle de données orienté objet est mis en avant.

Enfin, il est tout à fait possible de fournir un wrapper pour votre base de données qui effectue des requêtes SQL et les traduit en flux XML, de sorte que vous puissiez avoir les deux. XML devient une interface plus robuste et conviviale pour les programmeurs pour une base de données mature pour le stockage et la recherche. (Le servlet XSQL d'Oracle est un exemple de cette technique.)

L'application: un album photo en ligne

Tout le monde aime les photos! Les gens adorent montrer des photos d'eux-mêmes, de leurs amis, de leurs animaux de compagnie et de leurs vacances. Le Web est le moyen ultime pour les punaises auto-indulgentes - elles peuvent agacer leurs proches à des milliers de kilomètres. Alors qu'un site d'album photo à part entière nécessiterait un modèle d'objet compliqué, je me concentrerai sur la définition d'un seul Pictureobjet. (Le code source de cette application est disponible dans Ressources.) L'objet représentant une image a besoin de champs représentant son titre, la date à laquelle elle a été prise, une légende facultative et, évidemment, un pointeur vers la source de l'image.

Une image, à son tour, a besoin de quelques champs qui lui sont propres: l'emplacement du fichier source (un GIF ou un JPEG) et la hauteur et la largeur en pixels (pour vous aider à créer des balises). Ici, il y a un avantage intéressant à utiliser le système de fichiers comme base de données: vous pouvez stocker les fichiers image dans le même répertoire que les fichiers de données.

Enfin, étendons l'enregistrement d'image avec un élément définissant un ensemble d'images miniatures à utiliser dans la table des matières ou ailleurs. Ici, j'utilise le même concept d' image que j'ai défini plus tôt.

La représentation XML d'une image pourrait ressembler à ceci:

 Alex On The Beach 1999-08-08 Essayer en vain de se faire bronzer alex-beach.jpg 340 200 alex-beach-sm.jpg 72 72 alex-beach-med.jpg 150 99    

Notez qu'en utilisant XML, vous mettez toutes les informations sur une seule image dans un seul fichier, plutôt que de les disperser entre trois ou quatre tableaux distincts. Appelons cela un .pixfichier - votre système de fichiers pourrait donc ressembler à ceci:

 été99 / alex-beach.pix été99 / alex-beach.jpg été99 / alex-beach-sm.jpg été99 / alex-beach-med.jpg été99 / alex-snorkeling.pix etc. 

Techniques

Il y a plus d'une façon d'écorcher un chat, et il y a plus d'une façon d'amener des données XML sur votre page JSP. Voici une liste de certains de ces moyens. (Cette liste n'est pas exhaustive; de ​​nombreux autres produits et cadres seraient également utiles.)

  • DOM : vous pouvez utiliser des classes implémentant l'interface DOM pour analyser et inspecter le fichier XML
  • XMLEntryList : vous pouvez utiliser mon code pour charger le XML dans une java.util.Listdes paires nom-valeur
  • XPath : vous pouvez utiliser un processeur XPath (comme Resin) pour localiser les éléments dans le fichier XML par nom de chemin
  • XSL : vous pouvez utiliser un processeur XSL pour transformer le XML en HTML
  • Cocoon : Vous pouvez utiliser le framework open source Cocoon
  • Roll your own bean : vous pouvez écrire une classe wrapper qui utilise l'une des autres techniques pour charger les données dans un JavaBean personnalisé

Notez que ces techniques peuvent être appliquées aussi bien à un flux XML que vous recevez d'une autre source, comme un client ou un serveur d'applications.

Pages JavaServer

La spécification JSP a eu de nombreuses incarnations, et différents produits JSP implémentent différentes versions incompatibles de la spécification. J'utiliserai Tomcat, pour les raisons suivantes:

  • Il prend en charge les versions les plus à jour des spécifications JSP et servlet
  • Il est approuvé par Sun et Apache
  • Vous pouvez l'exécuter de manière autonome sans configurer de serveur Web distinct
  • C'est open source

(Pour plus d'informations sur Tomcat, voir Ressources.)

Vous êtes invités à utiliser n'importe quel moteur JSP que vous aimez, mais le configurer dépend de vous! Assurez-vous que le moteur prend en charge au moins la spécification JSP 1.0; il y a eu de nombreux changements entre 0,91 et 1,0. Le JSWDK (Java Server Web Development Kit) fonctionnera parfaitement.

La structure JSP

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.