Java Server Pages

Z FI WIKI
Přejít na: navigace, hledání


Úvod

Java Server Pages (JSP) jsou nadstavbou nad Java Servlety. Servlety samotné slouží k nízkoúrovňové obsluze HTTP protokolu. Psát webové aplikace přímo psaním servletů je ale krajně nepohodlné, už proto, že každý generovaný řádek HTML textu musí být vygenerován pomocí volání metody, a to je pro psaní rozsáhlejších stránek hóódně pracné:

 import javax.servlet.http.*;
 import javax.servlet.*;
 import java.io.*;
 
 public class Ukazka extends HttpServlet {
     protected void doGet(HttpServletRequest request, HttpServletResponse response) 
           throws ServletException, IOException {
 
        response.setContentType("text/html;charset=UTF-8");
        ResourceBundle bundle = ResourceBundle.getBundle("Texty", request.getLocale());
        String titulek = bundle.getString("titulek");
        String textOdkazu = bundle.getString("textOdkazu");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println(" <head>");
        out.println("  <title>" + titulek + "</title>");
        out.println(" </head>");
        out.println(" <body>");
        out.println("  <a href=\"http://nekde.com/tam.html\"" + textOdkazu + "</a>");
         ...
     }
  }

Proto vznikly JSP, které jsou servlety naruby. JSP stránka je text, s občasným vložením Java kódu. Před použitím je JSP stránka "obrácena na líc" do servletu, který je Java kódem obsahujícím generování textu. Výše uvedený servlet lze tedy přepsat jako JSP stránku takto:

<%@ page contentType="text/html;charset=UTF-8" %>
<%
 ResourceBundle bundle = ResourceBundle.getBundle("Texty", request.getLocale());
 String titulek = bundle.getString("titulek");
 String textOdkazu = bundle.getString("textOdkazu");
%>
<html>
 <head>
  <title><%=titulek%></title>
 </head>
 <body>
 <a href="http://nekde.com/tam.html"><%=textOdkazu%></a>
 ...

Úspora psaní znaků oproti psaní servletů je zřejmá. Při použití tzv. JSTL tagů (JSP Standard Tag Library), lze JSP stránku napsat ještě úsporněji bez použití Java kódu:

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
<f:setBundle basename="Texty" />
<html>
 <head>
  <title><f:message key="titulek" /></title>
 </head>
 <body>
 <a href="http://nekde.com/tam.html"><f:message key="textOdkazu" /></a>

(Všimněte si, že uvedené příklady zachovávají zásadu, že zobrazované texty se mění podle toho, jakému jazyku uživatel rozumí, tedy jsou internacionalizované. Více viz odstavec o i18n.)

Definice JSP

Java Server Pages alias JSP jsou textové soubory s příponou .jsp, umístěné ve webové aplikaci, které jsou při prvním požadavku na zobrazení automaticky převedeny servletovým kontejnerem na servlet (.java) a přeloženy do Java třídy (.class). Servlety vzniklé z JSP stránek jsou tedy mapovány na URL původního textového souboru.

Po jakékoliv další změně .jsp souboru dojde při následujícím požadavku znovu k převodu na servlet a rekompilaci. Následná vyvolání JSP jsou již jen spuštěním metody service() přeloženého servletu, jsou tedy velice rychlá, nedochází k opakované analýze JSP stránky.

Nejlepším zdrojem informací o JSP je přímo specifikace JSP, kterou je nutné si stáhnout, není přístupná přímo z webu.

Použití JSP

Skriptlety - špagety s kódem a kečupem

JSP byly původně navrženy jako konkurent ASP (Active Server Pages) firmy Microsoft, tedy jako HTML text proložený tu a tam kusy programovacího jazyka, kde programovacím jazykem byla Java. Tyto kusy programovacího jazyka uvnitř HTML se nazývají skriptlety nebo také SSI - Server Side Includes. Tento přístup, dnes zavržený, vede k vytváření webových aplikací pouze z JSP stránek se skriptlety, jež se špatně opravují a udržují, protože HTML a výkonný kód jsou promíchány. Nicméně kvůli zpětné kompatibilitě JSP dodnes skriptlety podporují, proto je zde ukázka:

<%@ page contentType="text/html; charset=utf-8" pageEncoding="iso-8859-2" %>
<%! //kód mimo metodu service() public String prictiJedna(String a) { return Integer.toString(Integer.parseInt(a)+1); } %> <html> <body> <% //kód uvnitř metody service() if(request.getMethod().equals("GET")) {  %> <form method="post"> Zadejte číslo: <input name="cislo" value=""> <input type="submit" > </form> <% } else if (request.getMethod().equals("POST")) { String cislo = request.getParameter("cislo"); String plusjedna = prictiJedna(cislo);  %> Výsledek <%out.println(cislo);%> + 1 je <%=plusjedna%> <% }  %> </body> </html>

Kdekoliv v JSP textu je možné použít Java kód uzavřený mezi znaky <% %>, ten je pak vložen na příslušné místo v metodě service() výsledného servletu. Protože častou činností je výpis řetězce do generované stránky, existuje konstrukce <%= %>, která vytiskne řetezcový výraz či proměnnou. Pokud je nutné umístit nějaký kód mimo metodu service(), například definici pomocné metody pro často se opakující činnosti, lze tak učinit konstrukcí <%! %>. V Java kódu je možné používat předdefinované proměnné request, response a out, které odpovídají vstupním parametrům metody service() a Writeru pro výstup textu do stránky. Syntaxe skriptletů je přehledně popsaná v JSP 1.2 syntax card.

Používání skriptletů sice díky dynamické rekompilaci JSP stránek po každé změně umožňuje rychlejší vývoj stránek, ale trpí stejnými neduhy jako jiné skriptovací nástoje pro tvorbu webových aplikací (PHP, Perl, atd.) - ve výsledném kódu je těžké se vyznat, a opravy se špatně provádějí. Používání skriptletů je v dnešní době důrazně nedoporučováno.

Model 1 a Model 2

Skriptlety se hojně používaly v architektuře, která se neformálně nazývá Model 1, kdy prohlížeč přistupuje k JSP stránkám přímo (viz J2EE blueprints). Následující stránka je obvykle určena v okamžiku načtení současné stránky přímým odkazem.

Model 1

Model 1 neznamená nutně použití skriptletů, volání funkcionality může být zapouzdřeno do vývojářem definovaných JSP značek, nicméně i tak vede ke špatně udržovatelným aplikacím, protože řízení je rozprostřeno do mnoha JSP stránek.

Naproti tomu tzv. Model 2 používá řídící servlet, který rozhoduje, která stránka má být zobrazena. Model 2 je použitím architektury Model-View-Controller (MVC) u webových aplikací. Použití jednoho řídícího servletu umožňuje lepší zajištění bezpečnosti a logování, a činí jednotlivé stránky méně závislé jedna na druhé. Věnujme MVC vlastní kapitolku.

Model 2


Model-View-Controller

Potíže s webovými aplikacemi vytvořenými podle Modelu 1 vedly k převzetí metodologie z tvorby grafických uživatelských rozhraní (GUI), která se nazýva Model-View-Controller (MVC). V přístupu MVC je aplikace rozdělena na tři části:

Model 
třídy představující čistou funkcionalitu aplikace, nezávislou na uživatelském rozhraní
View 
nástroje pro zobrazení uživatelského rozhraní
Controller 
funkcionalita propojující Model s View, řízení uživatelského rozhraní

Model je tedy nezávislý na uživatelském rozhraní, měl by být použitelný stejně, ať vytváříme webovou aplikaci, desktopovou aplikaci nebo třeba aplikaci pro mobilní telefony. Konkrétní uživatelské rozhraní je pak tvořeno View a Controllerem.

Webové aplikace vytvořené podle MVC se snáze udržují (opravují, mění), a jednou vytvořený Model může být použit znovu.

Konkrétních způsobů, jak použít MVC při tvorbě webových aplikací, je mnoho. Obvykle se používá nějaký rámec pro tvorbu webových aplikací (viz Web Application Frameworks), který používá JSP stránky jako View, a Controller je realizován řídícím servletem, volajícím pomocné třídy. Typickou ukázkou takového rámce jsou Apache Struts.

Při MVC přístupu je přicházející HTTP požadavek nejdříve zachycen servletem, který vyhodnotí, jaká akce na Modelu má být provedena, provede ji, a podle výsledku zvolí příslušné View. View je realizováno nějakou šablonou (třeba JSP stránkou), která na příslušných místech zobrazí data dodaná Controllerem z Modelu. Schematický náčrtek je na obrázku:

Web-tiera7.gif

Oproti Modelu 1, kde URL určují stránku, která má být zobrazena, v Modelu 2 určují URL akci, která má být provedena, a výsledek akce teprve rozhoduje o zobrazené stránkce. Java kód je tak ukryt v Java třídách Controlleru, a je tak striktně oddělen od JSP stránek. Pro předávání dat JSP stránkám fungujícím jako šablony se používají atributy stránky, requestu, session či aplikace, jak je vysvětleno v hesle JavaServlets#Rozsahy_platnosti_atributů.

Historie verzí JSP

Specifikace JSP různých verzí obvykle závisí na určité verzi specifikace Servlet API. Postupně také vznikly doplňky JSP, které byly nejdřív samostatné, a následně byly zařazeny spolu s JSP do Java Enterprise Edition, konkrétně standardní knihovna tagů JSTL (JSP Standard Tag Library) a JSF (Java Server Faces), jejichž verze závisí na verzi JSP.

Uveďme shrnující tabulku souvisejících verzí:

Servlet Java Server Pages JSP Standard Tag Library Java Server Faces Expression Language Java platform implementace
Servlet 4.0 (září 2017) JSP 2.3 JSF 2.2 Unified EL 2.3 Java EE 8, Java 8.0 Tomcat 9.x
Servlet 3.1 (květen 2013) JSP 2.3 JSF 2.2 Unified EL 2.3 Java EE 7, J2SE 7.0 Tomcat 8.x
Servlet 3.0 (prosinec 2009) JSP 2.2 JSTL 1.2.1 JSF 2.0 Unified EL 2.2 Java EE 6, J2SE 6.0 Tomcat 7.x
Servlet 2.5 (září 2005) JSP 2.1 (květen 2006) JSTL 1.2 JSF 1.2 Unified EL 2.1 Java EE 5, J2SE 5.0 Tomcat 6.x, Jetty 6, Glassfish
Servlet 2.4 (listopad 2003) JSP 2.0 JSTL 1.1 JSP EL 2.0 J2EE 1.4 , J2SE 1.3 TomCat 5.x
Servlet 2.3 (srpen 2001) JSP 1.2 JSTL 1.0 JSF 1.0 JSTL EL J2EE 1.3 , J2SE 1.2 TomCat 4.x
Servlet 2.2 (srpen 1999) JSP 1.1 J2EE (1.2), J2SE 1.2 TomCat 3.x
Servlet 2.1 (listopad 1998) JSP 1.0 JDK 1.1
Servlet 2.0 JSP 1.0 JDK 1.1
Servlet 1.0 JDK 1.1

JSP v posledních dvou verzích také využívají speciální jazyk EL (Expression Language). Původně byl součástí JSTL 1.0. které byly samostatnou specifikací, a bylo možné jej používat jen v atributech JSTL tagů. Pak byl přemístěn ze specifikace JSTL do specifikace JSP 2.0, a bylo jej možné používat i kdekoliv v textu JSP stránky, tou dobou se jmenoval JSP EL. Nezávisle vznikla speficikace JSF, která zavedla vlastní jazyk, zvaný JSF EL. Nakonec byly všechny technologie (Servlety, JSP, JSTL, JSF) prohlášeny za součást Java Enterprise Edition, ale byl vytvořen sjednocený jazyk Unified EL 2.1.

Knihovny značek

Pokud v JSP nechceme používat scriptlety (a to nechceme, důvody viz výše), je potřeba jiný mechanismus, jak generovat dynamický obsah. Tímto mechanismem jsou JSP značky (tagy), které znamenají provedení nějaké akce. JSP značka vypadá podobně jako XML značka, tedy

<prefix:jméno atribut="hodnota" />

kde prefix určuje příslušnost k určité rodině značek, jméno specifikuje konkrétní značku.

Specifikace JSP samotná definuje několik takových značek:

<jsp:include page="soubor" /> zavolání RequestDispatcher.include()
<jsp:forward page="soubor" /> zavolání RequestDispatcher.forward()
<jsp:useBean id="id" scope="page|request|session|application" class="package.class" /> najde nebo vytvoří instanci JavaBeanu v daném rozsahu platnosti
<jsp:getProperty name="bean" property="něco /> najde atribut bean a zavolá getNěco()
<jsp:setProperty name="bean" property="něco /> najde atribut bean a zavolá setNěco()

Dále je možné přidávat libovolné další značky pomocí tzv. knihoven značek, jejichž použití je nutné deklarovat na začátku JSP stránky:

<%@page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="h" uri="http://jakarta.apache.org/struts/tags-html" %>
<%@ taglib prefix="moje" uri="http://www.nekde.cz/moje" %> 

Deklarace sváže zvolený prefix se zadaným URI, podle kterého se vyhledá knihovna značek. Implementace knihoven značek se přidávají obvykle jako .jar soubory do /WEB-INF/lib/, každá knihovna obsahuje tzv. TLD (Tag Library Description) soubor popisující jaké značky obsahuje. Knihovnu značek si může vytvořit kdokoliv.

JavaBeans

JavaBean je každá třída, která splňuje určitá pravidla.

  • implementuje java.io.Serializable, aby jej šlo zapsat a znovu načíst
  • má konstruktor bez parametrů
  • pro každou tzv. property jménem jmeno a typu Typ obsahuje metodu Typ getJmeno() nebo metodu void setJmeno(Typ typ).
  • první písmeno jména se mění z malého na velké, pokud není i druhé velké (např. getURL() patří property URL).

Např.

 
public class MujJavaBean implements java.io.Serializable {
 
    private String polozka1;
    private int nejakaPolozka2;
 
    public MujJavaBean() {    }
 
    public String getPolozka1() {
        return polozka1;
    }
 
    public void setPolozka1(String polozka1) {
        this.polozka1 = polozka1;
    }
    
    public int getNejakaPolozka2() {
        return nejakaPolozka2;
    }
 
    public void setNejakaPolozka2(int nejakaPolozka2) {
        this.nejakaPolozka2 = nejakaPolozka2;
    }
}

jazyk EL

Jazyk EL byl původně součástí JSTL, později byl přesunut do JSP. Umožňuje snadný přístup k datům, uloženým jako atributy stránky,requestu,session nebo aplikace. Výrazy jazyka EL pro zpřístupnění dat jsou označeny konstrukcí ${ }. Mohou se vyskytovat kdekoliv v JSP stránce. Jsou vyhodnoceny servletovým kontejnerem. Pokud jsou použity jako hodnota atributu nějaké značky, výsledná hodnota je předána implementaci značky.

Výrazy jazyka EL se skládají z hodnotových výrazů a operátorů. Operátory jsou obvyklé operátory z programovacích jazyků, tj.

  • aritmetické (+,-,*,/,div,%,mod)
  • logické (and,&&,or,||,not,!)
  • relační (==,eq,!=,ne,<,lt,>,gt,<=,ge,>=,le)
  • podmíněný operátor ( podmínka ? splněno : nesplněno)
  • logický operátor empty.

Hodnotové výrazy využívají konvenci jazyka ECMAScript (dříve JavaScript) pro vyvolání property operátorem tečka nebo hranaté závorky, např.:

${uzivatel.jmeno}
${uzivatel['jmeno']}

První část výrazu znamená nalezení rozsahové promměnné' (atributu stránky, requestu, session či aplikace) s klíčem uzivatel. Další části oddělené tečkou či uzavřené v hranatých závorkách znamenají zpřístupnění části objektu podle tohoto klíče:

  • pokud je nalezený objekt JavaBean, zavolá se jeho metoda getJmeno()
  • pokud implementuje java.util.Map, získá se mapy hodnota s klíčem jmeno
  • pokud je pole nebo implementuje java.util.List, použije se číselná hodnota v hranatých závorkách jako index.

Rozsahové proměnné mohou být buď nastaveny voláním setAttribute() na příslušném objektu, nebo mohou být některou z předdefinovaných proměnných:

param mapa parametrů requestu na řetězcové hodnoty (na jednu hodnotu, tj. request.getParameter()
paramValues mapa parametrů requestu na řetězcové hodnoty (na více hodnot, tj. request.getParameterValues()
header mapa názvů HTTP hlaviček na jejich hodnoty
pageScope mapa rozsahových promměných v rozsahu stránky
requestScope mapa rozsahových promměných v rozsahu requestu
sessionScope mapa rozsahových promměných v rozsahu session
applicationScope mapa rozsahových promměných v rozsahu aplikace
pageContext objekt javax.servlet.jsp.PageContext zpřístupňující vše podstatné

JSTL - JSP Standard Tag Library

Protože mnohé činnosti jsou potřeba opakovaně, existuje standardizovaná knihovna značek JSTL. Ve skutečnosti nabízí pět knihoven:

Název URI použití
Core http://java.sun.com/jsp/jstl/core práce s proměnnými, cykly, větvení, práce s URL
XML http://java.sun.com/jsp/jstl/xml práce s XML a XSLT transformace
Internationalization (Formatting) http://java.sun.com/jsp/jstl/fmt zobrazování časových údajů, čísel a textů podle zvoleného jazyka
SQL http://java.sun.com/jsp/jstl/sql SQL funkce, porušuje princip MVC, nepoužívat
Functions http://java.sun.com/jsp/jstl/functions přidává k EL funkce pro práci s řetezci a kolekcemi

JSTL Core

Před použitím je nutné zavést prefix pro knihovnu značek vložením řádku

 
<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>

Uveďme důležité značky. Podrobnosti viz specifikace JSTL 1.2.

bezpečný výpis hodnoty výrazu (při nastavení atributu escapeXML na true, což je default):

 <c:out value="${ EL-výraz }" >

nastavení rozsahové proměnné (atributu) jménem varName na hodnotu výrazu:

<c:set scope="page|request|session|application" var="varName" value="${EL výraz}" />

podmíněné zobrazení těla značky:

 <c:if test="${EL výraz}"> 
 ... 
 </c:if>

vícenásobné větvení, uspěje první část, jejíž výraz je vyhodnocen jako pravdivý, nebo možnost otherwise:

 <c:choose>
  <c:when test="${EL výraz}">
  ...
  </c:when>
  <c:when test="${EL výraz}">
  ...
  </c:when>
  ...
  <c:otherwise>
  ...
  </c:otherwise>
 </c:choose>

cyklus v pevných mezích nebo přes prvky kolekce či pole

 <c:forEach var="varName" begin="1" end="10" step="1">
  ...
 </c:forEach>
 <c:forEach var="varName" items="kolekce">
  ...
 </c:forEach>

sestavení URL s parametry, prefixem aplikace (context-path) a případně uživatelskou session (pokud se nepoužívají cookies)

<c:url var="varName" value="jina.jsp">
  <c:param name="a" value="${a}" />
  <c:param name="b" value="${b}" />
  ...
 </c:url>

Příklady EL a JSTL Core

Nejlépe to ukažme na příkladu. Předpokládejme, že před vyvoláním JSP stránky byly do requestu uloženy data pro zobrazení tabulky, a sice pole JavaBeanů s metodami getNazev() a getHodnota(), a to pod klíčem seznam:

 ...
 Polozka[] seznam = new Polozka[10];
 for(int i=0;i<10;i++) { 
     seznam[i] = new Polozka();
     seznam[i].setNazev(...);
     seznam[i].setHodnota(...);
 }
 request.setAttribute("seznam",seznam);
 
 Map<String,Object> mapa = new HashMap<String, Object>();
    mapa.put("nazev","Pocet slonu");
    mapa.put("hodnota",3);
 request.setAttribute("mapa",mapa);

Pak je snadné tabulku pomocí JSTL značek zobrazit:

 <%@page contentType="text/html" %>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <table>
 <c:forEach var="i" items="${seznam}">
   <tr>
     <th><c:out value="${i.nazev}" /></th>
     <td><c:out value="${i.hodnota}" /></td>
   </tr>
 </c:forEach>
   <tr>
     <th><c:out value="${mapa.nazev}" /></th>
     <td><c:out value="${mapa.hodnota}" /></td>
   </tr>
 </table>

Párová značka c:forEach je cyklus, způsobuje opakované vygenerování obsahu v ní obsaženého, a to pro každou položku nějakého souboru, zadaného atributem items. Souborem může být cokoliv, přes co se dá iterovat, například pole nebo java.util.List. V tomto případě je obsahem atributu EL výraz ${seznam}. Implementace jazyka EL zkusí najít objekt uložený pod klíčem seznam ve všech rozsazích platnosti (scope), a výsledek předá implementaci značky c:forEach. Ta pro každou položku souboru nastaví atribut jménem i a nechá zobrazit svoje tělo.

Značka <c:out> jednoduše vypisuje obsah atributu value, pouze nahrazuje znaky < a >, aby se správně zobrazily v HTML stránce, a tím zabraňuje útokům spočívajícím v zadání speciálních znaků do řetězců. EL výraz ${i.nazev} najde atribut i nastavený značkou c:forEach, a na něm zavolá metodu getNazev(). Její výsledek převede na String a vytiskne ho.

Kromě značek pro tisk a cyklus obsahuje JSTL knihovna Core dále značky pro větvení. c:if vykoná svoje tělo jen pokud je EL výraz v atributu test vyhodnotitelný jako pravda, kdežto c:choose je obdobou příkazu switch, provede tělo prvního vnořeného příkazu c:when, který uspěje:

<c:if test="${ ! empty ovoce}">
   <c:choose>
    <c:when test="${ovoce.typ == 'hruska'}" >  hruštička </c:when>
    <c:when test="${ovoce.typ == 'jablko'}" >  jablíčko </c:when>
    <c:otherwise> neznámé ovoce </c:otherwise>
   </c:choose>
 </c:if>

V tomto příkladu už výrazy jazyka EL nejsou jen jednoduchá nalezení dat, ale obsahují i další operátory, jako negaci, test neprázdnosti či porovnání. Další zásadní značkou z JSTL Core knihovny je c:url, která umožňuje vytvářet odkazy, protože před relativně uváděné odkazy doplňuje prefix webové aplikace, a pokud je používáno sledování session bez použití cookies, tak i přidání identifikátoru session do URL:

<c:url var="au" value="dalsi.jsp">
  <c:param name="r" value="${r}" />
 </c:url>
 <a href="${au}">...

JSTL XML

Knihovna XML poskytuje tři druhy značek, XML Core Actions, XML Flow Control Actions a XML Transform Actions. Podrobnosti viz specifikace JSTL. Jen uveďme, že značky z této knihovny podporují XPath výrazy a XSLT transformace. Například takto lze na výstup dostat transformaci XML souboru pomocí XSLT stylesheetu:

<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:import var="xml" url="/mojedata.xml" charEncoding="utf-8" />
<c:import var="xsl" url="/muj_xslt_stylesheet.xsl" />
<x:transform doc="${xml}" xslt="${xsl}" xsltSystemId="muj_xslt_stylesheet.xsl">
 <x:param name="mujparametr" value="${neco}"/>
</x:transform>

JSTL Formatting

Knihovna Formatting (v poslední verzi nazývaná Internationalization) obsahuje značky určené pro podporu internacionalizace, které se věnuje speciální kapitola, popis je tedy umístěn tam.

JSTL SQL

Tato knihovna je nejspíš výsledkem tlaku pointed-hair bossů na vývojáře u SUNů, navádí totiž k přístupu k databázi na architektonické úrovni, kam vůbec nepatří. Nepoužívat.

JSTL Functions

Knihovna značek může kromě značek poskytovat i implementace funkcí pro EL jazyk. JSTL tedy poskytují určitou sadu standardních funkcí.

Délka kolekce

${fn:length(kolekce)}

Manipulace s řetězci

${fn:substring(name, 0, 30)}
${fn:toUpperCase(name)}
${fn:toLowerCase(name)}
${fn:trim(custId)}
${fn:indexOf(text,'a')}
${fn:contains(string, substring)}
${fn:containsIgnoreCase(name, searchString)}
${fn:replace(inputString, beforeSubstring, afterSubstring)}
${fn:escapeXml(text)}
${fn:substringBefore(text,'*')}
${fn:startsWith(string, prefix)}
${fn:endsWith(string, suffix)}
${fn:join(array, separator)}
${fn:split(string, delimiters)}

Vlastní knihovny značek

Když je JSP stránka převedena na servlet, JSP značka je převedena uvnitř servletu na volání metod obsluhovače značky (tag handler), což je Java třída.

Značka obecně vypadá buď:

 
 <prefix:tag jednoduchy_atribut="hodnota atributu" dynamicky_atribut="hodnota atributu" ...>
    tělo
 </prefix:tag>

nebo

 
 <prefix:tag jednoduchy_atribut="hodnota atributu" dynamicky_atribut="hodnota atributu">
   <jsp:attribute name="fragmentovy_atribut1" >
       hodnota atributu včetně vnořených značek
   </jsp:attribute>
   <jsp:attribute name="fragmentovy_atribut2" >
       hodnota atributu včetně vnořených značek
   </jsp:attribute>
   <jsp:body>
     tělo
   </jsp:body>
 </prefix:tag>

Atributy se dělí na tři druhy:

  • jednoduché - klasické XML atributy v otevírací značce, jejich hodnotou je řetězec nebo EL výraz vyhodnocený kontejnerem
  • dynamické - libovolné atributy nespecifikované jmenovitě v definici značky
  • fragmentové - hodnoty zadávané pomocí <jsp:attribute> v těle značky, mohou obsahovat jiné značky

Jednoduché atributy jsou obdobné normálním XML atributům. Jejich názvy a typy obsahu musí být definovány v definici značky. Jejich obsah vyhodnocuje servletový kontejner, a výsledek předá obsluhovači značky.

Dynamické atributy nemají názvy definovány předem, avšak definice značky musí uvést, že podporuje dynamické atributy.

Výhoda fragmentových atributů je v tom, že mohou obsahovat použití jiných značek (i z jiných knihoven). Obsluhovač značky rozhoduje, které z fragmentových atributů budou vyhodnoceny, v jakém pořadí a kolikrát. Tělo značky je pak speciálním případem fragmentového atributu. Například můžeme vytvořit značku

<p:pokud podminka="${a==1}" >
  <jsp:attribute name="splnena" >
      <table>
      <c:forEach ...
      </table>
  </jsp:attribute>
  <jsp:attribute name="nesplnena">
      <f:message key="neni_jedna" />
  </jsp:attribute>
 </p:pokud>

která podle hodnoty jednoduchého atributu podminka provede buď obsah fragmentového atributu splnena, nebo obsah fragmentového atributu nesplněna.

JSP značky mohou být vnořované. Mohou spolu komunikovat buď veřejně pomocí proměnných jazyka EL, (tj. setAtribute() na nějakém "scope" objektu), nebo privátně přístupem k nadřazeným značkám.

Vytvoření nové značky můžeme provést třemi způsoby. Buď vytvoříme soubor s příponou .tag, nebo značku implementujeme jako třídu rozšiřující třídu javax.servlet.jsp.tagext.SimpleTagSupport, nebo značku implementujeme jako třídu rozšiřující třídu javax.servlet.jsp.tagext.TagSupport.

Soubor s příponou .tag

Nejjednodušší vytvoření nové značky je vytvořením souboru s příponou .tag v adresáři /WEB-INF/tags, jehož obsahem je fragment JSP stránky s definovanými atributy. Toho lze s výhodou využít například pro opakující se fragmenty kódu, které lze parametrizovat. V souboru .tag je možné používat jiné knihovny značek, musí jen být zavedeny stejně jako v normálních JSP pomocí direktivy <%@taglib%>:

 
<%-- /WEB-INF/tags/tabulkalidi.tag --%>
<%@ tag %>
<%@ attribute name="lidi" type="cz.moje.Clovek[]" rtexprvalue="true" required="true" %>
<%@ attribute name="edit" type="java.lang.Boolean" rtexprvalue="true" required="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
 
<table>
  <tr> <th> Jméno </th><th> Příjmení </th></tr>
  <c:forEach var="clovek" items="${lidi}">
   <tr> 
     <td><c:out value="${clovek.jmeno}"/></td>
     <td><c:out value="${clovek.prijmeni}"/></td>
     <c:if test="${edit}">
       <td><a href="/edit?id=${clovek.id}">edit</a></td>
     </c:if>
   </tr>
  </c:forEach>
</table>

Zavolat jej pak můžeme takto:

 
<%@ taglib tagdir="/WEB-INF/tags" prefix="h" %>
 
 <h:tabulkalidi lidi="${lidi} />
 
 

V souboru s příponou tag můžeme používat i skriptlety. Parametry tagu existují i jako lokální proměnné. Můžeme dokonce předávat hodnoty do atributů pomocí

 
 <% for(Clovek clovek : lidi) { %>
 <td><c:out value="<%=clovek.getJmeno()%>"/></td>
 <% } %>
 

Soubor .tag je servletovým kontejnerem tiše převeden na implementaci Java třídy rozšiřující třídu SimpleTagSupport, viz dále.

Vlastní A tag

Vytvářet hyperlinky v rámci jedné aplikace je poměrně pracné, proto si na to můžeme vytvořit vlastní tag v souboru /WEB-INF/tags/a.tag s následujícím obsahem:

 
<%@ tag pageEncoding="utf-8" trimDirectiveWhitespaces="true" %>
<%@ attribute name="href" required="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:url value='${href}' var="url" scope="page"/>
<a href="<c:out value='${url}'/>"><jsp:doBody/></a>
 

a vyvolat se dá pomocí

 
<%@ taglib tagdir="/WEB-INF/tags" prefix="my" %>
...
<my:a href="/neco">Něco</my:a>

Implementace pomocí SimpleTagSupport

Novou značku můžeme vytvořit tak, že popíšeme její definici v souboru TLD (Tag Library Descriptor) a naimplementujeme obsluhovač značky jako Java třídu rozšiřující třídu javax.servlet.jsp.tagext.SimpleTagSupport. Uveďme si jako příklad značku podminka uvedenou výše. Musíme vytvořit TLD soubor s příponou .tld v adresáři /WEB-INF/, obsahující definici značky a jejích atributů:

<taglib 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-jsptaglibrary_2_0.xsd"
  version="2.0">
    <tlib-version>1.0</tlib-version>
    <short-name>Moje</short-name>
    <uri>http://www.nekde.cz/moje</uri>
    <tag>
        <name>pokud</name>
        <tag-class>cz.nekde.PokudTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <description>Podminka k vyhodnoceni</description>
            <name>podminka</name>
            <required>yes</required>
            <rtexprvalue>yes</rtexprvalue>
            <type>boolean</type>
        </attribute>
        <attribute>
            <description>fragment provedeny pokud podminka plati</description>
            <name>splnena</name>
            <required>no</required>
            <fragment>yes</fragment>
        </attribute>
        <attribute>
            <description>fragment provedeny pokud podminka neplati</description>
            <name>nesplnena</name>
            <required>no</required>
            <fragment>yes</fragment>
        </attribute>
    </tag>
</taglib>

a implementaci obsluhovače:

 package cz.nekde;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 import javax.servlet.jsp.tagext.JspFragment;
 import javax.servlet.jsp.JspException;
 import java.io.IOException;
 
 public class PokudTag extends SimpleTagSupport {
    //definice promennych pro atributy
    private boolean podminka;
    private JspFragment splnena;
    private JspFragment nesplnena;<br>
    public boolean isPodminka() {  return podminka; }
    public void setPodminka(boolean podminka) { this.podminka = podminka;   }
    public JspFragment getNesplnena() {  return nesplnena;  }
    public void setNesplnena(JspFragment nesplnena) { this.nesplnena = nesplnena;   }
    public JspFragment getSplnena() { return splnena; }
    public void setSplnena(JspFragment splnena) {this.splnena = splnena; }<br>
    //implementace zpracovani jednoho nebo druheho fragmentoveho atributu podle podminky
    public void doTag() throws JspException, IOException {
        if(podminka) {
            if(splnena!=null) splnena.invoke(null);
        }  else {
            if(nesplnena!=null) nesplnena.invoke(null);
        }
    }
 }

V JSP stránce pak stačí nadeklarovat knihovnu s touto značkou pomocí jejího URI a značku použít:

<%@ taglib prefix="m" uri="http://www.nekde.cz/moje" %>
...
<m:pokud podminka="${param.a == 1}" >
     <jsp:attribute name="splnena">   Splneno !   </jsp:attribute>
     <jsp:attribute name="nesplnena"> Nesplneno ! </jsp:attribute>
</m:pokud>

V hodnotách atributů, a to i fragmentových, nelze používat skriptlety. Lze však používat výrazy jazyka EL, a v hodnotách fragmentových atributů i jiné značky.

Implementaci značek lze spolu s TLD souborem zabalit do JAR archívu, který pak lze distribuovat do světa. V tom případě musí být TLD soubor umístěn v adresáři /META-INF v JAR souboru, a tento JAR soubor se dává do /WEB-INF/lib adresáře webových aplikací.

Vytvoření vlastní funkce

Kromě tagu si můžeme nadefinovati vlastní funkci pro jazyk EL. V .tld souboru ji musíme popsat:

 
 ...
 <function>
   <description>moje funkce </description>
   <name>mojefce</name>
   <function-class>cz.moje.MojeTagLibFunkce</function-class>
   <function-signature>boolean mojefce(cz.moje.Neco,cz.moje.NecoJineho)</function-signature>
 </function>
 ...

a implementujeme ji pomocí statické funkce:

 
 public static boolean mojefce(cz.moje.Neco n,cz.moje.NecoJineho nj) {
    return n.jeZelene() && nj.neniModre();
 }

V JSP stránce ji pak použijeme v EL výrazech:

 
<%@ taglib prefix="m" uri="http://www.nekde.cz/moje" %>
...
 <c:if test="${m:mojefce(jablko,svestka)}">
 ...
 </c:if>

Implemetace pomocí TagSupport

Tato možnost je historicky starší než implementace pomocí SimpleTagSupport, je pracnější a jedinou její výhodou je, že v hodnotách atributů je povoleno používat skriptlety. Protože však používání skriptletů je odsouzeníhodné, nebudeme tuto možnost dále rozebírat. Používejte SimpleTagSupport.

Využití pro šablony stránek

Soubory s příponou tag a fragmentové atributy můžeme dohormady výhodně použít pro definici šablony stránek.

Např. můžeme vytvořit soubor WEB-INF/tags/layout.tag s následujícím obsahem definujícím části společné všem stránkám (menu, nadpis atd.):

 
<!DOCTYPE html>
<%@ tag pageEncoding="utf-8" dynamic-attributes="dynattrs" trimDirectiveWhitespaces="true" %>
<%@ attribute name="title" required="true" %>
<%@ attribute name="head" fragment="true" %>
<%@ attribute name="body" fragment="true" required="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
 
<html>
<head>
    <title><c:out value="${title}"/></title>
    <jsp:invoke fragment="head"/>
</head>
<body>
<h1><c:out value="${title}"/></h1>
<nav>
    <ul>
        <li><a href="<c:url value='/'/>">Home</a></li>
        <li><a href="<c:url value='/about/'/>">About us</a></li>
    </ul>
</nav>
<jsp:invoke fragment="body"/>
</body>
</html>

a všechny stránky pak mohou tuto šablonu využívat:

 
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %>
<%@ taglib tagdir="/WEB-INF/tags" prefix="my" %>
<my:layout title="Nadpis">
    <jsp:attribute name="head">
        <style>
            table { border-collapse: collapse; margin: 10px; }
            table th, table td {  border: solid 1px black; padding: 4px; }
        </style>
    </jsp:attribute>
    <jsp:attribute name="body">
        <table>
            <tr>
                <th>A</th>
                <td>B</td>
            </tr>
        </table>
    </jsp:attribute>
</my:layout>

Internacionalizace

Viz heslo I18n - Internacionalizace.

Shrnutí

Tato stránka je součástí souboru hesel o webových aplikacích. Java Server Pages jsou textové soubory, převáděné za běhu aplikace na servlety. Používají se jako šablony pro generování webových stránek, do kterých se na zvolených místech doplňují dynamicky získaná data.

Doporučujeme pokračovat heslem Bezpečnost ve webových aplikacích.