V tomto článku dokončíme rozprávanie o zdieľaní objektov a externých zdrojov v súvislosti so servletmi. Hlavnou témou bude zdieľanie a správa atribútov webovej aplikácie na troch úrovniach (v kontexte aplikácie, aktuálneho sedenia a príchodzej požiadavky).

Už vieme, že servlety môžu spolupracovať prostredníctvom filtrovania a reťazenia požiadaviek. Ďalej prostredníctvom presmerovania a predávania riadenia na iné zdroje. Môžu tiež využívať rôzne zdieľané objekty, respektíve zdroje, a priamo k nim pristupovať. Spomenul som, že v starších verziách špecifikácie mohol servlet priamo volať public metódy iného servletu. Nehovorili sme zatiaľ o možnosti vytvárania kvázi databáz atribútov, ktoré je možné zdieľať na rôznych úrovniach.

Na začiatok si skúste prezrieť nasledujúci obrázok. Snažil som sa v ňom vystihnúť podstatu dnešnej témy:

Bloková schéma delenia atribútov vo webovej aplikácii

Zdieľanie atribútov na úrovni requestu

Vieme, že pri požiadavke sa vytvorí objekt nesúci rôzne typy informácií. Tento objekt môže obsahovať aj formulárové dáta ako parametre. A v neposlednom rade je možné tento objekt predať inému servletu či stránke JSP, bez toho aby stratil platnosť. Čo ak však potrebujeme preniesť aj iné typy objektov medzi požiadavkami, nesúce iné typy informácií ako sú formulárové dáta?

Na tento účel sa využívajú práve takzvané request atribúty, ktoré sa prenášajú spoločne s požiadavkou. Atribúty sa nastavujú pomocou metódy request.setAttribute("name",object). Táto metóda nám umožňuje ukladať objekty akéhokoľvek typu pod vybraným menom a pod týmto menom sa neskôr na daný objekt odkazovať. Využijeme to napríklad pri request dispatchingu. Uložený objekt môže byť napríklad JavaBean, štandardná Java trieda alebo vlastná trieda. Všetky takto vložené objekty zostávajú v platnosti počas doby trvania požiadavky, čo je dovtedy, kým servlet nepošle odpoveď.

Nasleduje krátka ukážka kódu, v ktorom nastavíme atribút predstavujúci počet prístupov na stránku. Tento kód by ste mohli nájsť v servlete, ktorý presmerováva riadenie (cez metódu forward()) na iný servlet.

//calledCount predstavuje premennú, ktorú chceme uložiť do atribútu
int calledCount;
//pričom ju musíme previesť na objektový typ
request.setAttribute(„count“, new Integer(calledCount));

Pokračujeme výpisom ukazujúcim, ako získame hodnotu uloženú ako atribút. Tento kód by ste zase mohli nájsť v servlete, ktorému bolo predané riadenie v procese servlet dispatchingu.

//získanie hodnoty atribútu a pretypovanie na integer
Integer tempCount = (Integer)request.getAttribute(„count“);
int calledCount = tempCount.intValue();
out.println(„Počet prístupov: “ + calledCount);

Zdieľanie atribútov na úrovni session

O objekte HttpSession sme pomerne podrobne hovorili v časti Java Servlets – session tracking. Ukázali sme si, ako zabezpečiť uchovanie stavu medzi požiadavkami toho istého klienta na ten istý servlet. Vysvetlili sme si, ako sa vytvorí objekt session, ako ho spravovať, naplniť atribútmi a podobne. Nemusím sa teda k tomu znova podrobne vracať, spomenieme iba veci týkajúce sa dnešného článku.

V prvom rade je dôležité si uvedomiť, že servlety, spadajúce pod konkrétnu session (viď obrázok), môžu navzájom zdieľať session atribúty (objekty). Jediným obmedzením je, že tieto objekty je možné zdieľať len medzi servletmi spadajúce pod jeden konkrétny aplikačný kontext (web aplikáciu).

Zopakujme si teda, ako nastavíme atribúty session, ako ich získame a prípadne vymažeme:

HttpSession session = request.getSession();
//nastavenie hodnoty atribútu
session.setAttribute(String name, Object value);
//získanie hodnoty atribútu
Object object = (Object) session.getAttribute(String name);
//odstránenie atribútu
session.removeAttribute(String name);

Zdieľanie atribútov na úrovni aplikácie

V predošlom odstavci som použil pojem „aplikačný kontext“. Je to v podstate virtuálny priestor, v ktorom sa nachádzajú servlety, JSP, HTML stránky a iné zdroje web aplikácie, ktoré zdieľajú informácie a vzájomne spolupracujú podľa vopred danej logiky. Tento koncept webovej aplikácie je vyjadrený a používaný objektom ServletContext balíčka javax.servlet.

ServletContext definuje zo strany servletu pohľad na aplikáciu, pod ktorou beží. Umožňuje servletu pristupovať k zdrojom určeným preň. Prostredníctvom neho môže servlet logovať udalosti, získavať URL referencie na zdroje, nastavovať a čítať atribúty na úrovni aplikácie. Atribúty sú potom prístupné aj ostatným zdrojom aplikácie. To všetko spôsobom, ktorý sa podobá na prácu s atribútmi na úrovni sedenia a požiadavky. Každá web aplikácia môže vlastniť len jednu inštanciu triedy ServletContext.

Vytvoríme si príklad, v ktorom si ukážeme použitie techniky zdieľania atribútov na úrovni aplikácie. Majme dva jednoduché servlety – ContextSetAttribute, cez ktorý budeme atribúty nastavovať, a ContextGetAttribute, cez ktorý ich budeme čítať. Tieto dva servlety nebudú spolupracovať priamo, budú len využívať zdieľané dáta.

package interval;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ContextSetAttribute extends HttpServlet {
  public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
    res.setContentType(„text/html“);
    PrintWriter out = res.getWriter();
    out.println(„<HTML><TITLE>SetContextAttribute</TITLE><BODY>“);
    out.println(„<H4>ServletContext example – Attribute Setter</H4><HR>“);
     ServletContext sc = getServletContext() ;
    int calledCount = 0;
    if (sc. getAttribute („calledCount“) != null) {
      Integer tempCount = (Integer) sc.getAttribute(„calledCount“);
      calledCount = tempCount.intValue();
    }
    out.println(„ServletContext, server info: “ + sc.getServerInfo() + „<BR>“);
    out.println(„ServletContext, real path: “ + sc.getRealPath(„“) + „<BR>“);
    out.println(„The attribute ‚calledCount‘ value we retrieved: “ +
        calledCount + „<BR>“);
    calledCount++;
     sc.setAttribute(„calledCount“, new Integer(calledCount)) ;
    out.println(„We set the ServletContext attribute ‚calledCount‘ to: “ +
    sc.getAttribute(„calledCount“));
    out.println(„</BODY><HTML>“);
    out.close();
  }
}

Vždy, keď zavoláme ContextSetAttribute servlet, inkrementuje sa počítadlo a jeho hodnota sa uloží ako atribút, respektíve ak už taký atribút existuje, je nahradený novou hodnotou. Ak zavoláme servlet ContextGetAttribute, tento si prečíta poslednú hodnotu atribútu a vypíše ju na výstup.

package interval;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ContextGetAttribute extends HttpServlet {
  public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
    res.setContentType(„text/html“);
    PrintWriter out = res.getWriter();
    out.println(„<HTML><TITLE>SetContextAttribute</TITLE><BODY>“);
    out.println(„<H4>ServletContext example – Attribute Getter</H4><HR>“);
     ServletContext sc = getServletContext() ;
    int calledCount = 0;
    if (sc. getAttribute („calledCount“) != null) {
    Integer tempCount = (Integer) sc. getAttribute („calledCount“);
        calledCount = tempCount.intValue();
    }
    out.println(„The attribute ‚calledCount‘ value we retrieved: “ +
        calledCount + „<BR>“);
    out.println(„</BODY></HTML>“);
    out.close();
  }
}

Týmto článkom by sme uzavreli kapitolu zdieľania zdrojov a vzájomnej spolupráce servletov, respektíve iných zdrojov webovej aplikácie. Uvedené zdrojové kódy si môžete stiahnuť a vyskúšať.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

1 Příspěvěk v diskuzi

  1. Dobry den, S java EE este len zacinam a dost sa trapim s otazkou connectionu. Je spravne zdielat na urovni aplikacie connection vytvoreny pomocou DBCP ? servlety si zdielaju pripojenie, ktore uz vzniklo v jedinom servlete. Ak sa to takto nerobi budem rad ak ma opravite. Este jedna vec s tymto riesenim sa mi naskytla. Nemozem v servlete nikde ukoncit connection ani statement inak mi to pise SQLExceptiony. Bol by som vdacny za akukolvek informaciu popripade link na nejaky rozhsiahlejsi zdroj na tuto temu. Dakujem

Odpovědět