Dynamische webapplicaties in Java October 7, 2006 In java is het mogelijk dynamische webpagina’s te implementeren. De code om de dynamische gegevens te genereren staat in servlets of Java Server Pages (JSP). Deze tekst geeft een korte inleiding zowel servlets als JSP. Verder wordt ook nog ingegaan op hoe deze dynamische applicatie geconfigureerd wordt in de web deployment descriptor en wordt ingegaan op het gedeelde geheugen waar verschillende JSP pagina’s of servlets objecten kunnen delen.
1
Servlets
Servlets zijn klassen die de javax.servlet.Servlet interface implementeren. Wanneer een gebruiker van de webapplicatie een aanvraag stuurt voor een servlet, zal een methode van een object van deze klasse opgeroepen worden. Die methode genereert een antwoord dat teruggestuurd wordt naar de gebruiker. Indien het de bedoeling is servlets te maken die werken via het HTTPprotocol is het niet nodig de Servlet-interface volledig zelf te implementeren. Java voorziet de klasse javax.servlet.http.HttpServlet. Deze implementeert de Servlet-interface en biedt enkele extra HTTP-specifieke methodes aan die het mogelijk maken op zeer eenvoudige manier de servlets te maken. Vaak is het voldoende enkel de doGet-methode, de doPost-methode en de init-methode opnieuw te defini¨eren. Deze worden opgeroepen wanneer de server een HTTPaanvraag met het get-commando ontvangt voor die bepaalde servlet, wanneer de server een HTTP-aanvraag met het post-commando aankrijgt en wanneer de servlet aangemaakt wordt. Een zeer eenvoudig voorbeeld van een servlet is te vinden in figuur 1. Elke servlet van een webapplicatie zal maar ´e´en keer ge¨ınstantieerd worden. De init-methode wordt dan ook slechts ´e´en keer opgeroepen. Alle gebruikers van de applicatie zullen dit servlet-object gebruiken. Dit beperkt het geheugengebruik van de applicatie. Het zorgt er wel voor dat een servlet geen toestandsinformatie in verband met ´e´en bepaalde gebruiker kan bijhouden. Het is mogelijk verschillende servlets na elkaar te laten uitvoeren. Op die manier wordt er een keten van servlets gecre¨eerd die samen een aanvraag afwerken. De functionaliteit wordt dus verspreid over verschillende servlets. Om de controle naar een andere servlet te laten gaan wordt gebruik van een requestdispatcher. Deze roept de andere servlet effectief op.
1
public class HelloServlet extends HttpServlet { public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Met volgende zin wordt de writer om naar //de client te schrijven opgevraagd. PrintWriter out = response.getWriter(); out.println("Hello, world!"); out.close(); } } Figure 1: Hello World servlet
<TITLE>JSP pagina! <jsp:include page="header.html" />
Uitslag:
<% double rand = Math.random(); if (rand < .5) { out.println("U wint!"); } else { out.println("U verliest!"); } %> Figure 2: Hello World JSP-pagina
2
<servlet> <servlet-name>Hello <servlet-class>app.HelloServlet <servlet-mapping> <servlet-name>Hello
/hello Figure 3: Servlet- en Filter-mappings
2
JavaServer Pages
Servlets zijn een grote hulp bij het cre¨eren van dynamische webapplicaties, maar zijn minder geschikt om de HTML-opmaak van het antwoord te genereren. Hiervoor moet voor elke uitvoer een uitvoercommando gebruikt worden. Om dit te vereenvoudigen is er de JSP-technologie. Een JSP-pagina bestaat uit gewone HTML-opmaak, die het statische deel van de pagina voorstelt. Tussen de HTML-tags bevinden zich scriptlets en JSP-tags. Deze verzorgen het dynamische gedeelte. Met scriptlets is het mogelijk om Java-code rechtstreeks in het JSP-bestand te zetten. Scriptlets zijn niet heel gebruiksvriendelijk. Als pagina’s eenzelfde scriptlet willen gebruiken, moeten ze allemaal de volledige code hiervan bevatten. Een scriptlet die vele lijnen code omvat, zal de structuur van de HTMLopmaak onduidelijk maken. Een derde nadeel is dat scriptlets best gemaakt kunnen worden door Java-programmeurs en de opmaak door designers. Hierdoor moeten beiden in hetzelfde bestand werken, wat tot problemen kan leiden. Het is dus beter de scriptlets uit de JSP-pagina te halen. Dit kan door het gebruik van JSP-tags. Deze gebruiken eenzelfde syntax als HTML en stellen een bepaalde dynamische actie voor, zoals het tonen van een eigenschap van een object. Wat zo’n tag effectief doet, wordt gedefinieerd in een tag library. Hierin staat de code die uitgevoerd moet worden indien een bepaalde tag in een JSP-pagina staat. Sun voorziet de JavaServer Pages Standard Tag Library (JSTL). Deze tag library bevat zeer veel tags die webapplicaties vaak gebruiken. Een voorbeeld van een zeer eenvoudige JSP-pagina is te vinden in figuur 2. In dit voorbeeld staat er eerst een JSP-tag die een pagina invoegt. Daarna volgt een scriptlet die op basis van een willekeurig getal een bepaalde zin toont. Tussen de dynamische inhoud door is het ook mogelijk statische inhoud weer te geven. Bij het ophalen van een JSP-pagina wordt de gelijkenis met servlets duidelijk. Bij de eerste oproep zal de web container de code van de pagina vertalen naar een servlet-klasse. Daarna wordt de JSP-pagina als servlet uitgevoerd.
3
3
De web deployment descriptor
Om correct te kunnen werken zal elke webapplicatie een web deployment descriptor bevatten. Dit is een XML-bestand dat de configuratie van de webapplicatie bevat. Hierin is het mogelijk om te defini¨eren welke servlet-mappings er zijn, aan te geven welke foutmeldingen getoond moeten worden en te zeggen welke gegevensbanken gebruikt moeten worden. Servlet-mappings zijn ´e´en van de belangrijkste elementen van de web deployment descriptor. Ze worden gebruikt om een URL te linken aan een bepaalde servlet. Figuur 3 toont hoe servlet-mappings gedefinieerd worden. In de <servlet>tag staat dat er een servlet gedefinieerd wordt met naam Hello van de klasse HelloServlet.class. De <servlet-mapping>-tag zorgt ervoor dat wanneer er een oproep komt voor de URL /hello, deze oproep doelt op de servlet met naam Hello.
4
Het gedeelde geheugen
Alle webcomponenten (servlets en JSP-pagina’s) van een webapplicatie hebben toegang tot een gedeeld geheugen. Hiermee kunnen ze objecten met elkaar delen en resultaten aan elkaar doorgeven. Het gedeelde geheugen is handig om twee redenen. Het HTTP-protocol is toestandsloos. Er wordt geen toestandsinformatie bijgehouden. Door middel van het gedeelde geheugen is het mogelijk per gebruiker informatie zoals bijvoorbeeld login-gegevens bij te houden. Een ander voorbeeld is een e-commerce applicatie waar elke gebruiker gedurende een hele gebruikerssessie een winkelmand moet hebben om de aangekochte producten bij te houden. Door middel van het gedeelde geheugen kunnen de verschillende componenten van een webapplicatie ook gemakkelijk resultaten delen. Er is op vijf niveau’s toegang tot het gedeelde geheugen. Objecten op het niveau van een dynamische webpagina zijn enkel toegankelijk voor die pagina. Ze worden zolang bijgehouden tot de pagina volledig gegenereerd is. Op aanvraagniveau zullen de objecten voor ´e´en bepaalde aanvraag (tot de webserver het antwoord terugstuurt naar de gebruiker) in het geheugen toegankelijk zijn. Op sessie-niveau worden de objecten gedurende de levensduur van een gebruikerssessie bijgehouden. Deze objecten zijn alleen voor de sessie die het object in het gedeelde geheugen gezet heeft toegankelijk. Het geheugen op deze drie niveau’s wordt niet gedeeld onder de gebruikers. Het context-niveau is w´el toegankelijk voor alle gebruikers en zal objecten bevatten die voor de hele applicatie beschikbaar moeten zijn. Context is een woord dat vaak gebruikt wordt om de webapplicatie aan te duiden. Ze zullen gedurende de gehele levensduur van de context bijgehouden worden. Het applicatie-niveau laat toe objecten over meerdere contexten te delen. Per niveau hebben de webcomponenten toegang tot twee operaties: get om een bepaald object uit het geheugen te halen en set om een object in het geheugen te zetten. De webcomponenten geven hierbij steeds een naam mee voor het te zetten/te krijgen object. Figuur 4 toont de code die servlets uitvoeren om een object uit het gedeelde geheugen te halen of erin te zetten. Servlets hebben in de J2EE-specificatie toegang tot het aanvraag-, het sessie- en het context-niveau.
4
//Op Request-niveau Vector vector; vector = (Vector) request.getAttribute("naam_van_object"); request.setAttribute("naam_van_object",vector); //Op Sessie-niveau HttpSession session = request.getSession(true); vector = (Vector) session.getAttribute("naam_van_object"); request.setAttribute("naam_van_object",vector); //Op Context-niveau vector = getServletContext().getAttribute("naam_van_object"); getServletContext().setAttribute("naam_van_object",vector); Figure 4: Objecten uit het gedeeld geheugen halen
5