Servlet - Lebenszyklus Beispiel: Keine Threadsicherheit (1/2) Laden meist ein wiederverwendetes Exemplar Instanziieren response init() init() Bearbeiten service() service() Aufruf von doGet() doGet() oder doPost() doPost() Löschen Komponentenbasierte SoftwareEntwicklung @Override public void init() init() { zv = 42; } new MyServlet() MyServlet() Initialisieren request public class TimerServlet extends HttpServlet { private int zv; zv; // unü unüblich static{...} static{...} für Entwicklung relevant destroy() destroy() Prof. Dr. Stephan Kleuker 166 Beispiel: Keine Threadsicherheit (2/2) protected void processRequest(HttpServletRequest request, request, HttpServletResponse response) response) throws ServletException, ServletException, IOException { response.setContentType("text/html;charset=UTFresponse.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); response.getWriter(); out.println((new Date()) + " <br <br> br> "); int tmp=zv; tmp=zv; try { Thread.sleep(10000); } catch (InterruptedException (InterruptedException ex) {} zv = tmp+1; out.println("Wert: out.println("Wert: " + zv); zv); out.close(); out.close(); }... Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 167 Berechnen und Weiterleiten (1/2) public class MachA extends HttpServlet { protected void processRequest(HttpServletRequest request, request, HttpServletResponse response) response) throws ServletException, ServletException, IOException { request.setAttribute("Start", request.setAttribute("Start", new Date());//String,Object // keine responseresponse-Nutzung! Nutzung! try { Thread.sleep(10000); } catch (InterruptedException (InterruptedException ex) { } RequestDispatcher view = request. request. getRequestDispatcher("MachB"); getRequestDispatcher("MachB"); view.forward(request, view.forward(request, response); response); // nichts weiter! } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 168 Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 169 Berechnen und Weiterleiten (2/2) HHTP ist zustandslos/gedächtnislos (1/4) public class MachB extends HttpServlet { protected void processRequest(HttpServletRequest request, request, HttpServletResponse response) response) throws ServletException, ServletException, IOException { response.setContentType("text/html;charset=UTFresponse.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); response.getWriter(); try { out.println("Gestartet: out.println("Gestartet: "+request.getAttribute("Start "+request.getAttribute("Start")); request.getAttribute("Start")); out.println("<br>Beendet: out.println("<br>Beendet: "+new "+new Date()); } finally { out.close(); out.close(); } }... Klassenname in web.xml auch als Servlet-Name gesetzt Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 170 HHTP ist zustandslos/gedächtnislos (2/4) Prof. Dr. Stephan Kleuker 171 else { request.setAttribute("prog1", prog1); // nur Versuch out.println("<html><head></head>"); out.println("<html><head></head>"); out.println("<body>"); out.println("<body>"); out.println("<form name=\ name=\"a2\ "a2\" action=\ action=\"Amnesie\ "Amnesie\" " + "method= "method=\ method=\"POST\ "POST\">Programmiersprache Nr.2?"); out.println("<input type=\ type=\"text\ "text\" name=\ name=\"prog2\ "prog2\" " + "value "value= value=\"\" size=\ size=\"12\ "12\" />"); out.println("<input type=\ type=\"submit\ "submit\" " + "value= "value=\ value=\"Abschicken\ "Abschicken\" name=\ name=\"send1\ "send1\" />"); out.println("</form></body></html>"); out.println("</form></body></html>"); } } finally { out.close(); out.close(); } }... protected void processRequest(HttpServletRequest request, request, HttpServletResponse response) response) throws ServletException, ServletException, IOException { response.setContentType("text/html;charset=UTFresponse.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); response.getWriter(); String prog1 = request.getParameter("prog1"); try { if (prog1 == null) { out.println("Sprache 1: " +request.getAttribute("prog1")); out.println("<br> out.println("<br> Sprache 2: " + request.getParameter("prog2")); } else {...//nä {...//nächste Folie Prof. Dr. Stephan Kleuker Komponentenbasierte SoftwareEntwicklung HHTP ist zustandslos/gedächtnislos (3/4) public class Amnesie extends HttpServlet { Komponentenbasierte SoftwareEntwicklung <!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"> Transitional//EN"> <html> html> <head> head> <title></title> title></title> <meta httphttp-equiv="Contentequiv="Content-Type" Type" content="text/html; content="text/html; charset=UTFcharset=UTF-8"> </head </head> head> <body> body> <form name="amnesie" name="amnesie" action="Amnesie" action="Amnesie" method="POST"> method="POST"> Programmiersprache Nr.1? <input type="text" type="text" name="prog1" value="" value="" size="12" /> <input type="submit" type="submit" value="Abschicken" value="Abschicken" name="send1" /> </form> </body </body> body> </html </html> html> 172 Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 173 HHTP ist zustandslos/gedächtnislos (4/4) Session (1/2) ...String String prog1 = request.getParameter("prog1"); HttpSession session = request.getSession(true); request.getSession(true); try { if (prog1 == null) { out.println("Sprache 1: "+session.getAttribute("prog1")); out.println("<br> out.println("<br> Sprache 2: " + request.getParameter("prog2")); } else { session.setAttribute("prog1", prog1); out.println("<html><head></head>"); out.println("<html><head></head>"); ... • in web.xml wichtig: (Minuten, -1 für unbeschränkt) <sessionsession-config> config> <sessionsession-timeout> timeout> 30 </session </sessionsession-timeout> timeout> </session </sessionsession-config> config> Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 174 Session (2/2) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 175 HTTPSession • ein Objekt, dass dem Servlet zugeordnet wird • Objekt lebt von erster Servlet-Nutzung bis Nutzer Verbindung terminiert, Server terminiert, Servlet neu deployt wird oder Time-out • mit HttpSession session = request.getSession(true); request.getSession(true); erhält man Session-Objekt (mit „true“ wird neue Session erzeugt, falls keine existiert, mit „false“ erhält man null falls keine Session existiert) • Anmerkung: true kann weggelassen werden; ist default unsere Ziele: • Nutzer muss sich erst einloggen, wenn notwendig • HTTPS nur nutzen, wenn nichts anderes möglich Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 176 Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 177 Cookie zur Nutzeridentifikation Containerunterstützung für Cookies • Nutzer bekommt beim ersten Kontakt individuelle Session ID HTTP WebWeb-Server GET GET … Client … Web Server Steuerung ... HTTP … <HTML> <HTML> [Cookie] [Cookie] … Komponentenbasierte SoftwareEntwicklung Web Server Steuerung erster Kontakt: berechne ID, erstelle Cookie … ... Prof. Dr. Stephan Kleuker • wir teilen mit, ob neue Session gewünscht ist, oder Session genutzt wird • Container erzeugt Session ID • Container erzeugt Cookie mit Session ID als Inhalt • Container macht Cookie zum Teil von response • Achtung zwei Wirkungen einer Methode HttpSession session = request.getSession(true): request.getSession(true): if (request enthä enthält Cookie mit Session ID) finde Session mit der genannten ID else if (request enthä enthält keinen Cookie mit Session ID oder es gibt keine aktuelle Session mit der ID) erzeuge neue Session • Methode isNew() isNew() erlaubt Prüfung, ob Session gerade erzeugt 178 Browser ohne Cookie-Unterstützung Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 179 Garantieren von URL-Rewriting • Cookies können im Browser ausgeschaltet werden • Container ermöglicht auch hier (unsicherere) Session IDNutzung • bei ausgeschalteten Cookies liefert isNew() immer true (was ursprünglichen Ansatz verhindert) • Lösung: URL Rewriting, Parameter jsessionid in URL • In spezieller Datei des Web-Servers; Glassfish: sun-web.xml <session<session-config> config> <session<session-properties> <property name="enableCookies name="enableCookies" enableCookies" value="false" /> <property name="enableURLRewriting name="enableURLRewriting" enableURLRewriting" value="true" /> </session</session-properties> </session</session-config> config> • URL-Rewriting bei Weiterleitung: response.encodeRedirectURL( response.encodeRedirectURL("/Mach2" /Mach2"); • Ansatz: immer wenn URL (Pfad) ausgegeben werden soll, dann encode nutzen Generell bei der Entwicklung • Browser nach Nutzung schließen! • out.println("<form name=\ name=\"a2\ "a2\" action= action=\"" +response.encodeURL("/ServletSpielerei4/Amnesie2") +"\ +"\" method=\ method=\"POST\ "POST\">Programmiersprache Nr.2?"); Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 180 Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 181 Irritationsversuch mit Session Phishing (geht so auch ohne Cookie und Servlet) :NaiverNutzer :ITBoesewicht Email: Gratis auf www.bankk.de Geht auf Seite www.bankk.de Session-Cookie+ Login? ID+Passwort+ Session-Cookie Peinliche Daten+ Session-Cookie :Servlet Verbindung zu www.bank.de Session-Cookie ID+Passwort+ Session-Cookie Peinliche Daten+ Session-Cookie Bösewicht kann sich nach Passworterhalt ausklinken Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 182 Phishing mit Session ID :NormalerNutzer Prof. Dr. Stephan Kleuker 183 Weitere interessante Möglichkeiten :ITBoesewicht :UnerfahrenesServlet Verbindung zu www.bank.de Email: Gratis auf Session ID www.bank.de/jsession mit Session ID Geht auf Seite www.bank.de mit Session ID Session ID+Login? ID+Passwort+Session ID nutzt Session ID für eigene Entdeckungen Gegenmaßnahmen: - Timeout für Sessions setzen - session.invalidate() session.invalidate() um Session bei Login zu beenden - nach Login neue Session ID vergeben Komponentenbasierte SoftwareEntwicklung Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 184 • Event-Listener (welchen Zustandswechsel führt ein Servlet aus, welches Attribut ändert sich, ..) z. B. Zählen aktiver Sessions • Servlet kann Parameter im Deployment Descriptor haben, die gelesen werden können • HTTPSession-Objekte können serialisiert werden und von einer zur anderen virtuellen Maschine wandern • Applikation (Summe der zusammengehörigen Servlets) kann (Context-) Parameter im Deployment Descriptor haben, die gelesen werden können Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 185 Vorgehensweise 5. JavaServer Pages • • • • Prinzip: Java in HTML Typisches Tags JSP-Lebenszyklus MVC2 • Bekannt: Servlets erlauben Erstellung von WebApplikationen, leider viel HTML in Java • JSP-Ansatz: Java in HTML einbetten • Hier zunächst: JSP-Grundlagen getrennt betrachten • Späteres Ziel: Vereinigung von Servlets, JSP, JavaBeans, JPA zur strukturierten mehrschichtigen Software Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 186 Einführendes Beispiel Prof. Dr. Stephan Kleuker 187 Typische Sprachelemente <%@page <%@page contentType="text/html" contentType="text/html" pageEncoding="UTFpageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN" Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> html> <head> head> <meta httphttp-equiv="Contentequiv="Content-Type" Type" content="text/html; content="text/html; charset=UTFcharset=UTF-8"> <title>Zahlen</title> title>Zahlen</title> </head </head> head> <%@page <%@page import="java.util.List, import="java.util.List, java.util.ArrayList" java.util.ArrayList" %> <%! List<Integer> List<Integer> zahlen = new ArrayList<Integer>();%> ArrayList<Integer>();%> <% for (int i = 1; i < 10; i = i + 3) zahlen.add(i); zahlen.add(i); %> <body> body> <h3>Zahlen!</h3> <ul> ul> <% for (Integer i : zahlen) { %> <li> li> <%=i%> </li </li> li> <% }%> </ul </ul> ul> </body </body> body> </html </html> html> Komponentenbasierte SoftwareEntwicklung Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 188 • <%@ page [eigenschaften] eigenschaften] %> Direktiven, hier Seiteneigenschaften, Info für Container • <%! [Deklaration] %> Deklaration von in der Seite nutzbaren Methoden, Variablen • <% [Programmstü [Programmstück] %> Ausführbare Code-Fragmente (Scriptlets) • <%= [Ausdruck] %> Auswertbarer Ausdruck, nutzt toString() toString() • Anmerkung: Gibt auch reine XML-Syntax (wesentlich sauberer, aber später eingeführt und längere Tipperei, daher seltener genutzt) <jsp:directive.page [eigenschaften] eigenschaften] /> Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 189 JSPs sind Servlets Implizite Objekte - Ausschnitt (1/2) C:\Sun\AppServer\domains\domain1\generated\jsp\j2ee-modules\JSPSpielerei1\org\apache\jsp public final class index_jsp extends // aus index.jsp org.apache.jasper.runtime.HttpJspBase...{ org.apache.jasper.runtime.HttpJspBase...{ List<Integer> List<Integer> zahlen = new ArrayList<Integer>(); ArrayList<Integer>(); ... public void _jspService(HttpServletRequest request, request, HttpServletResponse response) response) throws java.io.IOException, java.io.IOException, ServletException {... try { response.setContentType("text/html;charset=UTFresponse.setContentType("text/html;charset=UTF-8"); response.setHeader("Xresponse.setHeader("X-PoweredPowered-By", By", "JSP/2.1"); ... for (int i = 1; i < 10; i = i + 3) zahlen.add(i); zahlen.add(i); ... for (Integer i : zahlen) { out.write("\ out.write("\n"); out.write(" <li out.write(" <li>"); li>"); out.print(i); out.print(i); out.write("</li>\ out.write("</li>\n"); out.write(" "); out.write(" }... Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 190 Implizite Objekte - Ausschnitt (2/2) <%@page pageEncoding="UTF<%@page contentType="text/html" contentType="text/html" pageEncoding="UTF -8"%> <html> html> <head> head> <title>Implizite <title>Implizite Objekte</title> Objekte</title> </head </head> head> <% response.setContentType("text/html;charset=UTFresponse.setContentType("text/html;charset=UTF-8"); %> <% if (session.isNew()) session.isNew()) { session.setAttribute("Zaehler", session.setAttribute("Zaehler", 1); } %> <body><form name="f1" action="index.jsp" action="index.jsp" method="POST"> method="POST"> <% if (request.getParameter("n") request.getParameter("n") != null){%> letzte Nachricht: <%=request.getParameter("n <%=request.getParameter("n")%> request.getParameter("n")%> <br <br> br> <% ;}%> Nachricht:<input type="text" type="text" name="n" name="n" value="" value="" size="12" /> <% int anzahl = (Integer) session.getAttribute("Zaehler"); session.getAttribute("Zaehler"); out.println("<br> out.println("<br> Ihre Aufrufe: " + (anzahl++)+"<br (anzahl++)+"<br>"); anzahl++)+"<br>"); session.setAttribute("Zaehler", session.setAttribute("Zaehler", anzahl); anzahl); %> <input type="submit" type="submit" value="Weiter" value="Weiter" name="w1" /> </form></body </form></body> form></body> </html </html> html> Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 191 JSP - Lebenszyklus JSP-Seite in Servlet übersetzen [ja] JSP-Seite kompilieren Erster Aufruf? Klasse laden [nein] Instanziieren Initialisieren jspInit() jspInit() request Bearbeiten _jSPservice() service() response Löschen Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 192 Komponentenbasierte SoftwareEntwicklung für Entwicklung relevant jspDestroy() jspDestroy() Prof. Dr. Stephan Kleuker 193 Nutzung von Beans (1/2) Nutzung von Beans (2/2) • Generell können in Servlets und JSPs selbst entwickelte JavaKlassen (POJO, Plain Old Java Objects) direkt genutzt werden • Um möglichst wenig Java in JSPs zu haben existieren sogenannte Aktionselemente (Action Elements) • Idee: XML-artige Erzeugung und Nutzung von Beans • Beanerzeugung <jsp:useBean id="kunde" id="kunde" class="entities.Kunde" class="entities.Kunde" /> entspricht kunde = new entities.Kunde(); entities.Kunde(); id: (Variablen-)Name, auch kunde.getAdresse() kunde.getAdresse() möglich class: voll qualifizierter Klassenname scope: Gültigkeitsbereich (page, request, session, application) type: Typ der Variablen kunde Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker request response JavaBean 195 public Kunde(){} schreibt JSP Prof. Dr. Stephan Kleuker package entities; entities; public class Kunde { private String name; name; private int alter; private String Adresse; Servlet übergibt Kontrolle (und request) request) Komponentenbasierte SoftwareEntwicklung Kombination von HTML, Servlets und JSP (1/6) • Ansatz heißt Model-View-Controller 2 (MVC2) Controller entspricht kunde.setAdresse( kunde.setAdresse("XStr. XStr. 42" 42"); name: vergebene id property: name der zu ändernden Eigenschaft value: Wert (wird konvertiert, wenn möglich) param: Alternativ Parameter aus request nutzbar • Get-Methode (auch für Attribute und Properties aus request) entspricht kunde.getAdresse(); kunde.getAdresse(); name s.o; property: zu lesende Eigenschaft 194 liest <jsp:setProperty name=" name="kunde" kunde" property=" property="adresse" adresse" value=“ value=“Xstr. Xstr. 42" /> <jsp:getProperty name="kunde name="kunde" kunde" property="adresse property="adresse" adresse" /> Basis-Design-Pattern für Web-Applikationen als • Set-Methode (auch für Attribute und Properties aus request) public Kunde(String name, name, int alter, String Adresse) { this.name = name; name; this.alter = alter; this.Adresse = Adresse; } als Model liest // getget- und setset-Methoden für die Attribute als View Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 196 Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 197 Kombination von HTML, Servlets und JSP (2/6) Kombination von HTML, Servlets und JSP (3/6) <!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"> Transitional//EN"> <html> html> <!-<!-- index.html --> --> <head> head> <title>Detailanfrage</title> title>Detailanfrage</title> <meta httphttp-equiv="Contentequiv="Content-Type" Type" content="text/html; content="text/html; charset=UTFcharset=UTF-8"> </head </head> head> <body> body> <form name="suche" name="suche" action="Suche"> action="Suche"> Name: <input type="text" type="text" name="name" name="name" value="" value="" size="15" /> <input type="submit" type="submit" value="Abschicken" value="Abschicken" name="send" name="send" /> </form> </body </body> body> </html </html> html> Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 198 199 Stephan Kleuker Kombination von HTML, Servlets und JSP (5/6) <%@page <%@page contentType="text/html" contentType="text/html" pageEncoding="UTFpageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN" Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> html> <head> head> <meta httphttp-equiv="Contentequiv="Content-Type" Type" content="text/html; content="text/html; charset=UTFcharset=UTF-8"> <title>Suchergebnis</title> title>Suchergebnis</title> </head </head> head> <body> body> Name: <jsp:getProperty <jsp:getProperty name="erg" name="erg" property="name"/> property="name"/> <br <br> br> Alter: <jsp:getProperty <jsp:getProperty name="erg" name="erg" property="alter"/> property="alter"/> <br <br> br> Adresse: <jsp:getProperty <jsp:getProperty name="erg" name="erg" property="adresse"/> property="adresse"/> </body </body> body> </html </html> html> Prof. Dr. Stephan Kleuker protected void processRequest(HttpServletRequest request, request, HttpServletResponse response) response) throws ServletException, ServletException, IOException { String name= name= request.getParameter("name"); request.getParameter("name"); Kunde ergebnis= ergebnis= new Kunde(name,Kunde(name,-1,"fehlt"); for(Kunde k:kunden) k:kunden) if(k.getName().equals(name)) if(k.getName().equals(name)) ergebnis=k; ergebnis=k; request.setAttribute("erg", request.setAttribute("erg", ergebnis); ergebnis); RequestDispatcher view = request.getRequestDispatcher("ergebnis.jsp"); request.getRequestDispatcher("ergebnis.jsp"); view.forward(request, view.forward(request, response); response); }... Komponentenbasierte SoftwareProf. Dr. Entwicklung Kombination von HTML, Servlets und JSP (4/6) Komponentenbasierte SoftwareEntwicklung public class Suche extends HttpServlet { private Set<Kunde> Set<Kunde> kunden = new HashSet<Kunde>(); HashSet<Kunde>(); @Override public void init(){ init(){ kunden.add(new Kunde("Ute",42,"XStr. 3")); kunden.add(new Kunde("Urs",43,"YStr. 9")); kunden.add(new Kunde("Ulf",44,"YStr. 3")); } 200 <?xml <?xml version="1.0" encoding="UTFencoding="UTF-8"?> <webweb-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchemaxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/webhttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> servlet> <servletservlet-name>Suche</servletname>Suche</servlet-name> name> <servletservlet-class>servlets.Suche</servletclass>servlets.Suche</servlet-class> class> </servlet </servlet> servlet> <servletservlet-mapping> mapping> <servletservlet-name>Suche</servletname>Suche</servlet-name> name> <urlurl-pattern>/Suche</urlpattern>/Suche</url-pattern> pattern> </servlet </servletservlet-mapping> mapping> <welcomewelcome-filefile-list> list> <welcomewelcome-file>index.html</welcomefile>index.html</welcome-file> file> </welcome </welcomewelcome-filefile-list> list> </web </webweb-app> app> Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 201 Kombination von HTML, Servlets und JSP (6/6) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 202