Programmering

Server-side Java: Brug af XML og JSP sammen

Med henblik på denne artikel antager jeg, at du ved, hvad JavaServer Pages (JSP) og Extensible Markup Language (XML) er, men du kan være lidt uklar om, hvordan du kan bruge dem. JSP-brug er ret let at forsvare. Det giver dig mulighed for at designe et websted bygget fra filer, der ligner og fungerer meget som HTML. Den eneste forskel er, at JSP'er også handler dynamisk - for eksempel kan de behandle formularer eller læse databaser - ved hjælp af Java som serversprog til serversiden. XML-brug er sværere at retfærdiggøre. Mens det ser ud til, at hvert nyt produkt understøtter det, ser det ud til, at de bruger XML til et andet formål.

I denne artikel lærer du at designe et system ved hjælp af XML på en ret beskeden måde. Mange websteder har enorme samlinger af data, der vises på en mere eller mindre standard måde. Jeg vil designe et system, der bruger XML-filer til at gemme data på en webserver og JSP-filer til at vise disse data.

XML versus relationsdatabaser

"Men vent," spørger du måske, "du bruger XML til at gemme data? Hvorfor ikke bruge en database?" Godt spørgsmål. Svaret er, at en database til mange formål er overdreven. For at bruge en database skal du installere og understøtte en separat serverproces, som ofte også kræver installation og support af en databaseadministrator. Du skal lære SQL og skrive SQL-forespørgsler, der konverterer data fra en relation til en objektstruktur og tilbage igen. Hvis du gemmer dine data som XML-filer, mister du omkostningerne på en ekstra server. Du får også en nem måde at redigere dine data på: brug bare en teksteditor snarere end et kompliceret databaseværktøj. XML-filer er også nemmere at sikkerhedskopiere, dele med dine venner eller downloade til dine kunder. Du kan også nemt uploade nye data til dit websted ved hjælp af FTP.

En mere abstrakt fordel ved XML er, at det er et hierarkisk snarere end et relationelt format og kan bruges på en meget mere ligetil måde til at designe datastrukturer, der passer til dine behov. Du behøver ikke at bruge en enhedsrelationseditor eller normalisere dit skema. Hvis du har et element, der indeholder et andet element, kan du repræsentere det direkte i formatet i stedet for at bruge en sammenføjningstabel.

Bemærk, at et filsystem for mange applikationer ikke er tilstrækkeligt. Hvis du har et stort antal opdateringer, kan et filsystem blive forvirret eller ødelagt af samtidige skrivninger; databaser understøtter normalt transaktioner, som tillader samtidighed uden korruption. Desuden er en database et fremragende værktøj, hvis du har brug for at lave komplicerede forespørgsler, især hvis de vil variere fra tid til anden. Databaser bygger indekser og er optimeret til at holde indekserne opdaterede med et konstant skiftende datasæt. Relationsdatabaser har også mange andre fordele, herunder et rigt forespørgselssprog, modne redigerings- og skemadesignværktøjer, dokumenteret skalerbarhed, finkornet adgangskontrol osv.

(Bemærk: Du kan bruge simpel fillåsning til at levere en fattig mands transaktionsserver. Og du kan også implementere et XML-indeks-og-søgeværktøj i Java, men det er et emne for en anden artikel.)

I dette tilfælde kan du, som i de fleste publiceringsbaserede websteder med lavt til medium volumen, antage følgende: det meste af dataadgangen er læsning, ikke skrivning; dataene, selvom de potentielt er store, er relativt uændrede; du behøver ikke foretage komplicerede søgninger, men hvis du gør det, skal du bruge en separat søgemaskine. Fordelene ved at bruge en moden RDBMS falmer, mens fordelen ved at bruge en objektorienteret datamodel kommer frem.

Endelig er det fuldt ud muligt at levere en indpakning til din database, der foretager SQL-forespørgsler og oversætter dem til XML-streams, så du kan have det begge veje. XML bliver en mere robust, programmørvenlig frontend til en moden database til lagring og søgning. (Oracles XSQL-servlet er et eksempel på denne teknik.)

Ansøgningen: Et online fotoalbum

Alle elsker fotos! Folk elsker at vise billeder af sig selv, deres venner, deres kæledyr og deres ferier. Internettet er det ultimative medium for selvoverbærende lukkerbugs - de kan irritere deres slægtninge tusinder af miles væk. Mens et fuldt udbygget fotoalbumside kræver en kompliceret objektmodel, vil jeg fokusere på at definere en enkelt Billede objekt. (Kildekoden til denne applikation er tilgængelig i Ressourcer.) Objektet, der repræsenterer et billede, har brug for felter, der repræsenterer dets titel, datoen det blev taget, en valgfri billedtekst og naturligvis en markør til billedkilden.

Et billede har til gengæld brug for et par egne felter: kildefilens placering (en GIF eller JPEG) og højden og bredden i pixels (for at hjælpe dig med at bygge tags). Her er der en pæn fordel ved at bruge filsystemet som din database: du kan gemme billedfilerne i samme bibliotek som datafilerne.

Lad os endelig udvide billedoptagelsen med et element, der definerer et sæt miniaturebilleder til brug i indholdsfortegnelsen eller andre steder. Her bruger jeg det samme koncept af billede Jeg definerede tidligere.

XML-repræsentationen af ​​et billede kan se sådan ud:

 Alex On The Beach 1999-08-08 Forsøger forgæves at få en tan alex-beach.jpg 340 200 alex-beach-sm.jpg 72 72 alex-beach-med.jpg 150 99 

Bemærk, at ved at bruge XML placerer du alle oplysninger om et enkelt billede i en enkelt fil i stedet for at sprede det mellem tre eller fire separate tabeller. Lad os kalde dette en .pix fil - så dit filsystem kan se sådan ud:

 summer99 / alex-beach.pix summer99 / alex-beach.jpg summer99 / alex-beach-sm.jpg summer99 / alex-beach-med.jpg summer99 / alex-snorkeling.pix osv. 

Teknikker

Der er mere end en måde at flå en kat på, og der er mere end en måde at bringe XML-data på din JSP-side. Her er en liste over nogle af disse måder. (Denne liste er ikke udtømmende; mange andre produkter og rammer vil tjene lige så godt.)

  • DOM: Du kan bruge klasser, der implementerer DOM-grænsefladen til at analysere og inspicere XML-filen
  • XMLEntryList: Du kan bruge min kode til at indlæse XML i en java.util.Liste af navn-værdi-par
  • XPath: Du kan bruge en XPath-processor (som Resin) til at finde elementer i XML-filen efter stienavn
  • XSL: Du kan bruge en XSL-processor til at omdanne XML til HTML
  • Kokon: Du kan bruge open source Cocoon framework
  • Rul din egen bønne: Du kan skrive en indpakningsklasse, der bruger en af ​​de andre teknikker til at indlæse dataene i en brugerdefineret JavaBean

Bemærk, at disse teknikker kan anvendes lige så godt til en XML-stream, du modtager fra en anden kilde, såsom en klient eller en applikationsserver.

JavaServer-sider

JSP-spec har haft mange inkarnationer, og forskellige JSP-produkter implementerer forskellige, inkompatible versioner af spec. Jeg vil bruge Tomcat af følgende grunde:

  • Det understøtter de mest opdaterede versioner af JSP- og servlet-specifikationerne
  • Det er godkendt af Sun og Apache
  • Du kan køre den enkeltstående uden at konfigurere en separat webserver
  • Det er open source

(For mere information om Tomcat, se Ressourcer.)

Du er velkommen til at bruge enhver JSP-motor, du kan lide, men det er op til dig at konfigurere den! Sørg for, at motoren understøtter mindst JSP 1.0-specifikationen; der var mange ændringer mellem 0,91 og 1,0. JSWDK (Java Server Web Development Kit) fungerer fint.

JSP-strukturen

Når du bygger et JSP-drevet websted (også kendt som en Webapp), Jeg foretrækker at lægge almindelige funktioner, import, konstanter og variable erklæringer i en separat fil kaldet init.jsp, placeret i kildekoden til denne artikel.

Jeg indlæser derefter filen i hver JSP-fil ved hjælp af . Det Direktiv fungerer som C-sprog #omfatte, trækker i teksten i den inkluderede fil (her, init.jsp) og kompilere det som om det var en del af den inklusive fil (her, billede.jsp). I modsætning hertil tag kompilerer filen som en separat JSP-fil og integrerer et opkald til den i den kompilerede JSP.

Find filen

Når JSP starter, er den første ting, den skal gøre efter initialisering, finde den XML-fil, du ønsker. Hvordan ved det, hvilken af ​​de mange filer du har brug for? Svaret er fra en CGI-parameter. Brugeren påkalder JSP med URL'en picture.jsp? file = summer99 / alex-beach.pix (eller ved at passere en fil parameter gennem en HTML-formular).

Men når JSP modtager parameteren, er du stadig kun halvvejs der. Du skal stadig vide, hvor rodmappen ligger på filsystemet. For eksempel på et Unix-system kan den faktiske fil være i biblioteket /home/alex/public_html/pictures/summer99/alex-beach.pix. JSP'er har ikke et koncept for en aktuel mappe under udførelse, så du skal angive et absolut sti til java.io pakke.

Servlet API giver en metode til at omdanne en URL-sti i forhold til den nuværende JSP eller Servlet til en absolut filsystemsti. Metoden ServletContext.getRealPath (streng) gør tricket. Hver JSP har en ServletContext objekt kaldes Ansøgning, så koden ville være:

Streng billedfil = application.getRealPath ("/" + anmodning.getParameter ("fil")); 

eller

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

som også fungerer inde i en servlet. (Du skal tilføje en / fordi metoden forventer at blive bestået resultaterne af request.getPathInfo ().)

En vigtig note: Når du får adgang til lokale ressourcer, skal du være meget forsigtig med at validere de indgående data. En hacker eller en skødesløs bruger kan sende falske data for at hacke dit websted. Overvej f.eks. Hvad der ville ske, hvis værdien fil = .. / .. / .. / .. / etc / passwd blev indtastet. Brugeren kunne på denne måde læse din servers adgangskodefil.

Dokumentobjektmodellen

DOM står for Dokumentobjektmodel. Det er en standard API til gennemsøgning af XML-dokumenter, udviklet af World Wide Web Consortium (W3C). Grænsefladerne er i pakken org.w3c.dom og er dokumenteret på W3C-webstedet (se Ressourcer).

Der er mange DOM-parserimplementeringer tilgængelige. Jeg har valgt IBMs XML4J, men du kan bruge enhver DOM-parser. Dette skyldes, at DOM er et sæt grænseflader, ikke klasser - og alle DOM-parsere skal returnere objekter, der trofast implementerer disse grænseflader.

Desværre, selvom standard, har DOM to store fejl:

  1. API'en, selvom den er objektorienteret, er ret besværlig.
  2. Der er ingen standard API til en DOM-parser, så mens hver parser returnerer en org.w3c.dom.Document objekt, middel til initialisering af parser og indlæsning af selve filen er altid parserspecifik.

Den enkle billedfil beskrevet ovenfor er repræsenteret i DOM af flere objekter i en træstruktur.

Dokumentknude -> Elementknude "billede" -> Tekstknude "\ n" (hvidt mellemrum) -> Elementknude "titel" -> Tekstknude "Alex On The Beach" -> Elementknude "dato" - -> ... osv. 

At erhverve værdien Alex On The Beach du bliver nødt til at foretage flere metodeopkald, gå DOM-træet. Desuden kan parseren vælge at sprede et vilkårligt antal hvide mellemrums tekstnoder, hvorigennem du bliver nødt til at løkke og enten ignorere eller sammenkæde (du kan rette dette ved at kalde normaliser () metode). Parseren kan også omfatte separate noder til XML-enheder (som f.eks &), CDATA-noder eller andre element-noder (f.eks. det stor bjørn ville blive til mindst tre noder, hvoraf den ene er en b element, der indeholder en tekstknude, der indeholder teksten stor). Der er ingen metode i DOM til simpelthen at sige "skaf mig tekstværdien af ​​titelelementet." Kort sagt, at gå DOM er lidt besværligt. (Se XPath-sektionen i denne artikel for et alternativ til DOM.)

Fra et højere perspektiv er problemet med DOM, at XML-objekterne ikke er tilgængelige direkte som Java-objekter, men de skal åbnes stykkevis via DOM API. Se min konklusion for en diskussion af Java-XML Data Binding-teknologi, der bruger denne direkte til Java-tilgang til adgang til XML-data.

Jeg har skrevet en lille hjælpeklasse, kaldet DOMUtils, der indeholder statiske metoder til udførelse af almindelige DOM-opgaver. For eksempel at erhverve tekstindholdet i titel underordnet element af roden (billede) -element, ville du skrive følgende kode:

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

At få værdierne for billedunderelementerne er lige så ligetil:

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

Og så videre.

Når du har Java-variabler for hvert relevant element, skal du blot integrere variablerne i din HTML-markering ved hjælp af standard JSP-tags.

Se den fulde kildekode for flere detaljer. HTML-output produceret af JSP-filen - hvis det er et HTML-skærmbillede - er i billede-dom.html.