Java Servlety
CGI programy jsou poněkud těžkopádné (zvlášť v Javě). Proto pro Javu existuje lepší způsob - servlety. Jednoduchý servlet:
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloWorld extends HttpServlet { public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out; String title = "Simple Servlet Output"; response.setContentType("text/html"); out = response.getWriter(); out.println("<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>"); out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\""); out.println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); out.println("<html xmlns=\"http://www.w3.org/1999/xhtml\">"); out.println("<head>"); out.println("<meta http-equiv=\"content-type\""); out.println(" content=\"text/html; charset=iso-8859-2\" />"); out.println("<title>Sample Servlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hello World!</h1>"); out.println("</body>"); out.println("</html>"); } }Nyní už ovšem potřebujeme server, který si s Javou
rozumí, například Apache Tomcat. Potom stačí zadat http://localhost:8080/HelloWorld a dostaneme patřičný výstup.
Očividně jsme se stále nevyhnuli kostrbaté produkci výstupu. Síla servletů tkví ale jinde. Třídy
HttpServletRequest
, resp. HttpServletResponse
, zapouzdřují data putující od klienta, resp. k
němu. Metoda HttpServletRequest.getParameter
vrátí hodnotu parametru (ať už šlo o předání dat metodou GET
nebo POST). Pro ručnízpracování slouží metody
HttpServletRequest.getQueryString
(pro GET) a
HttpServletRequest.getReader
(pro POST, pokud čekáme textová data) nebo
HttpServletRequest.getInputStream
(pro POST, pokud čekáme binární data). Pro odeslání textových dat slouží
HttpServletResponse.getWriter
, pro odeslání binárních HttpServletResponse.getOutputStream
.
Příklad: výpis HTTP hlaviček:
Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = (String) headerNames.nextElement(); out.print("<tr><td>" + headerName + "</td>"); out.println("<td>" + request.getHeader(headerName) + "</td></tr>"); }
Příklad - výpis příchozích formulářových dat:
Enumeration paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = (String) paramNames.nextElement(); out.print("<tr>\n<td>" + paramName + "</td>\n<td>"); String[] paramValues = request.getParameterValues(paramName); if (paramValues.length == 1) { String paramValue = paramValues[0]; if (paramValue.length() == 0) out.print("<em>No Value</em>"); else out.print(paramValue); } else { out.println("\n<ul>"); for(int i=0; i < paramValues.length; i++) { out.println("<li>" + paramValues[i] + "</li>"); } out.println("</ul>"); } out.println("</td></tr>"); }
Samotný
životservletu má tři fáze: inicializace (metoda
init
), zpracovávání klientských
požadavků (metody doGet
a doPost
- ve skutečnosti jsou tyto metody automaticky volány pomocí
metody service
, kterou můžeme, ale nemusíme, předefinovat) a úklid (metoda destroy
). Metoda
init
je vhodná pro činnosti jako spojení s databází, otevření souborů, v metodě destroy
se
obvykle dělá opak.
Sessions
Protokol HTTP je bezstavový, tudíž každý klientský požadavek je zcela samostatný a nijak nesouvisí s tím předchozím. Což
je v mnoha případech velmi nepříjemné (např. autentifikace). Řešením jsou takzvané HTTP sesssions. Objekt třídy
HttpSession
vytvoříme metodou HttpServletRequest.getSession
, jako parametr jí předáme konstantu
true
, která zajistí, že pokud session spojená s tímto klientem neexistuje, bude vytvořena. Poté do proměnné
typu HttpSession
můžeme pomocí řetězcového klíče ukládat hodnoty libovolné proměnné metodou
putAttribute
(např. putAttribute("customer_details", custDetails)
) nebo tyto hodnoty zase
vyzvedávat (typicky na další stránce naší webové aplikace) metodou getAttribute
- je ovšem třeba provést
explicitní přetypování: custDetails = (Customer) session.getAttribute("customer_details")
. Ke zrušení session
(např. při odhlášení uživatele) slouží metoda invalidate
.
Sessions jsou implementovány pomocí cookies. Ty nemusí prohlížeč umět nebo je mohl uživatel zakázat. Existuje i jiná
možnost, jak sessions implementovat - předáváním session ID v rámci URL. Pro použití tohoto mechanismu je potřeba všechny
odkazy
Bezpečnostním poznámka: session ID je relativně snadno ukradnutelné, pro zvýšení bezpečnosti je výhodnější obejít standardní prostředky a implementovat sessions vlastnoručně - speciální tabulkou pro sessions v databázi, kde bude uloženo session ID, čas posledního přístupu (pro možnost autoexpirace, někteří uživatelé považují tlačítko Logout za zbytečný pedantismus), IP adresu a případně další informace; pro samotné předávání session ID lze zvolit buď cookies nebo přídavný parametr v URL (tím se sice nevyhneme možnosti ukradnutí session ID, ale útočník by musel falšovat i IP adresu, což už představuje výrazně větší problém).
prohnatmetodou
HttpServletResponse.encodeURL
.
Bezpečnostním poznámka: session ID je relativně snadno ukradnutelné, pro zvýšení bezpečnosti je výhodnější obejít standardní prostředky a implementovat sessions vlastnoručně - speciální tabulkou pro sessions v databázi, kde bude uloženo session ID, čas posledního přístupu (pro možnost autoexpirace, někteří uživatelé považují tlačítko Logout za zbytečný pedantismus), IP adresu a případně další informace; pro samotné předávání session ID lze zvolit buď cookies nebo přídavný parametr v URL (tím se sice nevyhneme možnosti ukradnutí session ID, ale útočník by musel falšovat i IP adresu, což už představuje výrazně větší problém).
Cookies
Třída
Cookie
obsahuje konstruktor Cookie(String key, String value)
. Vytvořené cookie lze
nastavovat další vlastnosti (časovou platnost, platnost pro konkrétní doménu, případně cestu v rámci ní, …). Pro
přidání naší cookie do HTTP hlavičky je potřeba zavolat metodu HttpServletResponse.addCookie(Cookie
cookie)
. Naopak k vyzvednutí cookies slouží metoda HttpServletRequest.getCookies
, která vrací
Cookies[]
.