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ý život servletu 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 prohnat metodou 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[].