Praktikum aus Softwareentwicklung 2, Stunde 11 Lehrziele/Inhalt 1. Java Servlet Java Servlet Java Servlets sind auf Java basierende Web-Komponenten. Sie werden von einem Container verwaltet und können dynamisch Inhalt erzeugen. Ein Container (Servlet-Engine) ist ein Teil eines Web-Servers, leitet Anfragen an die Servlets und liefert Antworten zurück. Der Container verwaltet die Servlets über ihren Lebenszyklus hinweg. Abbildung 12 zeigt die grobe Architektur von Webanwendungen die auf Java Servlets aufbauen. Die Spezifikation der Java Servlets kann in JSR 145 für die Version 2.5 und in JSR 315 für die Version 3.0 nachgelesen werden. Die Version 3.0 bringt einige interessante Neuerungen, die wir besprechen werden. Es ist aber interessant sich auch mit Version 2.5 zu beschäftigen, um die Grundlagen zu verstehen und weil einige Web-Hoster nur Version 2.5 verstehen, zB Google App Engine. Client Request Web-Server & Servlet-Engine Firefox, Opera, Chrome, Internet Explorer, … Response GlassFish, Tomcat, jetty://, … Servlet 1 Servlet 2 Servlet 3 Ressourcen Dateien, Datenbanken, … Abbildung 12) Grobe Architektur von Webanwendungen mit Servlets Servlets vs. Common Gateway Interface Java Servlets sind vergleichbar mit dem Common Gateway Interface (CGI) und proprietären ServerErweiterungen. Servlets haben folgende Vorteile: Schneller als CGI-Skripte, weil der Code im Speicher bleibt und der Prozess nach einer Anfrage weiterläuft. Bei CGI wird pro Aufruf ein Prozess gestartet Unterstützung für Sitzungen, CGI ist von sich aus zustandslos In Java entwickelt: o Nur von der JavaVM abhängig, aber sonst Systemunabhängig o Große Klassenbibliothek © Markus Löberbauer 2010 Seite 41 Entwickeln eines Servlets Will man ein Servlet entwickeln, muss man eine Klasse schreiben die das Interface Servlet im Packet javax.servlet implementiert. Servlets sind generisch gehalten, die Methode service(ServletRequest, ServletResponse) bekommt eine Anfrage (ServletReqest) und beantwortet diese im ServletResponse. Dabei wird keine Aussage getroffen woher die Anfragen kommen. Meistens schreibt man aber Servlets für das Web, die Http-Anfragen beantworten. Dazu leitet man von HttpServlet ab, das ist eine abstrakte Basisklasse die von GenericServlet ableitet und Servlet implementiert. HttpServlet hat eine Methode für jede Http-Methode (GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT und OPTIONS), zB doGet für Get-Anfragen und doPost für Post-Anfragen. Je nachdem welche Http-Methoden man unterstützen will muss man die zugehörige Servlet-Methode überschreiben. Das Servlet in Abbildung 13 beantwortet Get-Anfragen mit dem Text „Hello!“. public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); try { out.println("Hello!"); } finally { out.close(); } } } Abbildung 13) Beispiel Hello World Servlet Installieren von Web-Anwendungen Um Web-Anwendungen in einem Servlet-Container wie zB Tomcat zu installieren muss man einen Deployment Descriptor (web.xml) schreiben. Für das Beispiel in Abbildung 13 ist die web.xml in Abbildung 14 gegeben. Abbildung 15 zeigt die Verzeichnisstruktur von Tomcat 6 mit installiertem Hello-Beispiel. Im Verzeichnis webapps sind die Installierten Web-Anwendungen, in unserem Fall hello5. Im Verzeichnis der Web-Anwendung kann beliebiger Inhalt liegen zB: Bilder oder HTMLDateien, dieser Inhalt kann über Web-Zugriffe abgefragt werden. Die Einzige Ausnahme ist das Verzeichnis WEB-INF, das ist vor Zugriffen von außen geschützt. In diesem liegen die Servlets im Verzeichnis classes und falls nötig jar-Dateien im Verzeichnis lib. © Markus Löberbauer 2010 Seite 42 Abbildung 15Abbildung 15 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class> at.jku.ssw.psw2.servlet.hello.HelloServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/hello.do</url-pattern> </servlet-mapping> <session-config> <session-timeout>30</session-timeout> </session-config> <welcome-file-list> <welcome-file>hello.do</welcome-file> </welcome-file-list> </web-app> Abbildung 14) web.xml für Beispiel Hello World Servlet Abbildung 15) Verzeichnisstruktur von Tomcat 6 © Markus Löberbauer 2010 Seite 43 Lebenszyklus von Servlets Der Servlet-Container lädt die Klasse des Servlets, erzeugt ein (!) Objekt, d.h. die Felder werden einmal initialisiert und leben so lange das Servlet-Objekt lebt. Clients (Web-Browser) stellen Anfragen an den Web-Server, dieser ruft die Servlet-Engine auf und diese leitet die Anfrage an das Servlet weiter. Pro Anfrage erzeugt die Servlet-Engine einen Thread, d.h. mehrere Threads können gleichzeitig Methoden auf einem Servlet-Objekt ausführen. Die Servlet-Engine bestimmt wann ein Servlet weggeworfen wird, dabei muss das Servlet Ressourcen frei geben und eventuell seinen Zustand speichern. Der Lebenszyklus aus der Sicht eines Servlets ist in Abbildung 16 zu sehen. init(ServletConfig) Variablen initialisieren, Ressourcen anfordern service(HttpRequest, HttpResponse) doGet(HttpRequest, HttpResponse) doPost(HttpRequest, HttpResponse) doPut(HttpRequest, HttpResponse) ... destroy() Ressourcen freigeben Eventuell Zustand speichern Abbildung 16) Lebenszyklus eines Servlets Sitzungen (Sessions) Http ist ein nicht sitzungsorientiertes Protokoll. Sinnvolle Web-Anwendungen benötigen aber Sitzungen, zB: Warenkorb einer Shop-Anwendung oder Anmeldung einer E-Mail-Anwendung. Intern verwenden Servlets Cookies, URL-Parameter und versteckte Formular-Felder zur SitzungsVerwaltung. Für den Programmierer wird die Sitzungsverwaltung über die Klasse HttpSession abstrahiert. Servlet 3.0 Am 10 Dezember 2009 hat Sun die Spezifikation für Servlet 3.0 veröffentlicht. Mit Version 3.0 werden Annotationen eingeführt mit denen man Informationen aus dem Deployment Descriptor direkt zu den Servlet-Klassen schreiben kann. Das Beispiel Hello World Servlet aus Abbildung 13 kann mit der Annotation @WebServlet angereichert werden, dadurch kann man die Information aus web.xml entfernen. Der neue Code und die neue web.xml ist in Abbildung 17 bzw. Abbildung 18 gegeben. © Markus Löberbauer 2010 Seite 44 @WebServlet(name = "HelloServlet", urlPatterns = {"/hello.do"}) public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); try { out.println("Hello from JavaEE 6!"); } finally { out.close(); } } } Abbildung 17) Beispiel Hello World Servlet mit @WebServlet Annotation <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <session-config> <session-timeout>30</session-timeout> </session-config> <welcome-file-list> <welcome-file>hello.do</welcome-file> </welcome-file-list> </web-app> Abbildung 18) web.xml für Beispiel Hello World Servlet mit @WebServlet Annotation Um dieses Servlet ausführen zu können braucht man einen Web-Container der Servlets in der Version 3.0 unterstützt, zB: GlassFish Server 3, jetty:// (Experimental) oder Tomcat 7 (in Entwicklung). JavaServer Pages (Erstellen von HTML-Seiten) Servlets sind die Basis der Java Web-Technologie. Will man aber HTML-Seiten aus Servlets erstellen ist das sehr aufwendig. Man müsste programmatisch, über den PrintWriter, den ganzen Text in den HttpServletResponse schreiben. Um den Standard-Anwendungsfall HTML-Seiten zu erstellen wurden JavaServer Pages eingeführt. JavaServer Pages (JSP) werden vom Web-Container in Servlets übersetzt und dann wie alle anderen Servlets behandelt. Der Web-Container übersetzt JSPs bei Veränderungen automatisch neu. Schreiben von JSPs ist Servlet-Programmierung auf einer abstrakten Ebene. Man kann mit JSPs alles machen was man auch mit Servlets machen kann. Aber man soll Servlets und JSPs als Team verwenden: wobei Servlets den Ablauf steuern, die Daten aufbereiten und die Geschäftslogik ansprechen; und JSPs die Darstellung übernehmen. Die Trennung entspricht dem Model-View-Controller-Muster, diese Architektur heißt in der Java Servlet Welt „Model 2 Architecture“. Die selten Verwendete „Model 1 Architecture“ benutzt JSPs zur Ablaufsteuerung und Darstellung; die Datenaufbereitung und Verbindung zur Geschäftslogik erfolgt in Java Beans. Heute © Markus Löberbauer 2010 Seite 45 wird fast nur mehr die „Model 2 Architecture“ eingesetzt, weil sie klarer und einfacher ist. <%@page contentType="text/html" pageEncoding="UTF-8"%> <html> <head> <title>Hello Page</title> </head> <body> Hello! </body> </html> Abbildung 19) Beispiel Hello World JSP public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent { // ... public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException { PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; JspWriter _jspx_out = null; PageContext _jspx_page_context = null; try { response.setContentType("text/html;charset=UTF-8"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; out.write("\r\n"); out.write("<html>\r\n"); out.write(" <head>\r\n"); out.write(" <title>Hello Page</title>\r\n"); out.write(" </head>\r\n"); out.write(" <body>\r\n"); out.write(" Hello!\r\n"); out.write(" </body>\r\n"); out.write("</html>\r\n"); out.write("\r\n"); } catch (Throwable t) { // ... } finally { _jspxFactory.releasePageContext(_jspx_page_context); } } } Abbildung 20) Generiertes Servlet für Hello World JSP © Markus Löberbauer 2010 Seite 46 Abbildung 19 zeigt eine einfache Hello World JSP. Abbildung 20 zeigt dazu Ausschnitte aus dem generierten Java Servlet. Man kann sehen wie die Zeilen aus der JSP-Datei in einzelne writeAnweisungen im Code verwandelt werden. Will man für eine JSP das generierte Servlet sehen, kann das in Tomcat unter work/Catalina/localhost/<Web-Anwendung>/org/apache/jsp/<JSPName>_jsp.java. © Markus Löberbauer 2010 Seite 47