Serwlety

Transkrypt

Serwlety
Serwlety
Co to jest serwlet?
kawałek kodu w Javie po stronie serwera HTTP
rozszerza moŜliwośći serwera
CGI, w Javie, wzbogacone o biblioteki ułatwiające Ŝycie programiście (np.
utrzymywanie sesji, wpólne zasoby serwletów, ciasteczka, obsługa GET/POST/PUT)
coś jak aplet: róŜni się miejscem wykonywania oraz dostępnymi bibliotekami
serwlety mogą korzystać ze standardowych klas Javy (z VM), klas wchodzących w
skład Servlet API: javax.servlet.* i javax.servlet.http.* oraz ewentualnie z
dodatkowych bibliotek zainstalowanych na serwerze.
serwlety nie mają interfejsu uŜytkownika, komunikują się z przeglądarką (za
pośrednictwem serwera WWW wspierającego serwlety) za pomocą protokołu HTTP
•
•
•
•
•
•
Przykładowy kod serwletu
import
import
import
import
import
import
java.io.IOException;
java.io.PrintWriter;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
public class SimpleServlet extends HttpServlet
{
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
PrintWriter
out;
response.setContentType("text/html");
out = response.getWriter();
out.println("<HTML><HEAD><TITLE>");
out.println("Hello world servlet");
out.println("</TITLE></HEAD><BODY>");
out.println("<H1>" + title + "</H1>");
out.println("<P>This is output from SimpleServlet.");
out.println("</BODY></HTML>");
out.close();
}
}
Po co są serwlety?
Zasadniczo: do wyświetlania dynamicznych stron WWW.
•
•
•
•
przetwarzanie formularzy
forwarding
wyświetlania wyników zapytań do b. d. (tu zaleca się strony JSP)
są częścią J2EE
Miejsce serwletów w aplikacjach J2EE
•
•
•
•
•
•
serwlety to rozszerzenie serwera WWW
blisko interfejsu uŜytkownika: zorientowane na Ŝądanie/odpowiedź (request/response)
serwlety działają w odpowiedzi na Ŝadania klienta
są interfejsem do serwera aplikacyjnego/bazy danych/EJB
pełnią rolę kontrolera w schemacie Model-View-Controller, za widok odpowiedzialne
są strony JSP (czyli kod Javy imieszczony w pliku html), model to EJB
w serwletach zaleca się umieszczanie tylko lekkich funkji biznesowych, ale w małych
aplikacjach cała logika moŜe być w serwletach i JSP
Rysunek 1. Warstwy w modelu J2EE (obrazek z J2EE Tutorial)
Rysynek 2. Kontenery w modelu J2EE (obrazek z J2EE Tutorial)
Komunikacja z klientem
•
•
•
•
przedefiniowanie metod doGet, doPost, doPut, doDelete. Te metody są
wywoływane przez metodę service zdefiniowaną w Servlet przy kaŜdym Ŝądaniu do
serwera dotyczącym serwletu. service to tablica rozdzielcza.
dane od klienta (przeglądarki) są w obiekcie HttpServletRequest.
WaŜne metody obiektu request:
o getParameter - zwraca parametr, np. z formularza
o getCookies - daje ciasteczka
o getSession - podaje obiekt sesji
o getReader (dla danych tekstowych)
o getInputStream (dla danych binarnych)
dane do klienta symbolizuje obiekt HttpServletResponse WaŜne metody obiektu
response:
o getWriter (dane tekstowe)
o getOutputStream (dane binarne)
szczegóły i pozostałe metody: javadoc do javax.servlet.http.*
Przykład komunikacji z klientem
<html>
<head><title>Formularz</title></head>
<body>
<form action="/karolb/test" method="post">
Podaj tekst: <input type="text" name="tekst" value="">
</form>
</body>
</html>
zadziała następujący serwlet:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class TestServlet extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out;
String tekst;
response.setContentType("text/html");
out = response.getWriter();
out.println("<HTML><HEAD><TITLE>Wyniki z formularza");
out.println("</TITLE></HEAD><BODY>");
tekst = request.getParameter("tekst");
if (tekst != null)
out.println("Z formularza otrzymalem: " + tekst);
else
out.println("Brak danych z formularza");
out.println("</BODY></HTML>");
out.close();
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out;
String tekst;
response.setContentType("text/html");
out = response.getWriter();
out.println("<HTML><HEAD><TITLE>Uwaga</TITLE>");
out.println("</HEAD><BODY>");
out.println("Ten serwlet nie obsluguje metody GET!");
out.println("</BODY></HTML>");
out.close();
}
}
Wielowątkowość
Serwlety wykonują się w środowisku wielowątkowym, więc moŜe się zdarzyć, Ŝe wiele kopii
serwletu będzie działać naraz. A moŜe być tak, Ŝe będzie jedna instancja serwletu, ale wiele
wątków wykonujących metodę service. JeŜeli w serwlecie jest odwołanie do zasobu, który
wymaga wyłączności to:
•
•
trzeba zapewnić wykluczanie ręcznie, np. uŜywając zmiennych/metod synchronized
zadeklarować, Ŝe serwlet implementuje interfejs SingleThreadModel, wtedy serwer
uruchomi jednocześnie tylko jedną instancję metody service, np. public class
ReceiptServlet extends HttpServlet implements SingleThreadModel.
Ten
interfejs nie zawiera Ŝadnych metod, jest tylko znacznikiem dla kontenera.
Cykl Ŝycia serwletu
•
•
na początku system woła metodę init(), w niej moŜna np. połączyć się z bazą
danych
o jeŜeli coś pójdzie nie tak to naleŜy rzucić wyjątek UnavailableException
o moŜna wołać metodę getInitParameter, interpretowaną przez serwer
(kontener), np. jako init-param z pliku web.xml w Tomcat'cie. W takim
parametrze moŜe być zapisany np. URL do bazy danych.
gdy serwer zdecyduje wyrzucić serwlet z pamięci to wywołuje metodę destroy.
Uwaga! JeŜeli metoda do[Get|Post] wykonuje się długo, to trzeba zadbać o jej
zakończenie. JeŜeli serwlet uruchamiał wątki, to teŜ trzeba je przerwać.. Szczegóły w
Servlet Tutorial na stronach Sun'a.
Utrzymywanie stanu (session tracking)
To jedna z najwaŜniejszych zalet serwletów. Nie ma tego w CGI.
Schemat:
•
•
•
•
HttpSession session = request.getSession(true); (czytanie/pisanie)
Klasa ref_obiektu1 = new Klasa(); (pisanie)
session.putAttribute("dluga.nazwa_atr", ref_obiektu1); (pisanie)
Klasa ref_obiektu2 = (Klasa) session.getAttribute("dluga.nazwa_atr");
(czytanie)
Cechy:
•
•
•
Wkładanie i wyjmowanie obiektów z sesji nie ma nic wspólnego z interfejsem
serializable. Obiekty nie są nigdzie składowane, tylko istnieją w pamięci
kontenera. Metody operują na referencjach. Po odczytaniu referencji metodą
getAttribute operujemy juŜ na oryginalnym (jedynym!) obiekcie.
Po odczytaniu atrybutu trzeba sprawdzić czy jest równy null, jeŜeli tak to trzeba
utworzyć nowy obiekt (uwaga na wielowątkowość).
Sesje działają standardowo na ciasteczkach. W ciasteczku jest tylko id sesji, reszta
siedzi w pamięci kontenera. JeŜeli przeglądarka nie obsługuje ciasteczek to trzeba
uŜywać metody encodeURL(). Gdy serwlet ma wyświetlić link do drugiego serwletu
to w metodzie doGet() trzeba umieścić:
String wartosc = "abc";
out.println("Link do drugiego serwletu z parametrem: " + ...
"<a href=\"" +
response.encodeURL("/drugi_serwlet?param=" + wartosc) + "\">" +
...);
•
•
Takie wywołanie dorzuci do parametrów w adresie identyfikator sesji.
Sesje nie są związane z jednym serwletem, róŜne serwlety korzystają z tej samej sesji
Przykład uŜycia sesji
•
Wkładanie i wyjmowanie z sesji
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DodajProdukt extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(true);
Koszyk koszyk =
(Koszyk) session.getAttribute("pl.zakupy.koszyk");
if (koszyk == null) {
koszyk = new Koszyk();
session.setAttribute("pl.zakupy.koszyk", koszyk);
}
koszyk.dodaj(request.getParameter("produkt"));
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(
"/wyswietl_koszyk.jsp");
if (dispatcher != null)
dispatcher.forward(request, response);
}
}
•
•
Uwaga: po modyfikacji koszyka nie trzeba go specjalnie zapisywać do sesji.
W skrypcie /wyswietl_koszyk.jsp wyświetlam zawartość koszyka.
Ciasteczka (Cookies)
Schemat uŜycia:
•
Wysyłanie
String wartosc = "byle-co";
Cookie ciacho = new Cookie("Nazwa", wartosc);
response.addCookie(ciacho);
Odbieranie
•
Cookie[] cookies = request.getCookies();
String wartosc;
for (int i = 0; i < cookies.length; i++) {
if (cookies[i].getName().equals("Nazwa"))
wartosc = thisCookie.getValue();
}
Lepiej jednak uŜywać sesji.
Dzielenie zasobów między serwlety (ServletContext)
Schemat (podobny do tego przy obsłudze sesji):
ServletContext context = getServletContext(); (czytanie/pisanie)
Klasa ref_obiektu1 = new Klasa(); (pisanie)
context.setAttribute("dluga.nazwa_atr", ref_obiektu1); (pisanie)
Klasa ref_obiektu2 = context.getAttribute("dluga.nazwa_atr"); (czytanie)
•
•
•
•
Przechowywanie jest podobne do tego związanego z sesjami, ale te same obiekty są dostępne
dla wszystkich serwletów na serwerze (w kontenerze). Dlatego trzeba szczególnie uwaŜać na
nazwy atrybutów, Ŝeby się nie zdarzyło, Ŝe dwie róŜne apliacje chcą korzystać z tego samego
atrybutu.
Przykład uŜycia kontekstu
public class WyswietlDane extends HttpServlet {
public synchronized void init() throws ServletExcpetion {
BazaDanych bd = (BazaDanych)
getServletContext().getAttribute("pl.sklep.bd.baza");
if (bd == null) {
bd = new BazaDanych("http://pulsar", "scott", "tiger");
getServletContext().setAttribute("pl.sklep.bd.baza", bd);
}
}
...
}
Inne moŜliwości serwletów
•
•
ServletDispatcher - umoŜliwia przekierowywanie do innego serwletu (metoda
forward, patrz wyŜej) i włączanie wyjścia innego serwletu we własne wyjście
(metoda include).
filtry - klasa Filter. Filtrów uŜywa się do modyfikowania komunikatów między
klientem a docelowym serwletem na serwerze. Filtry moŜna łączyć w łańcuchy.
Przykładowe zastosowania filtrów to: autentykacja, szyfrowanie, kompresja.
Szczegóły w J2EE Tutorial i JavaDocu.
Przykład z J2EE Tutorial:
public final class HitCounterFilter implements Filter {
private FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig)
throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (filterConfig == null)
return;
StringWriter sw = new StringWriter();
PrintWriter writer = new PrintWriter(sw);
Counter counter = (Counter)filterConfig.
getServletContext().
getAttribute("hitCounter");
writer.println();
writer.println("===============");
writer.println("The number of hits is: " +
counter.incCounter());
writer.println("===============");
// Log the resulting string
writer.flush();
filterConfig.getServletContext().
log(sw.getBuffer().toString());
...
chain.doFilter(request, wrapper);
...
}
}
Instalowanie serwletów na Tomcat'cie
•
•
Najpierw trzeba zainstalować Tomcata. Tomcat to serwer http napisany w Javie przez
Apache Software Group. MoŜe działać jako samodzielny serwer (domyślnie na porcie
8080) lub zintegrować się z Apachem.
Kompilacja serwletu: javac -classpath $TOMCAT_HOME/lib/servlet.jar
Test.java
•
Plik Test.class ma trafić do katalogu $TOMCAT_HOME/webapps/test_kat/WEB-
•
Trzeba utworzyć plik $TOMCAT_HOME/webapps/test_kat/WEB-INF/web.xml, o
treści:
INF/classes
<?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-app_2_2.dtd">
<web-app>
<servlet>
<servlet-name>
test_serw
</servlet-name>
<servlet-class>
Test
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
test_serw
</servlet-name>
<url-pattern>
/test
</url-pattern>
</servlet-mapping>
</web-app>
•
•
Jak widać najpierw nazwa serwletu (test_serw) jest wiązana z klasą (Test.class), a
potem nazwa serwletu jest przypisywana do ścieŜki (w obrębie kontekstu).
Do pliku $TOMCAT_HOME/conf/server.xml trzeba dopisać:
<Context path="/test_kat"
docBase="webapps/test_kat"
reloadable="true"/>
•
•
wewnątrz znacznika <ContextManager>. W tym pliku określa się jak z zewnątrz
adresować dany kontekst, tu kontekst z katalogu webapps/test_kat będzie widziany
jako katalog test_kat.
Teraz moŜna do serwletu odwoływać się poprzez localhost:8080/test_kat/test.

Podobne dokumenty