Utveckling av en enkel webapplikation (chat)

På den här sidan byggs, i små steg, en liten webapplikation som är en enkel chat-server. För enkelhetens skull struntar vi i säkerheten, det kommer inte att krävas någon inloggning för att se konversationen i ett visst chat-rum. Det kommer också gå att åstadkomma fel genom att tex titta på sidorna i fel ordning. Den intresserade kan hitta exempel på hur säkerhetsfrågorna kan lösas i avsnittet En komplett webapplikation (number guess game) på sidan Java Servlets och JavaServer Pages.

Steg 1

Först måste vi göra en enkel design av webapplikationen. Vilka komponenter ska ingå och vilket ansvar ska de ha? Vilka vyer ska finnas och i vilken ordning ska de visas?

Lösningsförslag

Det finns många bra (och många dåliga) lösningar. Resten av den här övningen utgår från denna design, chat-webapp.gif.

Steg 2

Vi börjar med choose-chatroom.jsp. Det första steget blir att över huvud taget kunna få kontakt med en jsp vi deployat, dvs en "hello world"-uppgift. Underskatta inte denna del av arbetet, det är förmodligen det största steget som måste tas på en gång.

Skriv alltså en jsp som heter choose-chatroom.jsp men inte gör något annat än att skriva ut en kort statisk html-sida. Deploya den och kolla att du kan surfa till den.

Lösningsförslag

choose-chatroom.jsp web.xml

Steg 3

Nu kommer en till "hello world", men denna gång med en servlet (som i sinom tid ska bli FrontController).

Skriv en servlet som heter FrontController och inte gör något annat än att skriva ut en kort text till System.out. Deploya den och kolla att du kan surfa till den.

Lösningsförslag

FrontController.java  web.xml

Steg 4

Nästa steg blir att lägga in ett formulär i choose-chatroom.jsp, det kan till exempel se ut som nedan:

Enter chat room: Enter nick name:
Tills vidare struntar vi i vad som ska hända när användaren klickar på OK, du kan alltså låta bli att ange attributet action i form-taggen. Om du anger method="get" (i stället för post) kan du se parametrarna som skickas när du klickar på OK i url:en.

Lösningsförslag

choose-chatroom.jsp

Steg 5

Nu är det dags att koppla ihop choose-chatroom.jsp med FrontController. För att göra det måste vi ange action="FrontController" i formuläret i jsp:n. Om du vill kan du också passa på att ändra method till post. En skillnad är att parametrarna inte visas (eller går att skriva in) i url:en, vilket kanske är snyggare, en annan är att post klarar fler tecken än get. Ur debug-synpunkt kan det i och för sig vara bra att fortsätta använda get just därför att parmetrarnas värde tydligt syns. Enligt HTML-specifikationen ska post användas om det blir några sidoeffekter till följd av att formuläret sänds. Exempel på sidoeffekter är att en databas uppdateras eller att anvädaren anmäls till någon mailinglista eller köper något. Följer vi detta ska post användas eftersom användaren börjar delta i en konversation när formuläret sänds.

Dessutom lägger vi till lite kod i servleten som skriver ut parametrarnas värde på System.out. På det viset kan vi kolla att vi kan skicka och ta emot parametrar. Om du låter både doGet() och doPost() i servleten anropa en och samma (privata) metod där alla operationer görs slipper du problem om du senare vill byta mellan get och post i formuläret.

I och med denna övning är choose-chatroom.jsp färdig.

Lösningsförslag

FrontController.java choose-chatroom.jsp

Steg 6

Skriv chat.jsp med "hårdkodad konversation", dvs det ska inte gå att chatta men vi kan labba lite med textareor i html genom att hårdkoda en fingerad konversation. Formuläret i chat.jsp kan till exempel se ut så här:


My next line:

Använd, som när vi började med choose-chatroom.jsp, get i stället för post så kan du se parametrarna.

Lösningsförslag

chat.jsp

Steg 7

Koppla ihop chat.jsp med FrontController genom att lägga till action="FrontController" i formuläret.

Lägg även till flödeskontroll i FrontController. I den här lilla applikationen blir det inte mer flödeskontroll än så här:
Det kan vara bra att ha kvar debugutskriften av request-parametrar i FrontController. För att inte missa något kan vi ändra i den så att alla parametrar skrivs ut utan att vi behöver namnge dem.

Lösningsförslag

chat.jsp FrontController.java

Steg 8

Nu är det dags att börja med filhantering. Det är meningen att varje konversation ska sparas i en egen fil (vi hoppar över databaser). Vi skriver en JavaBean som hanterar filen. Denna klass blir vår "modell". Genom att skapa en ny klass för detta ändamål kan FrontController vara en renodlad controller och JSP:erna behöver inte vara något annat än vyer.

Vi börjar med att fundera på det publika gränssnittet. Vår böna bör ha dessa metoder:
public void setFile(File file) //Talar om vilken fil konversationen ska sparas i.
public void setNickName(String nickName) //Talar om vilket namn som ska skrivas framför inläggen i konversationen.

public void addLine(String line) //Lägger till en replik (dvs en sträng) sist i filen.

public void startReading() //Gör att nästa anrop av getNextLine() returnerar första repliken i konversationen (dvs första raden i filen).
public boolean hasMoreLines() //Returnerar true om nästa anrop av getNextLine() kommer att returnera ytterligare en replik.
public String getNextLine() //Returnerar nästa replik i konversationen eller null om vi nått konversationens slut.
Det är en bra ide att skriva en main()-metod i bönan som testar alla dess publika metoder. På så sätt kan vi prova den utan att behöva blanda in resten av webapplikationen. Ett sådant test ska antingen tala om att alla tester lyckades eller vilket test som misslyckades. Det ska inte skriva ut något värde som måste tolkas för att avgöra om testen lyckades.

Lösningsförslag

ConversationBean.java

Steg 9

Nästa steg blir att koppla ihop bönan med FrontController. När användaren kllickar på START_CHAT i choose-chatroom.jsp ska FrontController anropa metoderna setFile() och setNickName(). När användaren klickar på SEND i chat.jsp ska addLine() anropas. Vi väntar med att låta chat.jsp läsa från filen.

Två frågor vi måste besvara är vad filen ska heta och var den ska ligga.  Alla servletar (och JSP:er) har tillgång till en katalog för temporära filer. Filer som placeras där finns så länge webapplikationen finns men får automatiskt tas bort sedan. Det är lämpligt att placera filerna där. Vi får tag i den katalogen med följande rad:
    File tempDir = (File)getServletContext().getAttribute("javax.servlet.context.tempdir");
Med Orion heter tempkatalogen (om inget annat angetts) ORION_HOME/application-deployments/default/chat/temp om webapplikationen finns i katalogen chat. Med nedanstående rad skapas filen test.txt i temporärkatalogen:
    new File(tempDir, "test.txt");
Angående namnet är ett förslag att filen får ha samma namn som chatrummet.

Ytterligare en fråga är hur vi ska spara ConversationBean-objektet. Det måste vara i sessionsobjektet eftersom det ska överleva ett request men inte vara gemensamt för alla webapplikationens användare.

Lösningsförslag

FrontController.java

Steg 10

Nu är vi äntligen framme vid sista steget, att låta chat.jsp läsa från filen. För det ändamålet ska getConversation() i ConversationBean anropas. Tyvärr är vi tvugna att skriva lite Java-kod i chat.jsp eftersom det kommer att krävas en loop som läser alla rader ur den Collection som returneras av getConversation(). Vi hade sluppit det om vi i stället låtit getConversation() returnera en jättesträng med hela konversationen. Nackdelen med den lösningen är att vi då börjar placera in formatering av vyerna (dvs strängens utseende) i modellen (dvs ConversationBean).

Lösningsförslag

chat.jsp

Teckenuppsättningar och åäöÅÄÖ

När vi ska hantera ett tecken som inte ingår i 7-bits ASCII (tex å, ä, ö, Å, Ä eller Ö) riskerar vi problem med teckenuppsättningarna. Det viktiga är att se till att alla browsrar använder samma teckenuppsättning som servern. Det är ingen bra ide att anpassa servern eftersom vi inte kan lita på att alla browsrar beter sig lika.

Orion 2.0.2 använder default UTF-8 (som egentligen inte är en teckenuppsättning utan en transformation av Unicode). Vi kan säga åt browsrarna att använda UTF-8 genom att lägga till attributet  accept-charset="UTF-8" i alla HTML-formulär. Detta innebär att våra jsp:er ser ut så här:
choose-chatroom.jsp chat.jsp

Att-göra lista

Det är inte direkt en kommersiellt gångbar chatserver vi skrivit... Några problem som återstår att lösa: