7.1 Servletter 135
7.1.1 Anmodningsmetoder 137
7.1.2 Hvornår bruge JSP og hvornår bruge servletter 137
7.2 Installation af en servlet 138
7.2.1 Flere URLer til samme servlet 138
7.2.2 Avanceret: Automatisk binding af servletter 139
7.3 Avanceret: JSP-siders interne virkemåde 139
7.3.1 Kigge i de genererede servletter 139
7.3.2 Eksempel 139
7.3.3 JSP-siders livscyklus 141
7.4 Webapplikationer 142
7.4.1 Pakkede webapplikationer (WAR-filer) 142
7.5 Samlet driftsbeskrivelse (web.xml) 143
7.6 Test dig selv 146
7.7 Resumé 146
Dette kapitel er frivillig læsning; det forudsættes ikke i resten af bogen.
Det forudsætter kapitel 3, Interaktive sider, og kapitel 5, Brug af databaser.
Dette kapitel handler om konfiguration af webserveren og nogle af de ting, der sker "under motorhjelmen", inde i webserveren.
En servlet er en Java-klasse, der bliver brugt af en webserver. Den har noget programkode, der opbygger et HTML-dokument, som bliver sendt til klienten.
Her er en servlet, der udskriver det samme som JSP-siden syvtabellen.jsp (fra afsnit 2.2.1, Indlejrede java-udtryk):
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class SimpelServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head><title>Syvtabellen - fra en servlet</title></head>"); out.println("<body>"); out.println("<p>Her er syv-tabellen:<br>"); for (int i=1; i<=10; i++) { out.println("Syv gange "+ i +" er: "+ 7*i +".<br>"); } out.println("</body>"); out.println("</html>"); } }
Læg mærke til:
Servlet-klassen skal arve fra HttpServlet
Servletten skal have en doGet(request, response)-metode1
Ud fra response-objektet får man et out-objekt, som man kan bruge til at skrive HTML-kode til klienten/netlæseren.
Uddata fra en servlet er som regel HTML, men kan egentlig være af enhver slags. Servletten kan sende andre slags data, e.v.t. binære, eller viderestille til en anden adresse.
Når webserveren får en anmodning om en URL, der svarer til servlettens navn2, kalder den metoden doGet() på servletten (allerførste gang opretter serveren et objekt af den pågældende klasse). Denne metode får overført alle relevante oplysninger om anmodningen i et request-objekt og skal så udfylde et response-objekt med svaret til klienten.
For at afprøve servletten (forudsat vi har oversat til binær kode og installeret det i en webserver) kalder vi f.eks. adressen http://localhost:8080/JSP/servlet/SimpelServlet op i en netlæser (man ser at servlettens navn normalt indgår i URLen).
Som diskuteret i afsnit 3.6.4, Skjule parametrene (POST-metoden), findes der flere metoder en netlæser kan tage i anvendelse, når den skal foretage en forespørgsel (GET og POST).
GET-anmodninger forårsager at servlettens doGet(request, response)-metode bliver kaldt.
Tilsvarende forårsager POST-anmodninger, at metoden doPost(request, response) kaldes.
Ofte er man dog ligeglad med, om anmodninger kommer med den ene eller anden metode og så lader man blot doPost() kalde doGet(), som så gør arbejdet:
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
doGet(request, response);
}
Hvilken anmodningsmetode, der bruges, kan altid ses med request.getMethod().
Servletter er som sagt javakode (Java-klasser), der genererer HTML-kode.
JSP er på en måde det omvendte: HTML-kode med indlejret Javakode.
Er du i tvivl om du skal bruge JSP-sider eller servletter til en given opgave, så er her et par betragtninger, du kan tage med i dine overvejelser:
Som enhver anden Java-klasse skal en servlets .java-fil oversættes til en binær .class-fil, som skal lægges i WEB-INF/classes/
Alle servletter skal nævnes i WEB-INF/web.xml (se afsnit 7.2, Installation af en servlet)
JSP-sider kan genkendes og redigeres visuelt i de fleste ordentlige HTML-redigeringsværktøjer. Det vil sige, at man ikke behøver at skrive al HTML-koden selv.
Servletter kan, som alle andre klasser, genkendes og redigeres af Java-udviklingsværktøjer. Værktøjerne kan dog ikke hjælpe dig med at lave HTML-koden i servletten.
Alt i alt er servletter mest velegnede til indviklet programlogik, mens JSP-sider er velegnede, hvis der skal produceres meget HTML til klienten. Er du begynder, bør du nok vælge JSP-sider, da de er lettest at komme i gang med.
Før du kan køre en servlet, skal du angive servlet-klassen, der svarer til en URL på webserveren. Det gøres i filen web.xml (der skal ligge i mappen WEB-INF), hvor der skal stå:
Navnet på servletten i <servlet-name>
Klassenavnet (incl. pakkenavn) i <servlet-class>
Hvilke(n) URL(er) på serveren der skal omdirigeres til servletten i <url-pattern> i en <servlet-mapping>
Her er et uddrag af web.xml. Gennem navnet "En simpel servlet" bindes klassen SimpelServlet til URLen /servlet/SimpelServlet:
<web-app> ... <servlet> <servlet-name>En simpel servlet</servlet-name> <servlet-class>SimpelServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>En simpel servlet</servlet-name> <url-pattern>/servlet/SimpelServlet</url-pattern> </servlet-mapping> ... </web-app>
Denne syntaks løsriver klassenavnet fra URLen og giver dermed mulighed for mange fikse måder at sætte sin webapplikation op på.
Vi kunne f.eks. sende alle forespørgsler til /simpel/* til vores SimpelServlet ved at tilføje:
<servlet-mapping> <servlet-name>En simpel servlet</servlet-name> <url-pattern>/simpel/*</url-pattern> </servlet-mapping>
Herefter ville f.eks. http://localhost:8080/JSP/simpel/hvad.som.helst få webserveren til at kalde SimpelServlet.
Et praktisk eksempel på, hvor dette kunne være nyttigt, findes i afsnit 10.5.3, Eksempel på en Frontkontrol.
En webapplikation er en gruppe websider, der hører sammen. En webserver kan godt have flere webapplikationer kørende samtidig og oprette/installere, fjerne og opdatere webapplikationer uafhængigt af hinanden.
På harddisken har serveren normalt hver webapplikation liggende i en separat mappe. I Tomcat ligger disse mapper under webapps/.
På billedet til højre kan man på mappestrukturen se, at der er installeret 5 webapplikationer, nemlig "JSP", "jsp-examples", "ROOT", "servlet-examples" og "tomcat-docs".
Disse kan findes under en URL, der svarer til navnet. F.eks. ligger webapplikationen "jsp-examples" på http://localhost:8080/jsp-examples/ (eneste undtagelse er ROOT som ligger i roden, på http://localhost:8080 ).
HTML- og JSP-sider, billeder etc. ligger som filer i webapplikationens mappe. I den specielle undermappe WEB-INF/ ligger alle andre filer:
I WEB-INF/classes skal dine egne klasser ligge.
I WEB-INF/lib skal du lægge JAR-filer med funktioner, der bruges i dine JSP-sider.
I WEB-INF/web.xml skal driftsbeskrivelsen til serveren ligge (se afsnit 7.5).
Nogen gange kan filstrukturen afvige fra, hvad man forventer ud fra URLen, fordi det står angivet i WEB-INF/web.xml (se afsnit 7.2). Det gælder især servletter. Således kunne SimpelServlet, der ligger webapplikationen "JSP" i filen WEB-INF/classes/SimpelServlet.class, være afbildet over på URL-adressen http://localhost:8080/JSP/servlet/SimpelServlet .
En webapplikation kan være pakket ned i en WAR-fil (Web ARchive), der er en ZIP-fil med en mappestruktur, der svarer til, hvordan filerne skal ligge på serveren.
En WAR-fil kan kopieres ind i mappen webapps i Tomcat. Derefter vil webserveren selv pakke den ud og idriftsætte den.
På billedet ovenfor kan man nederst se hvordan WAR-filen JSP.war er blevet kopieret til webapps/JSP.war, hvorefter webserveren har pakket ud i webapps/JSP/ , så den er tilgængelig på adressen http://localhost:8080/JSP/.
Selvom princippet i WAR-filer egentlig er enkelt nok, er der mange, der til at starte med, har problemer med at lave WAR-filer. Bruger du et udviklingsværktøj, bør du se, om det kan hjælpe dig med at generere WAR-filen. Ellers er det nemmeste ofte, at tage en eksisterende WAR-fil (tjek at den virker!) og erstatte filerne i den med dine egne.
Filstrukturen og mappestrukturen i en WAR-fil skal være præcist som den på harddisken, især skal man huske at WEB-INF/ skal ligge i roden af ZIP-filen. Her er et eksempel:
Det er i webapplikationens WEB-INF/web.xml man beskriver, hvordan serveren skal køre ens webapplikation i drift.
Her ses hvordan driftsbeskrivelsen web.xml samlet ser ud for eksemplerne til denne bog.
web.xml - driftsbeskrivelse for webapplikationen
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <!-- Samlet eksempel på konfigurationsfil for en webapplikation. Filnavn: /WEB-INF/web.xml --> <display-name>Eksempler fra javabog.dk</display-name> <description>Alle eksemplerne fra bogen "Webprogrammering med Java Server Pages", der også kan læses på http://javabog.dk/JSP</description> <!-- ================================================================ Eksempler på initialiseringsparametre - se afsnit 4.5.5 i bogen Aflæs med f.eks: application.getInitParameter("dbDriver") ================================================================ --> <context-param> <description>Driveren til databasen</description> <param-name>dbDriver</param-name> <param-value>com.mysql.jdbc.Driver</param-value> </context-param> <context-param> <description>Adressen (URLen) på databasen</description> <param-name>dbUrl</param-name> <param-value>jdbc:mysql:///test</param-value> </context-param> <context-param> <description>Brugernavnet til databasen</description> <param-name>dbBruger</param-name> <param-value>root</param-value> </context-param> <context-param> <description>Adgangskoden til databasen</description> <param-name>dbAdgangskode</param-name> <param-value></param-value> </context-param> <!-- Denne initialiseringsparameter er til JSTLs databasetags i afsnit 6.3 --> <context-param> <param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name> <param-value>jdbc:mysql:///test,com.mysql.jdbc.Driver</param-value> </context-param> <!-- Disse initialiseringsparametre er til Login-bønnen i afsnit 9.5 --> <context-param> <description>SMTP-server for epost fra Login-bønnen i afsnit 9.5</description> <param-name>postserver</param-name> <param-value>post.tele.dk</param-value> <!-- TDC som internetudbyder --> </context-param> <context-param> <description>Afsenderadressen for Login-bønnen i afsnit 9.5</description> <param-name>postafsender</param-name> <param-value>din@adresse.dk</param-value> </context-param> <!-- ================================================================ Indstillinger til afsnit 7.1, Servletter ================================================================ --> <servlet> <servlet-name>En simpel servlet</servlet-name> <servlet-class>SimpelServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>En simpel servlet</servlet-name> <url-pattern>/servlet/SimpelServlet</url-pattern> </servlet-mapping> <!-- Alle forespørgsler til /simpel/* sendes til vores SimpelServlet --> <servlet-mapping> <servlet-name>En simpel servlet</servlet-name> <url-pattern>/simpel/*</url-pattern> </servlet-mapping> <!-- Bind alle klasser (herunder også servletter) til /servlet/Klassenavn --> <!-- Kommenteret bort af sikkerhedshensyn <servlet> <servlet-name>invoker</servlet-name> <servlet-class>org.apache.catalina.servlets.InvokerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping> --> <!-- ================================================================ Indstillinger til afsnit 8.2, Adgangskontrol ================================================================ --> <!-- De roller, der er aktuelle for webapplikationen --> <security-role> <role-name>kunde</role-name> <role-name>administrator</role-name> </security-role> <!-- En gruppe sider med adgangbegrænsning --> <security-constraint> <display-name>Sikkerhedsbegraensning i kapitel 8</display-name> <!-- Præcist hvilke sider, der er omfattet af adgangbegrænsningen --> <web-resource-collection> <url-pattern>/kode/kapitel_08/beskyttet_side.jsp</url-pattern> </web-resource-collection> <!-- Hvilke brugerroller har adgang til de pågældende sider --> <auth-constraint> <role-name>kunde</role-name> <role-name>administrator</role-name> </auth-constraint> <!-- Hvordan skal data sendes over netværket --> <!-- Mulighederne er: NONE, INTEGRAL og CONFIDENTIAL (kræver SSL) <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> --> </security-constraint> <!-- Brugeren skal identificeres med en login-formular --> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/kode/kapitel_08/loginside.jsp</form-login-page> <form-error-page>/kode/kapitel_08/fejlagtig_login.jsp</form-error-page> </form-login-config> <!-- Andre muligheder er (giver et loginvindue i stedet for login-formular) <auth-method>BASIC</auth-method> <auth-method>DIGEST</auth-method> <auth-method>CLIENT-CERT</auth-method> --> </login-config> <!-- ================================================================ Indstillinger til kapitel 10, Arkitekturer i webprogrammering ================================================================ --> <!-- Forespørgsler til /kode/kapitel_10/ sendes til kontrol.jsp --> <servlet> <servlet-name>Kontrolloer</servlet-name> <jsp-file>/kode/kapitel_10/kontrol.jsp</jsp-file> </servlet> <servlet-mapping> <servlet-name>Kontrolloer</servlet-name> <url-pattern>/kode/kapitel_10/</url-pattern> </servlet-mapping> <!-- Frontkontrol: Alt der starter med /bank sendes til kontrol.jsp --> <servlet> <servlet-name>Frontkontrol</servlet-name> <jsp-file>/WEB-INF/bank/kontrol.jsp</jsp-file> </servlet> <servlet-mapping> <servlet-name>Frontkontrol</servlet-name> <url-pattern>/bank/*</url-pattern> <!-- Bemærk: * i URL-mønster --> </servlet-mapping> </web-app>
1Man kan også definere andre metoder, se senere.
2I afsnit 7.2 vil vi se, hvordan man binder en servlet til en URL.