servlets

Een interactieve applicatie - deel 2

1. Een servlet maken

Je kunt nu een werken met een JSP en een bijbehorende class. Je bent eigenlijk al in staat om een redelijk goed werkende applicatie te maken maar je mist nog de controller, de class die alles controleert. Het is overigens niet één class maar een aantal classes, afhankelijk van hoeveel je wilt met je applicatie. De controller is de Java Servlet.

de controller

De servlet maken we in de package controller. Maak deze nu eerst aan. In deel 5 kun je zien hoe je een package moet maken.

Vervolgens gaan we een servlet maken. Deze vindt je in het mapje web.

les8_servlet

Noem de servlet ContactFormServlet. De naamgeving van een servlet eindigt altijd op Servlet zodat we kunnen zien dat het om een servlet gaat.

les8_servlet_naamgeven

Klik op next en pas daarna de url aan. We gebruiken hier alleen kleine letters.

les8_servlet_url_aanpassen

Klik hierna op Finish. Je hebt nu je eerste servlet gemaakt. Je kunt hem proberen te runnen. Met http://localhost:8080/naamvanjeapplicatie/contactform kun je zien of het werkt. Hieronder de output in de browser.

les8_output_1

De servlet bestuderen en aanpassen

We zullen de servlet nu eerst gaan bestuderen en aanpassen. Ik begin bovenaan.

les8_servlet_bestuderen_1

Bovenaan staan de imports van de benodigde Java bibliotheken. Dit wordt automatisch aangemaakt. Logischerwijs zie je de Servlet bibliotheek erbij staan. Een bibliotheek is niet veel anders dan een package met classes. Deze bibliotheken vind je in het mapje Libraries. Hieronder de library van de JDK (Java Development Kit).

les8_bibliotheken

Vervolgens begint de class.

les8_class_start

Je ziet boven de class een zogenaamde annotation staan. Deze zijn enigzins vergelijkbaar met de de metatags in HTML. Het zegt iets over de applicatie. We noemen dit metadata en in dit geval dus iets over de url.

De inhoud van de servlet

processRequest

Nu door naar wat we binnen de servlet zien. We starten met de methode protected void processRequest(HttpServletRequest request, HttpServletResponse response). Deze methode is een beetje vergelijkbaar met de main method uit het intermezzo. Hier zet je alles in waar je wat mee wilt. Je ziet twee parameters van het type HttpServletRequest en het type HttpServletResponse. Dat is, heel simpel, de informatie die er van de applicatie binnen komt en de informatie die eruit gaat. Vervolgens zie je ook throws ServletException, IOException. Dit is code voor het afvangen van fouten. Het is een zogenaamde try and catch. Try betekent: probeer de code eerst. Wordt er een fout geconstateerd dan stopt het script en springt het naar catch.

Binnen de class zie je code staan die rechtstreeks naar de browser print. Het is typische spaghetti-code. Nu staat de HTML-code zomaar midden tussen de Java code. Weg ermee! Je mag het compleet verwijderen.

De methode is nu leeg en klaar om gevuld te worden met code.

doGet en doPost

Verderop in de code - je moet het misschien even open klappen - zie je nog twee methoden: de doGet en de doPost methoden. De ene methode wordt in werking gezet als het een GET verzoek is en de andere als het een POST verzoek is. Beide methoden doen niets anders dan het verzoek doorsturen naar de processRequest methode. Je kunt ze verder laten staan.

Als laatste zie je ook nog de getServletInfo() methode. Deze mag je verwijderen of laten staan. Kies maar.

2. Javacode van de jsp naar de servlet

Je hebt de servlet gemaakt maar je kunt er nog niets mee. Daar gaan we nu verandering in brengen.

We gaan nu alle java-code van het bestand email.jsp overbrengen naar de servlet. Je kunt de code hieruit kopiëren en overzetten naar de servlet. Verwijder hierna de javacode uit de jsp inclusief de import en inclusief alle variabelen net zolang tot alle foutmeldingen zijn verdwenen.

 

les9_code_1

 

Merk op dat op regel 41 en 42 een fout geeft. Dat komt omdat de servlet de class User en de class Message niet kent. We moeten dit eerst importeren. In Netbeans kun je dit heel handig automatisch laten doen. Ga met de cursus op de foutmelding staan en druk op Alt-Enter. Je krijgt nu de volgende melding:

les9_alt-enter

Je ziet dat de import als eerste suggestie wordt gedaan. Deze suggestie krijg je op voorwaarde dat de class User bestaat.

les9_import_user_class

Als je op enter hebt gedrukt wordt automatisch de clas User geïmporteerd vanuit de package business. De foutmelding verdwijnt. Je kunt dit eveneens doen voor de class Message.

De uitvoer van het formulier naar de servlet sturen

Het contactformulier zend de informatie naar de email.jsp door het action-attribuut in te stellen als action="/webapp/jsp/email.jsp". In plaats van de informatie naar email.jsp te sturen gaan we dit nu naar de servlet sturen. Stel daarom het action-attribuut als volgt in:

les9_contactform_action

Je gaat nu dus gebruik maken van de in de servlet ingestelde url /contactform. Merk op dat hier nog steeds de naam van de applicatie aan vooraf gaat.

Als je nu het formulier uitprobeert zul je zien dat je een lege pagina krijgt. Dat komt omdat de servlet verder nog niets doet. We zullen nu eerst eens met een debugmethode onderzoeken wat de servlet precies doet.

3. Debuggen in Netbeans

Een zeer handige functie in Netbeans is de Java Debugger. Debuggen betekent fouten eruit halen. Met behulp van deze debugger kan je tijdens de uitvoering van het script de code nader bekijken door breakpoints te plaatsen. Zodra de het script is gestopt bij zo'n breakpoint kun je de variabelen inspecteren. Het debuggen in Netbeans is mogelijk op de volgende twee manieren:

Door te klikken op het debug-symbool waarmee je de index.jsp start in debugmode.

les9_debug_knop

Of door met de rechtermuisknop te klikken op het bestand waarmee je rechtstreeks het bestand opstart.

les9_debug_rechtermuisknop

We kiezen voor de laatse methode. Eerst plaatsen we daarvoor breakpoints. Ga naar de ContactFormServlet en klik in de kantlijn. Er verschijnt een rood vierkantje en de regel wordt rood gemarkeerd.

les9_debug_kantlijn

Klik nu met de rechtermuisknop op het contactformulier en kies Debug File zoals je in de afbeelding hebt kunnen zien. Vul hierna het formulier op de normale wijze in en verzend het. Je zult nu zien dat de browser nu wacht. Het script is onderbroken door Netbeans en we kunnen nu tijden het lopen van het script dit manipuleren. We noemen dit een Line Breakpoint..

les9_debuggen_firefox_wacht

Firefox wacht op Netbeans

Als je hierna in Netbeans in de ContactFormServlet kijkt zie je dat regel 38 groen is geworden. Tevens zie je een groen pijltje in de kantlijn. Dit is het teken dat het script hier is aangekomen en wacht.

les9_debuggen_netbeans_wacht

Onder in Netbeans zijn nieuwe vensters verschenen. Het meest interesante venster voor ons zijn de variabelen waarvan we de waarde willen weten. Als dit venster niet automatisch wordt geopend kun je het vinden in Window -> Debugging -> Variables of met Alt-Shift-1.

les9_debug_variables_venste

Je ziet nu onderin het venster Variables. Daarin zijn drie objecten te vinden: request, response en this. Het woordje this is de ContactFormServlet. In de kolom type wordt dit bevestigd.

les9_debug_variables_venster_2

Je kunt het script nu een stapje verder laten gaan door op F8 te drukken of op Step Over

les9_debug_stepover

Als je dat hebt gedaan zie je de waarde van de eerste variabele verschijnen genaamd firstName. Tevens zie je welke waarde deze variabele heeft. Het is de String "Jan", precies zoals die is verzonden.

les9_debug_variables_venster_3

Bij nog een "step over" verschijnt ook de volgende variabele.

les9_debug_variables_venster_4

Op deze manier kun je zien of de servlet werkt en of alle verstuurde informatie wordt verstuurd. Dat is bij mij niet zo. Kijk maar naar de volgende waarde:

les9_debug_variables_venster_5

Je ziet dat het emailadres niet wordt opgepikt door de servlet. Het heeft een null-waarde. Wat komt er dan wel binnen? We kunnen het debuggen stoppen door te klikken op de Finish Debugger Session knop. Het script wordt nu afgemaakt (en ook gestopt). Vervolgens kunnen we in de browser de URL zien:

http://localhost:8080/webapp/contactform?voornaam=Jan&achternaam=Klaassen&emailaddress=jan%40klaassen.nl&message=Een+bericht+voor+Katrijn&copy=yes

Hierin is de variabele emailaddress op zijn Engels te vinden met de waarde jan%40klaassen.nl. Terugkijkend in de servlet kun je zien dat deze de waarde van emailadres opvraagt en niet van emailaddress. Kennelijk gaat er bij het formulier iets mis. Dat klopt ook. De naamgeving is niet consequent doorgevoerd naar het Nederlands. Als ik dit wijzig zal de servlet wel gaan werken. Ik kies ervoor om alle namen in het formulier in het Nederlands te zetten. Pas in de Javacode ga ik over op engelse benamingen. Je mag hier zelf een eigen keuze in maken.

les9_debug_contactformulie

De servlet zal nu wel op de juiste wijze gaan werken.

Nu rest ons nog te kijken wat er met de twee objecten User en Message gebeurt. Na het opnieuw opstarten van de debugfunctie worden deze ook getoond.

les9_debug_classMessage_User

Je ziet dat de bijbehorende waarden ook keurig worden opgepakt en weergegeven. Mocht één van deze waarden ook null zijn dan is er dus ook weer iets mis met het formulier of met het request-object in de servlet.

meer debugknopjes

Er zijn meer debugknopjes. De belangrijkste is de Step Into. Deze geeft je de mogelijkheid om naar de betreffende class te gaan om te kijken wat daar gebeurt. Dit gaat als volgt:

1. Als de debugger op regel 43 is gekomen en een nieuw object user aanmaakt.

2. Dan kun je klikken op step into.

3. De debugger gaat dan naar de betreffende class en de code die wordt aangesproken. In dit geval is dit de constructor.

4. Hier kun je dan de parameters controleren. Hierboven kun je zien dat de classvariabelen nog geen waarde hebben. De debugger is nog niet bij de regels waar dit plaats gaat vinden.

4. De servlet werkend maken

De volgende stap is de servlet werkend te maken. Je hebt de variabelen uit het formulier al binnen maar hoe krijg je ze nu weer opnieuw in de jsp? Daarvoor moet het volgende worden gebouwd:

  1. Alle variabelen moeten worden overgezet in nieuwe variabelen die de jsp kan lezen. Dit gebeurt met een specifieke taal, de JSP Expression Language;
  2. De servlet moet weten waar de jsp staat om deze op te starten. Dit heet forwarding.

De JSP Expression Language

Er zijn twee manieren om variabelen in een JSP te kunnen lezen. De standaard JSP Languague en de JSP Expression Language (EL). De eerste is een stuk ingewikkelder en daarom kiezen we voor de tweede optie. Om deze taal te kunnen gebruiken is er een voorwaarde. De EL maakt gebruik van een JavaBean. Je mag het ook een bean noemen.

Wat is een JavaBean?

Een bean heb je al gemaakt. Het is een class die voldoet aan de volgende voorwaarden:

  1. Er is een default constructor;
  2. Alle instance variables zijn private;
  3. De bean heeft voor iedere propertie een setter en een getter.

Een propertie is hetzelfde als een instance variable en dat is weer hetzelfde als een classvariabele. Een getter is het opvragen van de waarde van zo'n propertie. Een voorbeeld in de User class is public String getFirstName(). Een setter is het voorzien van een waarde van een propertie. Een setter heeft altijd een parameter. Een voorbeeld hiervan is public void setFirstName(String firstName).

Als je nu kijkt naar de class User hoef je er verder niet zoveel aan te doen. Het is al een bean.

les11_javabean

De class User is een Javabean.

Session attributen in een session bewaren en doorgeven aan de jsp

De manier waarop je variabelen in de servlet doorgeeft is door gebruik te maken van een session. De code om een session aan te maken is:

HttpSession session = request.getSession();

Methoden van een object zoals het object session zijn heel gemakkelijk te zien door achter het woord session op de punt te drukken. Je krijgt dan het documentation venster en een venster met een overzicht van alle methoden. Als je de eerste letter intypt, zoals de s, krijg je alle methoden die starten met een s.

Zodra je deze code inbrengt vraagt Netbeans of het de bijbehorende bibliotheek mag importeren. Natuurlijk klik je op OK.

les11_import_bibliotheek

In plaats van de getParameter methode neem je nu van het request object de getSession() methode en daarmee maak je een HttpSession object. Met het object session kun je nu de jsp variabelen gaan instellen. Dit gaat als volgt:

Je ziet dus dat het complete object user is "overgezet" naar een session object. Het is vervolgens heel eenvoudig om dit in de JSP te benaderen:

Je kunt met met de methode setAttribute van alles in zo'n attribute variable stoppen zoals bijvoorbeeld een String.

les11_code4

En in de jsp is deze eenvoudig op te vragen.

les11_code5

 

De servlet forwarden

De laatste stap om de servlet werkend te maken is het te forwarden. Dat is mogelijk met een RequestDispatcher object. Het woord dispatcher betekent zoiets als verzender. Met behulp van de methode getServletContext() kunnen we zo'n dispatcher maken. Als we het hebben gemaakt zijn we in staat om te forwarden met een vooraf gemaakte String als url. Hierbij geven de twee parameters request en response weer mee. Het request object hebben we in de bovenliggende code gemanipuleerd met de setAttribute methode.

les11_code3

Merk op dat bij deze url niet de naam van de applicatie staat. Java produceert dit zelf. Je begint dus met de naam van het mapje.

Basis

Je hebt nu al een behoorlijk geavanceerde basis om een complete applicatie te maken. We zullen in de volgende lessen meer ingaan op programmeertechnieken zoals de if en de loop die we zowel in de Java classes als in de JSP kunnen gebruiken. Je kunt ook geen data opslaan. Dit komt als laatste aan bod waarbij ik het onderwerp databases zal behandelen.

5. Een dependency toevoegen

Je zult merken dat je foutmeldingen krijgt in je code zoals package.servlet..... does not exists. Dat komt omdat deze bibliotheek niet is toegevoegd aan je applicatie. Dit kun je toevoegen via de pom.xml file. Hierin voeg je een zogenaamde dependency toe binnen de <dependencies>. Voeg daarbinnen de volgende code toe:

<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>3.0-alpha-1</version>
    <scope>provided</scope>
</dependency>

Hierna even wachten en de foutmelding zal verdwijnen.

6. De applicatie stabieler maken met try and catch

Stel dat je de volgende applicatie hebt gemaakt:app

Het is dus een applicatie die de tijd kan uitrekenen t.o.v. de snelheid.

De code voor deze applicatie is niet zo ingewikkeld en conform de lessen:

code servlet

De applicatie is echter niet stabiel. Stel we voeren het volgende in:

fill in

We krijgen nu een heel ander resultaat. Het is een zogenaamde Numberformatexception

numberformatexception

 Eigenlijk moet er een foutmelding zoals "Geef een getal" komen te staan zoals hieronder getoond. Anders geef je de gebruiker teveel informatie.

message

Dat kun je voor elkaar krijgen door een try and catch in te voeren. Hieronder zie je de code. De plaats waar het fout kan gaan, zet je een try {} omheen en daarna "vang" je de exception op en kun je zelf bepalen wat de applicatie ermee gaat doen. In dit geval dus een foutmelding tonen via een jsp-variabele.

 try and catch code

De variabele errormessage dien je dan ergens in het formulier te tonen. Je kunt er een inline style aan koppelen.

errormessage

 In de code mist nu nog één ding. Als er een vreemde invoer is geweest is het beter om dit te loggen. Zo kun je mogelijke hackpogingen wellicht voorkomen. Het loggen van foutmeldingen gebeurt in de catch. Je zag daar wellicht al de variabele NumberFormatException ex. Deze kunnen we gebruiken om te loggen. De code is als volgt.

logging

In de eerste regel maak je de logger aan en in de tweede regel geef je aan wat er gelogd moet worden met behulp van de variabele ex (exception). Stel dat jouw applicatie draait op de Glassfish server dan kom er de volgende melding. Je kunt dit zien in Netbeans.

 logged

Je kunt nu dus ook zien wat er is ingevoerd en welke exception je hebt gevangen.

Als je de hele foutmelding wilt zien dan kun je ook de logcode vervangen door onderstaande code. In de server log wordt dan alles geprint.