servlets

servlets deel 5

1. Het maken van een rekenmachine

In deze lessenreeks gaan we de het gebruik van een Servlet geavanceerder toepassen. Je gaat een rekenmachine maken op basis van een Servlet. Dat is niet eenvoudig maar als je de lessen  nauwkeurig volgt, ga je eruit komen.

Bij deze rekenmachine geldt de volgende eis: Je mag geen Javascript of andere scripttaal gebruiken. Alleen technieken van een servlet zijn toegestaan.

Maak een  nieuw project. Noem het calculator en begin daarna met het maken van een formulier in de index.jsp zoals hieronder wordt getoond.

<form action="calculator">
    <input type="submit" name="number" value="1" />
    <input type="submit" name="number" value="2" />
    <input type="submit" name="number" value="3" />
    <input type="submit" name="number" value="4" />
    <input type="submit" name="number" value="5" />
    <input type="submit" name="number" value="6" />
    <input type="submit" name="number" value="7" />
    <input type="submit" name="number" value="8" />
    <input type="submit" name="number" value="9" />
    <input type="submit" name="number" value="0" />
    <input type="submit" name="function" value="+" />
    <input type="submit" name="function" value="-" />
    <input type="submit" name="function" value="/" />
    <input type="submit" name="function" value="*" />
    <input type="submit" name="c" value="c" />
    <input type="submit" name="result" value="=" />
    <input type="hidden" name="savedNumber" value="${savedNumber}" />
</form>

Over dit formulier een paar opmerkingen. We gebruiken alleen inputs van het type submit waarvan we een aantal dezelfde naam geven.

<input type="submit" name="number" value="1" />
<input type="submit" name="number" value="2" />
<input type="submit" name="number" value="3" />
<input type="submit" name="number" value="4" />
<input type="submit" name="number" value="5" />
<input type="submit" name="number" value="6" />
<input type="submit" name="number" value="7" />
<input type="submit" name="number" value="8" />
<input type="submit" name="number" value="9" />
<input type="submit" name="number" value="0" />

Alle cijfers krijgen de naam number, alle function (plus, min, delen en vermenigvuldigen) krijgen de naam function.

<input type="submit" name="function" value="+" />
<input type="submit" name="function" value="-" />
<input type="submit" name="function" value="/" />
<input type="submit" name="function" value="*" />

Dan hebben we nog een knop c om de rekenmachine te resetten en een knop "=" om het resultaat op te vragen..

<input type="submit" name="result" value="=" />

We hebben ook een input van het type hidden.

<input type="hidden" name="savedNumber" value="${savedNumber}" />

Dit is om het cijfer wat is aangeklikt telkens terug te sturen en aan te vullen. De gebruiker ziet niet dat het wordt meegestuurd i.v.m. de optie hidden.  Het nieuwe cijfer wordt telkens samengevoegd in de variabele ${savedNumber}.

De action van het formulier is stellen we in op "calculator" zodat het formulier telkens netjes naar de servlet wordt gestuurd.

<form action="calculator">

In de servlet moet dat uiteraard ook worden ingesteld. 

2. Het eerste cijfer bewaren

Het formulier kan vier variabelen wegsturen waarvan 2 tegelijk. De variabele savedNumber wordt altijd weggestuurd vanwege de hidden input. De rest van de inputs zijn van het type submit dus dat houdt in dat zodra je klikt op een van deze knopjes alleen de waarde van die variabele wordt verstuurd. Dit kun je ook zien in de url-balk:

http://localhost:8080/Calculator/calculator?number=4&savedNumber=

In bovenstaande url wordt de variabele number en savedNumber wordt verstuurd. De eerste variabele heeft altijd een vraagteken vooraf staan. De overige variabelen worden aangegeven met het ampersand (&) teken. Je ziet dat de variabele savedNumber leeg is.

We sturen zogenaamde GET-variabelen weg. Dit zijn variabelen die te zien zijn in de url dus ?number=4&savedNumber= . We kunnen ook POST-variabelen wegsturen. Deze variabelen zijn niet te zien. Voor de servlet maakt het niet uit of het GET of POST is. We laten het voorlopig standaard op GET staan zodat we kunnen zien wat er gebeurd.

Maak nu een servlet genaamd CalculatorServlet en zorg dat alle het request /calculator naar de servlet wordt verwezen. Dit kun je instellen in de @Webservlet annotation en is in eerdere lessen al uitgelegd. Maak tevens een package controller en plaats de servlet daarin.

@WebServlet(urlPatterns = {"/calculator"})

In de servlet verwijderen we alle code in de methode processRequest() (zie eerdere lessen) en plaatsen daarvoor de volgende code:

HttpSession session = request.getSession();

String function = request.getParameter("function");
String number = "";
String c = "";
String savedNumber = "";
String result = "";

Als eerste maken we een variabele session om de http session te kunnen opvragen. Vervolgens vragen we de variabele function op van het formulier. We kunnen rechtstreeks een request.getParameter("function") opvragen omdat deze variabele uit de hidden input komt en dus altijd wordt meegestuurd. De overige variabelen worden niet altijd meegestuurd en deze geven we eerst een lege waarde.

We vragen aan het begin van de code ook altijd de volgende waarden op:

savedNumber = request.getParameter("savedNumber");
c = request.getParameter("c");
function = request.getParameter("function");

Vervolgens gaan we verder en gaan we detecteren of function een waarde heeft. Als deze de waarde null heeft dan weten we dat deze niet is meegestuurd. Dit kunnen we gebruiken voor het volgende stukje code:

if (function == null) {
    number = request.getParameter("number");
}

We vragen nu de variabele number op met de getParameter() methode. Het kan er altijd maar één zijn, zoals je weet. Het formulier kan maar één van deze variabelen versturen. Bij het versturen van het eerste cijfer moeten de variabelen number en savedNumber een waarde krijgen - zie ook de eerst verstuurde URL waarin savedNumber nog een lege string is (en dus wel een waarde heeft - een lege string is ook een waarde).

Vervolgens gaan we deze twee waarden samenvoegen in een session variabele. We checken daarbij nog steeds of de variabele function null is.

//putting the numbers together and saving in a session attribute
if (savedNumber != null) {
    session.setAttribute("savedNumber", number + savedNumber);
}

 

3. De input function krijgt een waarde

In het formulier heb je ook de input "function" ingevoerd.

<input type="submit" name="function" value="+" />
<input type="submit" name="function" value="-" />
<input type="submit" name="function" value="/" />
<input type="submit" name="function" value="*" />

Stel nu, nadat je het eerste getal hebt ingevoerd, dat je klikt op een van deze knopjes. Deze waarde komt binnen in de Servlet en de string function krijgt een waarde door de code String function = request.getParameter("function");

Breidt nu de eerste if expression uit met een else. Als volgt:

if (function == null) {
    number = request.getParameter("number");
    savedNumber = request.getParameter("savedNumber");
    c = request.getParameter("c");
} else {
    //don't destroy the previously saved session attribute in the next if
    savedNumber = null;
    //don't destroy the session
    c = null;
}

Dus als de String function niet null is dan zal het else gedeelte gaan werken en krijgen de strings savedNumber een null-waarde. Daarmee wordt de volgende if-expressie buiten werking gezet.

if (savedNumber != null) { 

......

In deze if had je al de code session.setAttribute("savedNumber", number + savedNumber); geplaatst maar deze wordt nu overgeslagen. Omdat het een session Attribute is blijft het leven. Met andere woorden: het ingegeven getal blijft gewoon bewaard in het session attribuut. De variabele savedNumber (dat is dus wat anders dan het session Attribuut) wordt op null ingesteld. Dit is ook te zien aan het commentaar wat erboven is geplaatst.

//don't destroy the previously saved session attribute in the next if
savedNumber = null;

Vervolgens moeten we de String function in een session Attribute gaan zetten. Dat gaat zo:

if (function != null) {
    if (function.equals("+")
            || function.equals("-")
            || function.equals("*")
            || function.equals("/")) {
        session.setAttribute("function", function);
    }
}

Eerst wordt nogmaals gechecked of de String function geen nullwaarde heeft. Vervolgens, in een nieuwe if, wordt gekeken of de waarde String function de waarde +, -, * of / heeft. Dit is een extra check. We willen niet dat er in het function attribuut een andere waarde komt.

Als deze if ook goed wordt doorstaan, wordt er een nieuw attribuut function ingesteld. We hebben nu dus 2 attributen levend:

  1. savedNumber
  2. function

Hoe kunnen we de waarde opvragen van een attribuut? Dat gaat zo:

String tempNumber = (String) session.getAttribute("savedNumber");

Let op de (String) code. Dit noemen we type casting. De methode getAttribute geeft een Object terug en met een cast kunnen het dwingen naar een string.  Vervolgens kunnen tempNumber gaan omzetten naar een float. Plaats de volgende code binnen de if-expressie (denk goed na over welke if-expressie we hier precies bedoelen):

String tempNumber = (String) session.getAttribute("savedNumber");
if (!tempNumber.equals("")) {
    float number1 = Float.parseFloat(tempNumber);
    session.setAttribute("number1", number1);
    //empty the savedNumber because there is now a session attribute number1
    session.setAttribute("savedNumber", "");
}

Dus als tempNumber niet de waarde lege string heeft plaatsen we in de float number1 de waarde van tempNumber. Tevens zetten we het savedNumber attribuut op een lege string zodat het niet meer wordt getoond.

4. de reset

We hebben in de rekenmachine ook een knop nodig die alles reset. Dit wordt gerealiseerd met de volgende input in het formulier:

<input type="submit" name="c" value="c" />

Vermoedelijk weet je al enigzins wat de code gaat worden namelijk als de variabele c een waarde krijgt moet de sessie invalidate worden gemaakt. Hieronder zie je de code waarbij je op de plaats van de vraagtekens zelf de code moet verzinnen:

try {
    if (???????) {
        if (?.equals("?")) {
            session.invalidate();
            request.getRequestDispatcher("/index.jsp").forward(request, response);
        }
    }
} catch (IllegalStateException ex) {
    //do nothing
}

try and catch

Je ziet dat er om de if-expressie een try and catch code staat. Dit werkt in pseudecode als volgt:

als er geen illegale status is (als de sessie al invalidate is)

maak dan de sessie ongeldig (zet alles op null) en 

forward de servlet (hier stopt dus ook de code)

in het geval de sessie we ongeldig was: geef geen foutmelding

5. het tweede getal

Zodra de function knop is aangeklikt beginnen we aan de opbouw van het tweede getal. Dit gebeurt weer op dezelfde manier namelijk omdat in het begin van de code de variabele function weer null wordt met de code function = request.getParameter("function"). Zodra de variabele function null is wordt ook weer de variabele savedNumber opgebouwd zonder dat we de code hoeven te wijzigen. Dit is een mooi voorbeeld van hergebruiken van code.

Wat verder? Zodra het tweede cijfer is opgebouwd zal de gebruiker op "=" klikken. De variabele result wordt nu gevuld als we de volgende code toevoegen aan het begin van ons script:

result = request.getParameter("result");

 De andere session variabelen krijgen weer de waarde null met uitzondering van savedNumber. We kunnen nu gaan rekenen door de volgende code toe te voegen:

if (result != null && result.equals("=")) {
    float number1 = (float) session.getAttribute("number1");
    float number2 = Float.parseFloat(savedNumber);
    session.setAttribute("savedNumber", "");
    session.setAttribute("number2", number2);
    //temporary code with a plus - must be replaced with a switch and the calculator Object
    session.setAttribute("count", number1 + number2);
}

Eerst checken we of de variabele result is gevuld en of het de "="-waarde is. Vervolgens vullen we in de float number1 en number2 met respectievelijk het session Attribuut number1 en met de variabele savedNumber. Het sessie Attribuut savedNumber legen we zodat het niet meer zichtbaar is en we maken van number2 eveneens een sessie Attribuut.

We laten de calculator alvast rekenen door de 2 floats bij elkaar op te tellen en in een session Attribuut te plaatsen. Deze code moet echter worden vervangen door code zoals wordt gevraagd in de opdracht.