Servlet
informasjon
oppdatert: Januar 14. oktober 2003
Servlet
Det mest slagkraftige webserver-programmeringspråket er Java. Java er i utgangspunktet et fullstendig programmeringsspåk på linje med C++. Koden er 100% portabel til ulike plattformer og webservere (uten behov for rekompilering). Java er et moderne objekt-orientert språk med standardklasser for nettverk- og web-programmering. Denne dokumentasjonen av servlet forutsetter kunnskap om generell java-programmering. "Mother-site" for alle java-programmerere er http://java.sun.com der finner en SDK (Software Devopment Kit), dokumentasjon av alle standard klasser, kodeeksempler, korte introduksjonskurs, referanser til bøker (en del bøker kan lastes ned online).

Java's hiarki av standardklasser
Alle servlet ekstender Java klassen HttpServlet. Alle standardklasser tilhører en Java-pakke. Java-pakkenavnene har en hiarkisk struktur. Klasser idenfiseres med fullstendig Java-pakke- og klasse-navn, f.eks. javax.servlet.http.HttpServlet.

Sun tilbyr tre pakker av Java-pakker, som innholder ulike standardklasser:

  • J2EE (Java 2 Enterpise Edition)
  • J2SE (Java 2 Standard Edition)
  • J2ME (Java 2 Micro Edition) På våre webhotell er J2EE og J2SE tilgjengelig.

    Du må laste dokumentasjon av klassene til din lokale maskin. Dokumentasjon av J2EE er inkludet i J2SKEE, men dokumentasjon av J2SE lastes ned separat. Etter nedlasting aksesser filen "...../doc/index.html" og følg linken "API-dokumentasjon" for beskrivelse av atributter og metoder i de ulike klassene.

    Eksempel på kode til et lite servlet
    Trykk her for å vise siden.
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class Demo extends HttpServlet {
    
        public void doGet (HttpServletRequest request, HttpServletResponse response)
    	throws IOException, ServletException
    
        {
    	PrintWriter out = response.getWriter();
    	out.println("Dette er skrevet av servlet \"Demo.class\"");
        }
    }

    Hvor skal jeg plasserere mine servlet på webhotellet?
    I din hjemmekataloger på webhoteller har vi installert katalogen "webapps/WEB-INF/classes/". Servlet plasseres under den katalogen. Eksempler:

    1. webapps/WEB-INF/classes/MittServlet1.class
    2. webapps/WEB-INF/classes/minpakke/MittServlet2.class

    Hvilke filrettigheter kan jeg sette på klassefilene?
    For at tomcat-serveren skal kunne aksessere dine klasse-filer må de være lesbare for alle (chmod 644). Vi jobber med å endre konfigurasjonen slik at det er tilstrekkelig at dine klasse-filer kun er lesbare for deg (chmod 600), se FTP- og SSH-protokollen for forklaring filrettigheter på Linux og hvordan disse settes.

    Hvordan aksesserer jeg servlet?
    Vi benytter Tomcat-server til å kjøre servelet. Alle requester med sti som begynner med "webapps/servlet" sender Apache-serveren videre til Tomcat-serveren. URL for aksess av servletene over blir som følger:

    1. http://servlets.no/webapps/servlet/MittServlet1
    2. http://servlets.no/webapps/servlet/minpakke.MittServlet2
    For andre muligheter for aksess av servlet se JSP.

    Hvordan laster jeg servlet inn i Tomcat?
    Servlet lastes automatisk inn Tomcat. Ved aksess av servlet sjekkes tidsstemplet på klassefilene og web.xml om de er endret, eventuelt ny versjon lastes inn i Tomcat.
    subklasse er endret?
    Blir i mememory
    evig løkke, får bruker stoppen dem?
    getBufferSize
    setBufferSize

  • Kompilering av Java
    Alle servlet du skriver må ekstende klassen "HttpServlet" som er en del av J2EE. For å kompilere servlet-programmering på din maskin trenger du dermed i tillegg til klassehiarkiet J2SE (som er inkludert i J2SDK) også J2EE (som er inkludert i J2SDKEE). Begge SDK-er kan lastes ned fra http://java.sun.com. Husk å inkluder " j2ee.jar" i environment-variablen CLASSPATH. Environment variabler på Microsoft NT, 2000 og XP settes i fliken "Environment" i panelet "System" i katalogen "Settings". F.eks på Microsoft kan stien som må legges til CLASSPATH være: c:\j2sdkee1.3.1\lib\j2ee.jar;. For å bruke javac-kompilatoren på din maskin. bør du etter nedlasting av J2SDK oppdatere environment-variablen PATH med stien til katalogen der javac-kompliatoren ligger. F.eks kan stien på Microsoft være: c:\j2sdk1.4.1\bin\;.

    Ved SSH-tilgang til våre webhotell er det mulig å kompilere koden direkte på webhotellet. Her er verktøyene javac, emacs og ant tilgjengelig. Her følger en kort innføring for de som er vant til andre utviklingsmiljøer:

    javac
    Class-filene må plassers i katalogstruktur i henhold til pakken de tilhører. Det også vanlig å lage tilsvarende struktur over kildefilen (.java-filene). Denne struktureringen støttes av "javac". Bruk av atributtet "-d" gjøre at class-filene blir automatisk plassert i korrekt katalog i henholdt til package-direktivetet i kilde-filen. Atributtet "-d" tar som parameterverdi katalogen hvor klasse-hiarket skal plasseres. Til atributtet "-sourcepath" kan oppgi en semikolon-separarert liste av katalognavn. Hver av katalog kan innholdene et hiarki av kildefiler. Kilder-filen er plassert i hiarket i overstemmelse med package-direktivet i filen. Javac vil dermed i tillegg til å kompilere filen en ønsker også sjekke i kilde-hiarkiet om filer som importeres er blitt endret og eventuelt automatisk kompilere disse.

    I eksemplene nedenfor antar vi at vi befinner oss hjemmekatalogen på webhotellet der filene "MittServlet1.java" og "MittServlet2.java" eksisterer. Videre antar vi at "MittServlet2.java" innholder direktivet "package minpakke;". Her vil class-filene plasseres i katalogen "webapps/WEB-INF/classes/" og "webapps/WEB-INF/classes/minpakke/".

    • javac -d webapps/WEB-INF/classes/ MittServlet1.java
    • javac -d webapps/WEB-INF/classes/ MittServlet2.java
    Antar vi videre at MittServlet2.java kaller på en metode i klassen "minpakke.util.add" der "add.java" befinner seg katalogen "src/minpakke/util/". Vil følgende kommando føre til at også denne filen automatisk blir kompilert (her har vi for ordensskyld flyttet "MittServlet2.java" til katalogen "src/minpakke"):
    • javac -d webapps/WEB-INF/classes/ -sourcepath src/ src/minpakke/MittServlet2.java

    emacs
    For endre på koden kan emacs-benyttes (se omtale under SSH). I emacs kan også kompilering koden å få feilmeldingene i et eget vindu. Gi kommandoen "Alt-X compile" trykk enter og skrive inn selve javac-kommandoen slik den er omtalt over.

    ant

    jar

    Eksempel: Form to mail
    For å lese ut innhold av en HTML-form og formidle dette pr. mail kan følgende gjøres:
    • Du kan lages en web.xml fil, som må plasseres i "webapps/WEB-INF" katalogen, for å oppgi innparametre til. Hensikten med filen er å unngå å endre selve koden for variable verdier. Her følger eksempel på en web.xml fil er vi definerer følgende fire parametere for a1-klassen: avsender, tema, melding og lesFil.

      <?xml version="1.0" encoding="ISO-8859-1"?>
      <!DOCTYPE web-app PUBLIC
      "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
      "http://java.sun.com/j2ee/dtds/web/web-app_2_2.dtd">

      <web-app>
      <servlet>
      <servlet-name>a1</servlet-name>
      <servlet-class>a1</servlet-class>

      <init-param>
      <param-name>avsender</param-name>
      <param-value>info@registrar.no</param-value>
      </init-param>
      <init-param>
      <param-name>tema</param-name>
      <param-value>Demo av Javascript og Servlet</param-value>
      </init-param>
      <init-param>
      <param-name>melding</param-name>
      <param-value>Denne mail er utsendt av et test eksempel vi har av Javascript og Servlet, der vi vi oppfordrer kunder til å skrive inn egen e-postadresse. Vi beklager om oppgitt e-postadresse ikke er korrekt. E-postadressen og eventuell annen oppgitt informasjon er uansett ikke lagret hos oss.\n\nVennlig hilsen\nREGISTRAR.NO</param-value>
      </init-param>
      <init-param>
      <param-name>lesFil</param-name>
      <param-value>/home/no/servl_2/webapps/WEB-INF/web.xml>
      </init-param>

      </servlet>
      </web-app>

    • Alle servlet ekstender "HttpServlet". I denne klassen må du vanligvsi overskriv metodene init, doGet og doPost. For slippe å oppgi fullstendig klassenavn importer vi også en del pakker.
      import java.io.*;
      import java.util.*;
      import javax.servlet.*;
      import javax.servlet.http.*;
      
      public class a1 extends HttpServlet {
      
            public void init() throws ServletException {/*Her skiver du din kode/*}
      
            public void doGet(HttpServletRequest request, HttpServletResponse respons)
      	throws IOException, ServletException {/*Her skiver du din kode/*}
      
            public void doPost(HttpServletRequest request, HttpServletResponse respons)
      	throws IOException, ServletException {/*Her skiver du din kode/*}
      }
      
      
    • Hver gang servlet-et lastes inn i Tomcat kalles init-metoden. Eventuelle parameterverdier oppgitt web.xml leses vanligvis av denne metoden. Metoden getInitParameter med parameternavnet som argument benyttes for å lese parameterene i web.xml. Metoden er medlem av ServletConfig. For å få tak tak i en instans av ServletConfig benyttes getServletConfig-metoden som HttpServlet-klassen arveav GenericServlet-klassen. HttpServlet-klassen ekstender GenericServlet-klassen.
      String avsender;
      String tema;
      String melding;
      String lesFil;
      
      public void init() throws ServletException{
              ServletConfig config=getServletConfig();
      	avsender=config.getInitParameter("avsender");
      	tema=config.getInitParameter("tema");
      	melding=config.getInitParameter("melding");
      	lesFile=config.getInitParameter("lesFil");
      }
      
    • Hver gang servlet vekkes til live kalles service-metoden. Metoden sjekker hvilken HTTP-metode som HTTP-requesten innholder og kaller tilhørende doGet-, doPost-, doHead-, doPut, doTrace-, doOptions eller doDelete-metode. Vanligvis behandles GET- og POST-request likt. For å slippe å skrive to like metoder benytter seg gjerne av at den ene metoden kaller den andre. Her er eksempel på at doPost kaller doGet:
      public void doPost(HttpServletRequest request,
                            HttpServletResponse response)
      	throws IOException, ServletException
          {
      	doGet(request, response);
      }
      
      
    • I doGet-metoden behandler vi HTTP-requesten og returner respons-melding tilbake til klient. Respons-melding vil vannligvis innholde en god del HTML. For å slippe å endre på servlet-koden ved mindre endringer i HTML-koden bør servlet-et lese HTML-koden fra en fil. Antar vi at stien til HTML-fil er lest inn i s string-variablen "lesFil", kan vi åpne et BufferedReader ved følgende kode. For å lese ut linjer fra filen kaller på metoden "readLine()" i BufferedReader instansen.
      File file=new File(lesFil);
      FileReader fileR=new FileReader (file);
      BufferedReader fileBR=new BufferedReader (fileR);
      
      String linje=fileBR.readLine();
      
    • For å skrive "body" i respons-meldingen må en først få tak en peker til PrintWriter i instansen av HttpSerlvetRespons. Aktuell instans av HttpServletRespons er oppgitt som paramerverdi til doGet, i vårt eksempel har vi kalt denne "response".
      PrintWriter out = respons.getWriter();
      
    • For å lese ut tilleggsopplysninger i søke- og oppdaterings-lenker benyttes getParameter-metoden. Metoden er medlem i HttpServelRequest og aktuell instans av HttpServletRequest er oppgitt som paramerverdi til doGet. I vårt eksempel har vi kalt instansen "request". For å lese verdien til paramet med navn "epost" kan følgende kode benyttes:
      String mottaker=request.getParameter("epost");
      
    • Vanligvis må respons-meldingen innholde verdier som er avhengig av request-meldingen. For å standardarisere operasjonen for å endre på HTML-koden før avsendelse er det en fordel å bruke Javascript-kode i HTML-dokumentet. Ved denne strategien trenger servlet-et kun bytte ut noe variabler i HTML-dokumentet, se Javascript koden for "Form to mail"-eksemplet. I dette eksemplet er variablene som skal byttes ut innrammet av kommentarene //REPLACE START og //REPLACE STOP. Dermed kan servlet enkelt lese alle inn alle linjer fram fra til //REPLACE START fra "fileBr" og skrive disse til "out". Servlet kan deretter inkluder nye Javascript-variabel deklarsjoner. Til slutte leser leses og inn og sendes over resten av HTML-filen.

    • For utsendelse av e-post kan klassen javax.mail.internet.MimeMessage benytts. En av konstruktørene til MimeMessage tar en instans av Session-klassen. For å få en instans av Session-klassen kan en benytte den statiske metoden i klassen kalt "getDefaultInstance". Parameter til denne klassene er en instans av Properties-klassen. Properties er en stakk der kan lagre parameteverdier assosiert med parameternavn. I aktuell instans av properties må innholde paremeternavnet "mail.smtp.host" der verdiener domene eller ip-adresse til mailserver. For å spesifisere mottager, avsender, innhold se av generelt documentasjon av java klasse API.
      static Properties props = new Properties();
      static {props.put("mail.smtp.host", "w6.registrar.no");}
      static Session session = Session.getDefaultInstance(props, null);
      

    Komplett kode for vårt eksempel "Mail to form":
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.util.*;
    import javax.mail.*;
    import javax.mail.internet.*;
    
    public class a1 extends HttpServlet {
        String mottaker;
        String avsender;
        String tema;
        String melding;
        String lesFil;
    
        static Properties props = new Properties();
        static {props.put("mail.smtp.host", "217.116.81.10");}
        static Session session = Session.getDefaultInstance(props, null);
    
    
        public void init() throws ServletException{
    	ServletConfig config=getServletConfig();
    	avsender=config.getInitParameter("avsender");
    	tema=config.getInitParameter("tema");
    	melding=config.getInitParameter("melding");
    	lesFile=config.getInitParameter("lesFil");
        }
    
    
        public void doGet(HttpServletRequest request,
                          HttpServletResponse respons)
    	throws IOException, ServletException
        {
    	//Sende epost
    	try{
    	    mottaker=request.getParameter("epost");
    	    Message message = new MimeMessage(session);
    	    message.setFrom(new InternetAddress(avsender));
    	    message.addRecipient(Message.RecipientType.TO, new InternetAddress(mottaker));
    	    message.setSubject(tema);
    	    message.setText(melding);
    	    Transport.send(message);
    	}
    	catch(Exception e){
    	    ;
    	}
    
    
    	//skrive respons
    	respons.setContentType("text/html");
    	PrintWriter out = respons.getWriter();
    
    
    	File file=new File(lesFil);
    	FileReader fileR=new FileReader (file);
    	BufferedReader fileBR=new BufferedReader (fileR);
    
    	String linje=fileBR.readLine();
    	while (linje!=null && !(linje.equals("//REPLACE START"))) {
    	    out.println(linje);
    	    linje=fileBR.readLine();
    	}
    
    
    	linje=fileBR.readLine();
    	out.println("var s=2;");
    	out.println("var epost=\""+mottaker+"\";");
    
    	linje=fileBR.readLine();
    	while (linje!=null && !linje.equals("//REPLACE STOP")) {
    	    linje=fileBR.readLine();
    	}
    	
    	while (linje!=null) {
    	    out.println(linje);
    	    linje=fileBR.readLine();
    	}       
    }
    
        public void doPost(HttpServletRequest request,
                          HttpServletResponse respons)
    	throws IOException, ServletException
        {
    	doGet(request, respons);
        }
    
    }
    

    Konfigurasjonfilen web.xml
    Konfigurasjonfilen web.xml
    Det kan plassers en konfigurasjonfil kalt web.xml i katalogen webapps/WEB-INF/, f.eks.
    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Application 2.2//EN"
    "http://java.sun.com/j2ee/dtdts/web-app_2_2.dtd">

    <web-app>
    <servlet>
    <servlet-name>MittServlet2</servlet-name>
    <servlet-class>minpakke.MittServlet2</servlet-class>
    <init-param>
    <param-name>parameter1</param-name>
    <param-value>verdi1</param-value>
    </init-param>
    </servlet>
    </web-app>

    Den kan brukes til å sette parametere og gi alias navn til servlet.

    Cookie API
    Cookies kan benyttes til å identinfisere brukeren ved at det lagre data i netteleseren. Nettlesere kan lagre opptil 20 coockies for hvert hoveddomene med opptil 4KB med data. Cookie sendes av klient til server i HTTP-hodefeltet: Cookie. Server sende cookie til klient i HTTP-hodefeltet: Set-Cookie. For mer generell forklaring av cookie se, her.

    Eksempel på kode for å generere cookie som kan leve opptil 1. år i nettleseren:
    Cookie nyKake=new Cookie("navn","verdi");
    nyKake.setMaxAge(60*60*25*365*); 
    response.addCookie(nyKake);

    For å lese cookies som sendes av klient benyttes metoden getCookies i instans av HttpServletRespons. Metoden returnerer en array av Cookie eller null. For å finne ønsket cookie går en i en løkke igjennom arrayen og kaller på getName metoden.

    Cookie-klassen har følgende get- og set-metoder.

    • public String getComment(), public void setComment(String comment)
      I cookie version 0 blir ikke eventuelle kommentarer en setter sendt til klient.
    • public String getDomain(), public void setDomain(String domainPattern)
      Atributtet kan utvide domenerommet klienten vil returne cookien for. Dette er begrenset oppad til 2.nivå domener, slik at du ikke kan lage cookes som returners f.eks for alle .no-domener.
    • public String getMagAge(), public void setMageAge(int lifetime)
      Angir hvor mange sekunder cookien skal leve. Default verdi er en negativ verdi som betyr at cookien kun skal leve til nettleseren lukkes og lagres ikke på disk. Settes verdien til 0 vil nettleseren slette cookien.
    • public String getName(), public void setName(String cookieName)
      Leser ut navn til og setter navn på cookie.
    • public String getPath(), public void setPath(String path)
      Atributtet kan utvide hvilket katalog-område klienten vil returnere cookien for.
    • public String getSecure(), public void setSecure(String secureFlag)
      Setter en boolan som indikere at cookie bare skal sendes over kryptert forbindelse. Default er false.
    • public String getValue(), public void setValue(String cookieValue)
      Leser ut verdi lagret i cookie og skrive verdi til cookie.
    • public String getVersion(), public void setVersion(String version)
      Version 0 er default (Netscape spesifikasjonene). Version 1 støttes ikke av eldre nettlesere.

    Session API
    HTTP er i utgangspunktet en stateless protokoll som ikke støtter identifikasjon av bruker (innlogging). Session API'et identifiserer hver bruker med en unik id. Identifesering skjer ved hjelp cookies eller URL-omskrivning. Ved URL-omskrivning legges en unik identifikasjon til enhver url. API'et vil benytte cookies om nettleseren støtter dette.

    Følgende kode henter ut brukeridentifkasjon eller lager en ny identifikasjon om den ikke eksisterer:
    HttpSession session=request.getSession(true);

    HttpSession innholder en hashtabelle som lagres lokalt på serveren. I hastabellen kan en lagre informasjon tilknyttet sesjonen. HttpSession innholder følgende metoder for å lagre og lese informasjon fra hashtabellen, samt metoder for å lese og sette cookie verdier.

    • public Object getAttribute(String name)
      Metoden leser ut lagret verdi i hastabellen. Metoden returnerer null om ikke atributtet eksisterer.
    • public void setAttribute(String name, Object value)
      Metoden setter en verdi i hashtabellen. Eksisterer atributtet fra før vil lagret verdi bli overskrevet.
    • public void removeAttribute(String name)
      Fjerner atributt fra hashtabellen.
    • public Enumeration getAttributeNames()
      Returnerer en list med navn på alle atributter.
    • public String getId()
      Leser ut brukeridentifikasjonen som benyttes i cookies.
    • public boolean isNew()
      Sjekker om brukeridenfikasjonen er ny eller gammel kan metoden isNew benyttes
    • public long getCreationTime()
      Returner tidspunkt når cookie ble laget av server. Tidspunkt angis i antall millisekunder etter januar 1 1970.
    • public long getLastAccessedTime()
      Returner tidspunkt når cookie cookie sist ble sendt fra klient. Tidspunkt angis i antall millisekunder etter januar 1 1970.
    • public int getMaxInactiveInterval(), public int setMaxInactiveInterval()
      Leser eller setter antall sekunder sesjonen skal være aktiv etter siste mottatte cookie.
    • public void invalidate()
      Metoden stopper sesjonen. Tilknyttet hashtabell med informasjon og andre data slettes.

    Eksempel: SQL-form