Java wybrane technologie spotkanie nr 3 Serwlety 1
Klient-Serwer Odpowiedzialność serwera przyjmowanie żądań od klienta przygotowywanie odpowiedzi statyczna dynamiczna Rodzaje odpowiedzi statyczna dynamiczna 2
Podział serwera Common Gateway Interface (CGI) serwer: komunikacja (protokół) skrypt: przetwarzanie danych i przygotowywanie odpowiedzi wady: nowy proces dla każdego żądania pełna inicjalizacja dla każdego żądania komunikacja za pomocą plików server extensions Netscape Server API (NSAPI) Internet Server API (ISAPI) Servlet API 3
Typy kontenerów serwletów Opracował standalone in-process out-of-process 4
Witaj świecie import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class WitajSwiecie extends javax.servlet.http.httpservlet { protected void service(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { //kodowanie znaków zostanie przekazane w nagłówku HTTP //Content-Type: text/html; charset=utf-8 response.setcontenttype("text/html;charset=utf8"); //posługuje się właściwym kodowaniem PrintWriter pw = response.getwriter(); pw.println("<html>"); pw.println("<head>"); pw.println("</head>"); pw.println("<body>"); pw.println("witaj świecie"); pw.println("</body>"); pw.println("</html>"); pw.close(); 5
Deskryptor <?xml version="1.0" encoding="utf-8"?> <web-app id="webapp_id" version="2.4" 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"> <display-name>serwlety1</display-name> <servlet> <description>jakiś opis</description> <display-name>witajswiecie</display-name> <servlet-name>witajswiecie</servlet-name> <servlet-class>witajswiecie</servlet-class> </servlet> <servlet-mapping> <servlet-name>witajswiecie</servlet-name> <url-pattern>/witajswiecie</url-pattern> </servlet-mapping> </web-app> 6
Interfejs javax.servlet.servlet init(servletconfig), service(servletrequest, ServletResponse), destroy(), getservletconfig(), getservletinfo() klasa javax.servlet.genericservlet (wszystko poza service()) interfejs javax.servlet.servletrequest interfejs javax.servlet.servletresponse pakiet javax.servlet.http 7
Java Server Pages (JSP) Java w HTML vs HTML w Javie server-side includes (np. ASP, PHP początkowo jako CGI) kiedy serwlet, a kiedy JSP JSP dla twórców stron Serwlety jako kontrolery uwierzytelnianie autoryzacja walidacja nadzorowanie transakcji Struts 8
Nie tylko serwlety import java.io.ioexception; import java.io.printwriter; import javax.servlet.servletexception; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; public class Pozdrawiak extends javax.servlet.http.httpservlet { protected void service(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/html;charset=utf8"); PrintWriter pw = response.getwriter(); String imie = request.getparameter("imie"); pw.println("<html>"); pw.println("<head>"); pw.println("</head>"); pw.println("<body>"); pw.println("witaj " + imie); pw.println("</body>"); pw.println("</html>"); pw.close(); 9
JSP <?xml version="1.0" encoding="iso-8859-1"?> <%@ page language="java" contenttype="text/html; charset=iso-8859-1" pageencoding="iso-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> <title>pozdrawiak</title> </head> <body> Witaj ${param.imie </body> </html> 10
Architektury Opracował Model 1 Model 2 11
Wprowadzenie do HTTP Uniform Resource Identifier (URI) napis identyfikujący dowolny zasób; nie musi przenosić informacji jak ten zasób odnaleźć; nadklasa URL i URN pliki/zajecia/wyklad3.pdf Uniform Resource Locator (URL) nieformalny termin określający URI wskazujące protokół internetu http://mimuw.edu.pl/~sroka/jwt/wyklad3.pdf Uniform Resource Name (URN) napis jednoznacznie identyfikujący zasób, ale nie zawierający informacji jak się do niego dostać; w celu zachowania jednoznaczności URN są nadzorowane przez odpowiednie instytucje ISBN:0-306-40615-2 12
Budowa komunikatu HTTP (jest podobna dla żądania i odpowiedzi) pierwsza linia określa cel komunikatu dla żądań: nazwa metody, URI, wersja protokołu GET /~sroka/jwt/wyklad3.pdf HTTP/1.1 GET HEAD POST nagłówki z metainformacjami (rozmiar, kodowanie, opis zawartości) pusta linia opcjonalne ciało wiadomości 13
Przykład żądanie: POST /serwlety/pozdrawiak HTTP/1.1 User-Agent: Mizilla/4.0 Content-Type: application/x-www-form-urlencoded ContentLength: 8 user=ala odpowiedź: HTTP/1.1 200 OK Date: Sun, 15 Oct 2006 20:21:57 GMT Content-Type: text/html Content-Length: 39 <html> <body> Witaj Ala </body> </html> 14
Serwlety c.d. HttpServlet protected void doxxx(httpservletrequest, HttpServletResponse) throws ServletException, IOException (XXX = Get, Head, Post, Put, Delete, Options, Trace) 1. kontener wywołuje service(servletrequest, ServletResponse) 2. jej implementacja z HttpServlet wywołuje service(httpservletrequest, HttpServletResponse) 3. która (dlatego nie należy jej przedefiniowywać) wybiera odpowiednią metodę doxxx() 15
Żądanie ServletRequest String getparameter(string paramname) String[] getparametervalues(string paramname) Enumeration getparameternames() HttpServletRequest String getheader(string headername) String[] getheaders(string headername) Enumeration getheadernames() Cookie[] getcookies() 16
Odpowiedź ServletResponse PrintWriter getwriter() ServletOutuputStream getoutputstream() void setcontenttype(string type) albo Writer albo OutputStream setcontenttype() nie nic nie robi jak wyjście zostało już zatwierdzone HttpServletResponse void setheader(string name, String value) void setintheader(string name, int value) void setdateheader(string name, long millisecs) void addheader/addintheader/addfateheader boolean containsheader(string name) niektóre nagłówki: Date, Expires, Las-Modified, Refresh addcookie(cookie c) 17
Wysyłanie plików public class WysylanieArchiwum extends javax.servlet.http.httpservlet implements javax.servlet.servlet { protected void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { dopost(request, response); protected void dopost(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("application/jar"); byte[] bufor = new byte[1024]; FileInputStream in = new FileInputStream("test.jar"); OutputStream out = response.getoutputstream(); int x; while ( (x = in.read(bufor))!= -1 ) out.write(bufor, 0, x); in.close(); out.close(); 18
Przekierowywanie i informowanie o błędach Opracował protected void dopost(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.sendredirect("http://www.mimuw.edu.pl/~sroka"); protected void dopost(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { //przekierowanie HTTP można wykonać jedynie przed zatwierdzeniem wyjścia PrintWriter pw = response.getwriter(); pw.print("<html><head></head><body>witaj świecie!</body></html>"); pw.flush(); //to wywołanie zgłosi java.lang.illegalstateexception response.sendredirect("http://www.mimuw.edu.pl/~sroka"); protected void dopost(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.senderror(httpservletresponse.sc_unauthorized, "Wstydź się"); 19
Cykl życia Opracował loaded = jest egzemplarz init(servletconfig) vs init() <load-on-startup> destroy() 20
Parametryzacja serwletów ServletConfig String getinitparameter(string name) Enumeration getinitparameternames() String getservletname() ServletContext getservletcontext() GenericServlet implementuje ServletConfig 21
Przykład public CyklZycia() { super(); System.out.println("CyklZycia konstruktor"); public void init() throws ServletException { System.out.println(getServletName()+" : init()"); String par1 = getinitparameter("mojparametr1"); String par2 = getinitparameter("mojparametr2"); String par3 = getinitparameter("mojparametr3"); System.out.println(getServletName()+" ("+par1+","+par2+","+par3+")"); public void destroy() { System.out.println(getServletName()+" : destroy()"); protected void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/html;charset=utf8"); PrintWriter pw = response.getwriter();... 22
Deskryptor <servlet> <description> Serwlet sparametryzowany, łądowany gorliwie (w trakcie osadzania aplikacji) </description> <display-name>sparametryzowanygorliwy</display-name> <servlet-name>sparametryzowanygorliwy</servlet-name> <servlet-class>wyklad.cyklzycia</servlet-class> <init-param> <param-name>mojparametr1</param-name> <param-value>x</param-value> </init-param> <init-param> <param-name>mojparametr2</param-name> <param-value>y</param-value> </init-param> <init-param> <param-name>mojparametr3</param-name> <param-value>z</param-value> </init-param> <load-on-startup>1</load-on-startup> <!--dla wartości nieujemnych serwlet będzie ładowany przy starcie kontenera z właśnie takim priorytetem, dla ujemnych lub jeżeli nic nie podano kontener ma wolna rękę i zazwyczaj ładuje leniwie--> </servlet> 23
ServletContext String getmimetype(string file) typy MIME mogą być zdefiniowane w deskryptorze String getrealpath(string path) np. "/index.html" -> "http://host/contextpath/index.html" nie zawsze się da (zasoby mogą być w archiwum) URL getresource(string path) ścieżka musi się zaczynać od "/" i jest interpretowana względem context root aplikacji zasoby mogą pochodzić z archiwów z aktywnymi zasobami lepiej używać obiektu RequestDispatcher wersja skrócona InputStream getresourceasstream(string path) void log(string msg) Z kontekstu można odczytać parametry dla całej aplikacji. 24
Współdzielenie atrybutów Object getattribute(string name) Enumeration getattributenames() void setattribute(string name, Object value) Kontenery: ServletRequest ServletContext HttpSession 25
Przekierowywanie i włączanie void forward(servletrequest req, ServletResponse res) void include(servletrequest req, ServletResponse res) RequestDispatcher.forward() vs HttpServletResponse.sendRedirect() w przypadku forward() odpowiedź nie może być jeszcze zatwierdzona w przypadku include() zdalny zasób nie powinien ustawiać nagłówków, wszelkie próby są ignorowane Zarówno ServletContext jak i ServletRequest mają metodę: RequestDispatcher getrequestdispatcher(string path) przyjmuje jedynie ścieżki z tej samej aplikacji, np. "/Serwlety1/WitajSwiecie" getrequestdispatcher() z ServletRequest akceptuje ścieżki względne, np. "../html/copyright.html" dodatkowo ServletContext ma getnameddispatcher(), która przyjmuje nazwę używaną w desktyptorze żeby przekierowywać lub włączać zasoby z inne aplikacji należy dostać jej ServletContext (przy pomocy getservletcontext().getcontext(uri)) i dopiero z niego pobrać ReqiestDispatcher 26
Informacje o oryginalnym żądaniu Atrybuty dodawane do żądania javax.servlet.include.request_url javax.servlet.include.context_path javax.servlet.include.servlet_path javax.servlet.include.path_info javax.servlet.include.query_string (oraz analogiczny zestaw dla "forward" zamiast "include") Wartości atrybutów odpowiadają wynikom getrequesturi(), getcontextpath(), getservletpath(), getpathinfo() i getquerystring() z oryginalnego żądania 27