Till startsida för Björns studiewebb

Java Servlets

Inledning

Denna sida beskriver hur man skapar en servlet (med Java) som exekverar på en webbserver (med t.ex. Tomcat från Apache eller Resin från Caucho installerad). Resultatet av exekveringen kan antingen vara en genererad HTML-sida eller att servlet dirigerar webbläsaren till en existerande HTML-/JSP-sida (dirigeringen behandlas inte här).

Innehållet på denna hemsida behandlar grundläggande om servlets - hur man skapar en servlet, var servlet ska placeras på webbserver och hur man anropar den från en webbläsare. Sidan behandlar även hur man skapar en enkel servlet och nackdelar med servlets.

Innehåll

Grundläggande om servlets

Att skapa en servlet "består" av fyra steg

Skapa en Java-klass

Hur Java-klassen ska se ut beskrivs under bl.a. rubriken "Enkel servlet..." nedan, vilket skiljer sig beroende på vilken typ av servlet (samt vad den ska göra). Men gemensamt för alla servlet är de övriga tre stegen, vilka beskrivs här nedan.

För att få tillgång till de klasser som behövs för att kommunicera med servern måste vi importera ett antal paket. Nedan visas hur vi importerar paketen och vilka som behövs.

import javax.servlet.*;       //servlet
import javax.servlet.http.*;  //servlet
import java.io.*;             //I/O

Kompilera

När vi skapar en servlet så importerar vi klasser så att servlet kan kommunicera med webbservern (bl.a. för att få tillgång till innehåll från formulär och ett objekt, motsvarande ASP:s Response, som skickar utskrifter till webbläsaren). Så när vi kompilerar servlet så måste vi ange sökvägen till dessa importerade klasser. Detta gör vi lättast genom att ange sökvägen till filen SERVLET.JAR som innehåller dessa klasser (eller filen J2EE.JAR som innehåller samma klasser som filen SERLVET.JAR).

Kompilera i kommandotolken med javac

Om vi kompilerar vår servlet i kommandotolken så skriver vi något i stil med

javac -classpath .;C:\Java\servlet.jar ServletNamn.java

för att ange sökvägen till filen SERVLET.JAR i mappen C:\JAVA eller bara

javac -classpath .;servlet.jar ServletNamn.java

om filen ligger i samma mapp som klassen för din servlet. (Punkter innan semikolonet anger att kompilator ska leta efter klasser (inte JAR-filer!) i samma mapp om vi t.ex. använder oss av egna klasser i servlet.)

Kompilera i kommandotolken med javac

Det är oftast (eller kan vara) lättare att använda en Java-editor/-IDE som JCreator där man (en gång för alla) anger sökvägen till filen SERVLET.JAR (eller J2EE.JAR). En annan fördel är att man slipper växla mellan olika fönster, för att kompilera och korrigera eventuella fel som kompilatorn hittade, då t.ex. JCreator visar resultatet av kompileringen längst ner i programmet. (JCreator, den editor/IDE som jag rekommenderar för "hobbyprogrammerare", har givetvis även andra fördelar...)

[ ATT GÖRA: Gör en beskrivning för hur man använder
JCreator och lägger till sökvägar till JAR-filer]

Kopiera till webbserver

De flesta servrar för servlets brukar definera en mapp WEB-INF (och dess undermappar) som den mapp där klassfilen för, och filer relaterade till, servlets ska placeras. Klassfiler för servlets brukar då placeras i mappen CLASSES under WEB-INF. (Om du satt upp din egna Resin server kan du se hur man konfigurerar dessa mappar på din server på sidan Konfigurerar Resin-server....)

Testa (anropa)

För att testa servlet så öppnar man en URL som liknar följande

https://server-namn:8080/servlet/ServletNamn

eller bara

https://server-namn/servlet/ServletNamn

om server för servlets (t.ex. Resin eller Tomcat) har "integrerats" med ordinarie webbserver.

Man utelämnar alltså filändelsen (.CLASS). Tänk på att det flesta servrar kan skilja på gemener och versaler, d.v.s. du måste ange rätt skiftläge för namnet på din servlet (om din klass heter "HelloWorldServlet" så kanske inte "helloworldservlet" fungerare).


| Till början på sida |


Enkel servlet

Klasser för servlets bör ärver från superklassen HttpServlet - det finns m.a.o. andra klasser att ärva från (se Mer om implementation av servlets nedan). Klassen måste då implementera en av, eller helst båda, metoderna doGet() och/eller doPost(). Vilken av de två metoderna som behöver implementeras beror på hur man vill anropa sin servlet. Skulle man välja att inte implementera den ena metoden så kommer alla anrop av metoden att generera ett fel (dock inget allvarligt!). För att förstå hur och när vilken metod anropas i servlet måste vi förstå hur hemsidor begärs av en webbläsare från en webbserver.

Generellt sätt så begär en webbläsare en fil (t.ex. en hemsida eller en servlet) från webbservern med metoden HTTP-GET (inte att förväxlas med metoder i en Java-klass!!). Men en webbläsare kan även begära en fil från webbservern med metoden HTTP-POST, t.ex. då innehållet från ett formulär skickas (<FORM METHOD="post" ...>). Vill man att servlet ska hantera begäran som sker med HTTP-GET så måste man implementera metoden doGet() i servlet. Och vill man, på motsvarande sätt, att servlet ska hantera begäran som sker med HTTP-POST så måste man implementera metoden doPost(). Följdaktligen så måste man implementera båda metoder om man vill att servlet ska svara på bägge typer av begäran.

Nedan visas ett exempel på en klass som ärver från klassen HttpServlet och som implementerar både metoden doGet() och metoden doPost(). Metoderna skriver ut texten "Hello world!" och vilken metod som anropades - doGet() eller doPost().

En enkel servlet som skriver ut "Hello world!"

Först importerar vi paketen (enligt ovan). Nästa steg är att påbörja klassen och tala om vilken servlet-klass vi vill ärva ifrån. Här kallar vi klassen för HelloWorldServletHttp och vi ärver/utökar (extends) klassen HttpServlet.

public class HelloWorldServletHttp extends HttpServlet {

Efter som vi ärver från HttpServlet så måste vi implementera metoderna doGet() och/eller doPost(). Metodernas signatur är enligt följande (ersätt "doGet" med "doPost" nedan om du implementerar metoden doPost() istället).

public void doGet(HttpServletRequest request,
  HttpServletResponse response) throws IOException
{

Nästa steg är att tala om för servern (som meddelar webbläsaren) vilken typ av data som kommer skickas - i vårt fall "vanlig" text (text/html). Det gör vi genom att anropa metoden setContentType() i Response-objektet och skicka med typen av data som en sträng ("text/html" i vårt fall).

response.setContentType("text/html");

Därefter hämtar vi ett PrintWriter-objekt som vi ska skriva data (HTML-kod) till och placerar objektet i variabeln out - servern kommer att skicka denna data till besökarens webbläsare. För att hämta PrintWriter-objektet använder vi metoden getWriter() i Response-objektet.

PrintWriter out = response.getWriter();

Därefter är det bara att börja skriva ut HTML-koden som det resulterande HTML-dokumentet ska innehålla. Vi kan välja mellan att använda metoden println(), som ger en radbrytning i HTML-koden, och println() som finns i PrintWriter-objektet.

out.println("<HTML>");

Även om man genererar HTML-kod i en servlet (eller ASP) så bör man försöka göra den resulterande HTML-koden så lättläst som möjligt (för att underlätta felsökningen av HTML-koden). Därför bör man försöka se till att infoga radbrytningar  i HTML-koden (m.h.a. metoden println()) så att strukturen för den resulterande HTML-koden blir så lättläst som möjligt. I exemplet nedan har HTML-koden delats upp så att varje tagg/element skrivs ut en i taget med metoden println() och därmed hamnar på varsin rad i HTML-dokumentet.

Sist av allt så avlutar vi metode och klassen.

} // doGet()
} //class HelloWorldServletHttp

Nedan visas den fullständiga koden för klassen HelloWorldServletHttp som implementerar båda metoderna doGet() och doPost(). Om vi jämför de båda metodernas kod så ser vi att de är den samma utom en rad - den rad som skriver ut texten <h1>Hello World! ...</h1>.

Filen HelloWorldServletHttp.class

/*
* Java Servlet som genererar en hemsida som skriver ut "Hello
world!".
* Björn Persson, EkI, MdH - 2001-04-29.
* bjorn.persson@mdh.se
*/

//Importera paket för...
import javax.servlet.*;       //servlet
import javax.servlet.http.*;  //servlet
import java.io.*;
            //I/O

public class HelloWorldServletHttp extends HttpServlet
{
   /***************************************************
  * Implementation av metoden doGet() som anropas av webbserver då
  * webbläsare begär servlet med metoden HTTP-GET
  ****************************************************/

public void doGet(HttpServletRequest request,
  HttpServletResponse response) throws IOException
{
     //Tala om för webbserver vad som kommer att skickas (d.v.s.
     // HTML-kod)
   response.setContentType("text/html");

     //Hämta objekt för "output" för att kunna skriva till den
     // genererade hemsidan
   PrintWriter out = response.getWriter();

     //Skriv ut HTML-kod
   out.println("<HTML>");
   out.println("<HEAD>");
   out.println("  <TITLE>Hello world</TITLE>");
   out.println("</HEAD>");
   out.println("<BODY>");
   out.println("<H1>Hello world! med doGet()</H1>");
   out.println("</BODY>");
   out.println("</HTML>");
} // doGet()
 
 
 
   /***************************************************
  * Implementation av metoden doPost() som anropas av webbserver då
  * webbläsare begär servlet med metoden HTTP-POST
  
****************************************************/

public void doPost(HttpServletRequest request,
  HttpServletResponse response)
throws IOException
{
     //Tala om för webbserver vad som kommer att skickas (d.v.s.
     // HTML-kod)
   response.setContentType("text/html");

     //Hämta objekt för "output" för att kunna skriva till den
     // genererade hemsidan
   PrintWriter out = response.getWriter();

     //Skriv ut HTML-kod
   out.println("<HTML>");
   out.println("<HEAD>");
   out.println("  <TITLE>Hello world</TITLE>");
   out.println("</HEAD>");
   out.println("<BODY>");
   out.println("<H1>Hello world! med doPost()</H1>");
   out.println("</BODY>");
   out.println("</HTML>");
} // doPost()

 
} //class HelloWorldServletHttp

Andra sätt att implementera doGet() och doPost()

Om man vill att servlets metoder ska göra samma sak, oavsett om doGet() eller doPost() anropas, så kan man i t.ex. implementera doGet() och sen anropa den metoden i doPost(). Koden för doPost() (i exemplet ovan) blir då

      //...
public void doPost(ServletRequest request, ServletResponse response) throws IOException
{
    //Anropa egen implementation av doPost() - skicka med inparametrarna
     doGet(request, response);
} //doPost()
  //...

Mer om implementation av servlets

I viss litteratur så visas hur servlets ärver från klassen GenericServlet istället för HttpServlet. Läs mer om varför...

Nackdelar med servlets

Den största nackdelen med servlets är synlig i exemplet ovan - all HTML-kod måste skrivas ut till den resulterande hemsidan m.h.a. metoderna print() eller println(). Detta gör att man blandar logik (funktion) med presentation, vilket bl.a. gör det svårare att läsa koden. Detta gör det även svårare att ändra sidans design - servlet måste kompileras om då HTML-koden ändras. Av den anledningen så har en annan teknologi kallad Java Server Pages (JSP) skapats.

Tanken är att JSP-sidorna ska innehålla presentationsskiktet (i HTML) samt serlvets och Java Beans ska hantera logiken. Kommunikationen mellan JSP-sida och servlet sker med  speciella JSP-taggar. Personer som är bra på design, men kanske inte är programmerare, kan då skapa JSP-sidorna och programmerare (som inte brukar vara bra på design :-) kan hantera logiken i servlets (och Java Beans).

Rekommenderad läsning är JavaServer Pages av Hans Bergsten (O'Reilly) för en inledande inblick i hur JSP fungerar. Boken visar att JSP inte är riktigt samma sak som Microsofts Active Server Pages (ASP) utan är, enligt andras och min mening, bättre genomtänkt. Det ska nämnas att det finns andra liknande teknologier som enligt vissa är bättre än JSP.


| Till början på sida | Tillbaka till Java |