JSTL (JavaServer Pages Standard Tag Library)

From Bauman National Library
This page was last modified on 1 June 2016, at 17:12.
JSTL
Developer Oracle
First appeared 2006
Stable release 1.2.1 / 2015.12 (1.2.1)
OS Cross-platform
Filename extensions .jsp .jspf .jsf
Website jstl.java.net
Influenced by
HTML, JSP

JSTL (JavaServer Pages Standard Tag Library) - JSP specification extension, adds libraries of JSP tags for common needs such as XML parsing, conditional processing, creating loops and localization support.

History

This article focuses on the means of display (layer View in the Model-View-Controller) in JAVA EE. Before the JSP there were the only servlets to create web applications in JAVA. Servlet - a special class with a set of required methods (doGet, doPost, and others), who called from the browser and generates a HTML-page. First, on the basis of data sent from a client (the request parameters or contents of the form fields) needed to perform the calculation of some information and prepare a data set in any way to visualize them, i.e. Stir HTML-tags and prepared data. It looked awful:

OutputStream out = response.getOutputStream();
out.println("<HTML>");
out.println("<body>");
out.println("<h1> Привет, " +  vasyanoFIO + "</h1>");
out.println("</body>");
out.println("</HTML>");

Then we come up with JSP. A typical page is characterized by a significant excess of the amount of static HTML-code of the dynamic information (taken from files, databases, calculated in a web application), so it was logical not to embed HTML-code into JAVA-code and the other way around - embed JAVA-code inside an HTML-template.

<%@ page contentType="text/HTML;charset=UTF-8" language="JAVA"%>
<body>
<%
    String vasuanoFIO = "Бла-бла-бла";
    if ( 1 < 2)
        vasuanoFIO = "Бум-бам-тарарам";
%>
<h1><%= vasuanoFIO %></h1>
</body>

It does not look very nice. Of course, if you need to quickly make a single page, it is a good way out, only to embed the logic of calculating the data in HTML is not good. As the number and complexity of the calculations layout code turns into a vinaigrette. Big code is not readable. The code contains HTML and logic are not readable even more. Very soon a part of the logic will be duplicated and spread over thousands of files, so understand what is it and where it came from becomes impossible. Also this solution greatly complicates the life of the designers. The standard JSP recommended practice is to move the processing logic in the request bean. For example, the problem with greetings can be issued as a separate class and adding the field to it (control calculation of the final value).

public class HelloMachineBean {
    public String fio;
    public String age;
    public String sex;

    public String getFio() {
        return fio;
    }

    public void setFio(String fio) {
        this.fio = fio;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getResult (){
        if ("male".equalsIgnoreCase(sex))
            return "Это дядя " + fio + " его возраст "+age;
        return "Это тетя "+fio+ " ее возраст "+age;
    }
}

Note the method getResult - is it contains the logic for calculating the message that will be shown to the user. Now you need to create a JSP-file in which the bean object is created, its properties are filled with values and calculated value recieved (getResult).

// create an object of logic, indicate the name and JAVA-class
<jsp:useBean id="helloMachine" class="t
sti.HelloMachineBean" />
// now beginning to fill in the values of the fields in this class bean syntax
// property=”*” means that all query parameters come to be placed inside the bean.
<jsp:setProperty name="helloMachine" property="*" />
// case, when the specific name of the property that you need to filled in the information field, and the name of the HTTP-request
<jsp:setProperty name="helloMachine" property="fio" param="fio" />
// attribute can be assigned a value as a constant
<jsp:setProperty name="helloMachine" property="sex" value="female" />
// Use as if a part of the class has a property hellMachine result
// to access the properties, use methods getters,
// so the actual existence of a class field named result unimportant
<h2>
    Hello <jsp:getProperty name="helloMachine" property="result" />
</h2>

This approach has many pitfalls. For example, if you create a JSP-page as the successor of a servlet class. The main problem is that programmers can (and will mean a) mixing JAVA-code and HTML:

<%
 if ( bla-bla)
  …
 else
  …
%>

There is another problem: the real site operates not only scalar data (a variable with a string value fio), but also lists, arrays. For processing cycles and conditionals are needed, (if the amount of money in the account is less than $ 100, then to bring it red, else - green). You can transfer cycles and conditions inside the beans, but in fact, it means that we will move generation of HTML-code into beans (the consequences of such a decision we have already seen in the case of servlets), so some primitive processing conditions and cycles are needed on the page, otherwise we will get a lot of problems.

<%
    String vasuanoFIO = "No. You can not defeat the forces of evil";
    if ( 1 < 2)
        vasuanoFIO = "Your fight against the cereal in a JSP is doomed to failure, Ha ha ha!";
%>

To simplify come up with custom tags. Those. You can create a JAVA-class who can do something and inject it into the page, for example:

<showcalendar />
<mailsend to="vasyano@mail.ru" />

It is very convenient and everything began to create their own libraries of "very relevant" tags. But this approach is not conducive to the accumulation of knowledge because there were too much tag libraries, but suffered the quality of these libraries. Therefore, the appearance of standards adopted by the set of tags and their quality implementation were inevitable. So there was JSTL – JAVA Servlet Templates Libruary.

Application

  • Download archive from the site with the library STL (the examples use version 1.2).
  • Add the library in the folder WEB-INF/lib of your web application.
  • Connect at the beginning of JSP-file using special taglib directives tag libraries you want to use.

Key tags allow to do loops, conditions, display information on the screen:

<%@ taglib prefix="c" uri="HTTP://JAVA.sun.com/JSP/jstl/core" %>

Tags for working with xml-documents:

<%@ taglib prefix="c" uri="HTTP://JAVA.sun.com/JSP/jstl/xml" %>

Tags for work with databases:

<%@ taglib prefix="c" uri="HTTP://JAVA.sun.com/JSP/jstl/sql" %>

Tags for formatting data before displaying and working with i10n and i18n:

<%@ taglib prefix="c" uri="HTTP://JAVA.sun.com/JSP/jstl/fmt" %>

First, we analyze the tags from the library JSTL / core. Let's start with the most simple: to display some text browser.

<%@ page contentType="text/HTML;charset=UTF-8" language="JAVA" %> 
<%@ taglib prefix="c" uri="HTTP://JAVA.sun.com/JSP/jstl/core" %>

<HTML>
  <head><title>Simple JSP page</title></head>
  <body>
    <c:out value="hello, Vasuano" />
  </body>
</HTML>

Sense in this design a little, because a simple static text, we can deduce without a tag and JSTL. c: out is needed to display the dynamically calculated values:

<c:out value="${12+56*2}" />

There is a list of pre-defined context:

Context A comment
pageScope The page context (variables declared on this page and available only for the page)
requestScope Access to these variables are all the pages (servlets), serving the current user request
sessionScope Access to a variable is maintained throughout the user session (until you close the browser or the inactivity time limit has expired)
applicationScope Access to a variable is retained on all pages to be included within the Web application
param In this context, all the variables are derived from the user page or the parameters of the address bar, or as a field
paramValues The list of values of variables that were passed to the page by the user in the form of a HashMap <String, String []>
header This site contains information about the HTTP-headers, which were transferred from the web server to the client
headerValues The list of HTTP-header values
initParam Configuration parameters specified for your page, the servlet in web.xml
cookie The list of variables within a cookie
pageContext Object reference pageContext

To refer to a variable located inside one of the contexts that you need to write the name of the context, then point and the variable name. And possible alternative syntax:

<c:out value="${param.fio}" />
<c:out value="${param['fio']}" />

Tag c:out has more attributes:

<c:out value="${param.fio}" default="NO DATA" escapeXml="true" />

In this example, if the input page is filed variable fio, we will see the phrase "NO DATA".

To create a variable tag c:set is used . As its attribute the name of context where we want to put a variable, the variable name and value is specified:

<c:set var="vasyano" scope="session" value="Вася Тапкин" /> 
<c:set var="petyano" scope="page">
  Петька Козлов на странице
</c:set>
<c:set var="petyano" scope="request">
  Петька Козлов в запросе
</c:set>
<c:set var="petyano" scope="session">
  Петька Козлов в сессии
</c:set>
<c:set var="petyano" scope="application">
  Петька Козлов в приложении
</c:set>
vasyano: <c:out value="${sessionScope.vasyano}" />

petyano: <c:out value="${petyano}" />

Shown here are a few tricky moments in the JSTL. First, notice how the names are different contexts in the set operation and the operation out. In the first case, you must write the word session, and in the second case - sessionScope. Also, if you do not specify the name of the context, the right context usually found by the rules: looking for a variable inside pageScope, if not found, then inside the requestScope, if not found again, something inside sessionScope and finally inside applicationScope.

There is another option in syntax of the c:set, when you need to set the properties of a JAVA-bean, embedded on the page.

<c:set target="${helloMachine}" property="fio" value="Ленка Слонова" />
<c:out value="${helloMachine.fio}" />

To remove variables (assigning null to a value) remove statement is used:

<c:set var="fio" scope="session" value="Vasyano Petrovno" />
 fio1 = <c:out value="${fio}" />
<c:remove var="fio" />
 fio2 = <c:out value="${fio}" />

Operators if and switch

The if statement is not like its big brothers in JAVA and other languages: You can not set any branch else, no branch elseif (elif), you can only check a condition and do something, if it is true:

<c:if test="${param.age gt 12}">
  Age over 12 years
</c:if><c:if test="${param.age lt 25}">
  Age less than 25 years
</c:if>

Note that in the condition the words "gt" and "lt" are used instead of marks "<" and ">", it is necessary because otherwise we violate the rules of recording xml-documents. There are other words operators:

  • eq – check for equality
  • ne – check for not equality
  • lt – strictly less than
  • gt – strictly more than
  • le – less than or equal to
  • ge – more than

if tag has several optional attributes that can be useful not to use recurring expression. The result of calculation (of attribute test) is written to the var attribute. The scope attribute specifies the context in which to put this variable.

<c:if test="${param.age gt 12}" var="if_less_12">
  Age over 12 years
</c:if>

<c:if test="${if_less_12}">
  Agean: Age over 12 years
</c:if>

If you need to check multiple conditions, you can use the tag choose -> when -> otherwise:

<c:choose>
  <c:when test="${param.age lt 10}">
      Age less than 10 years
  </c:when>
  <c:when test="${param.age lt 20}">
      Age in the interval from 10 to 20 years
  </c:when>
  <c:otherwise>
      Urgently go to the procedure of euthanasia
  </c:otherwise>
</c:choose>

Loops

Consider cycles in JSTL. There are two types of cycles: to pass on the elements of a list, and to traverse the list of tokens (parts into which the line was broken by some separator character).

The first tag "c:ForEach" has 6 attributes that govern its work but among them there is no mandatory.

Incorporated into the above-described class HelloMachineBean several new methods that return an array of items and a list of items.

public List< String> getFriendsAsList () {
        return Arrays.asList(getFriendsAsArray ());
}

public String[] getFriendsAsArray(){
    return new String[]{"Васька", "Петька", "Ленка"};
}

An example of the use of these data in the cycle:

<c:set var="friends" value="${helloMachine.friendsAsArray}" />
<c:set var="friends2" value="${helloMachine.friendsAsList}" /><c:forEach items="${friends}" var="friend">
    <h2>
        <c:out value="${friend}"/>
    </h2>
</c:forEach><c:forEach items="${friends2}" var="friend">
    <h3>
        <c:out value="${friend}"/>
    </h3>
</c:forEach>

There are two attributes of ForEach tag - items, playing the role of a data source, and var - variable, which is aggregate the elements of array / list.

The second option ForEach loop is designed to pass through the integers in the interval from X to Y, for example:
<c:forEach var="friend_i" begin="0" end="2">
    <h5>
        <c:out value="${friend_i}"/> =  <c:out value="${friends[friend_i]}"/>
    </h5>
    <h4>
        <c:out value="${friend_i}"/> =  <c:out value="${friends2[friend_i]}"/>
    </h4>
</c:forEach>

Note that using the index (in square brackets) can refer to not only the elements of the array, but also of the list. Another attribute of the tag forEach is step. It controls the value of step with which we run through the elements of the array. In the following example, the attribute step works correctly, not only when the cycle goes through the numbers in the interval from X to Y, but when he goes throuth the contents of a collection of items.

<c:forEach items="${friends}" var="friend" step="2">
    <h2>
        <c:out value="${friend}"/>
    </h2>
</c:forEach><c:forEach var="friend_i" begin="0" end="2" step="2">
    <h5>
        <c:out value="${friend_i}"/> =  <c:out value="${friends[friend_i]}"/>
    </h5>
    <h4>
        <c:out value="${friend_i}"/> =  <c:out value="${friends2[friend_i]}"/>
    </h4>
</c:forEach>

The last attribute for the cycle For - varStatus. This variable can monitor cycle is performed and the current step. Variable value differs depending cycle type is used. In the normal cycle, from X to Y value of this variable is the current code:

<c:forEach var="friend_i" begin="0" end="2" step="2" varStatus=”friendStatus”>
  <h5>
      friend_i = <c:out value="${friendStatus}"/>*
      <c:out value="${friend_i}"/> =  <c:out value="${friends[friend_i]}"/>
  </h5>
</c:forEach>

If the cycle is carried out through a collection, then varStatus - a complex object with information about the initial and final step of the cycle, about to go over the first element of the collection or not etc, for example:

<c:forEach items="${friends}" var="friend" step="1" varStatus="friendStatus">
    Status:
    index=<c:out value="${friendStatus.index}"/>
    count=<c:out value="${friendStatus.count}"/>
    first=<c:out value="${friendStatus.first}"/>
    last=<c:out value="${friendStatus.last}"/>
    step=<c:out value="${friendStatus.step}"/>
    <h2>
        <c:out value="${friend}"/>
    </h2>
</c:forEach>

Let us turn to the second type of cycles - for Tokens. This cycle is similar to the previously given forEach: many of the attributesare the same, but the key difference is that the loop goes through the list of tokens representing splitted line:

<c:set var="str" value="Graviton Photon Boson muon" />
<c:forTokens items="${str}" delims=" " var="token" begin="1" varStatus="tokenStatus" step="1">
    index=<c:out value="${tokenStatus.index}"/>
    count=<c:out value="${tokenStatus.count}"/>
    first=<c:out value="${tokenStatus.first}"/>
    last=<c:out value="${tokenStatus.last}"/>
    step=<c:out value="${tokenStatus.step}"/>
     
    <h2>     
        <c:out value="${token}"/>      
    </h2>
</c:forTokens>

The string "Graviton Photon Boson muon" is divided into separate substrings using delimiter delims (blank). The cycle does not start with the first element - "Graviton", and the second - "Photon". At each iteration of the loop information about the iteration number and an indication whether it is first or last iteration is displayed. The trouble is that the value of count can not be used, the value is not "4", as expected, but increases as the loop evaluates. The value of the attribute tokens can be multiple characters, such as:

<c:set var="str" value="Гравитон,Фотон.Бозон Мюон" />
<c:forTokens items="${str}" delims=" ,." var="token" begin="0" varStatus="tokenStatus" step="1">
    <h2>
        <c:out value="${token}"/>
    </h2>
</c:forTokens>

The division into modules

Obviously, it's hard to write good code pages in a single file without splitting it into parts, so import tag is the part of the JSTL and allows to include in a JSP-file another JSP-file. This tag is very flexible, in the simplest case, the page can include a piece of static text as HTML / txt block:

<c:import url="heading.HTML" />

An example of inclusion in the JSP-page result of work of other JSP-page: Including page is (footer.JSP):

<%@ page import="JAVA.util.Date" %>
<%@ page contentType="text/HTML;charset=UTF-8" language="JAVA"%>
<%@ taglib prefix="c" uri="HTTP://JAVA.sun.com/JSP/jstl/core" %><%
    out.write("Complex calculations on the introduction of information into ... " + new Date());
%>
<h1>
    <c:out value="${externalVar}" />
</h1>

Main page:

<c:set var="externalVar" value="Hello from Outer page"  scope="request"/>
<c:import url="footer.JSP" />

Similarly, you can pass variables from a sub-page to the outside (do not forget the context variables). On the page will be available to be included and those variables that were transferred to the main script from HTML-forms. For example, a clear indication of the encoding:

<c:import url="heading.HTML" charEncoding="utf-8" />

The content of the included page can not be even send directly to the client browser, but can be accumulated in a certain variable for further processing, for example:

<c:import url="heading.HTML" charEncoding="utf-8" var="inner_c" scope="request" />
<c:out value="${requestScope.inner_c}" escapeXml="true" />

In case, if you specify the attribute var Reader, insert the result page does not will be displayed or placed in a string variable var, and will be available only when reading the flow varReader.

One of the most frequently used methods of assembling the pieces of a page is redirecting to another URL to use this tag redirect.

<c:redirect url="heading.HTML">
    <c:param name="fio" value="${helloMachine.fio}" />
</c:redirect>

Param tag can be used when introducing the page in "subpage":

<c:import url="heading.JSP" charEncoding="utf-8">
    <c:param name="fio" value="${helloMachine.fio}" />
</c:import>

Another little use tag is c:url, it serves to decorate some addresses:

<c:url value="/a3.JSP" />

The address will be inserted into the page, including the application context.

Tags for working with xml

First of all, we need to connect the the following tag library to the header of jsp page:

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

In all the following examples we will need a xml-file, so the code:

<?xml version="1.0" encoding="utf-8"?>
<bookshelf>
    <book id="12">
        <title>Книга про зайцев</title>
        <description><![CDATA[Книга &amp;copy;рассказывает про суровую
 судьбу молодой семьи зайцев, живущих в самый разгар ...]]></description>
        <price>99.95</price>
        <authors>
            <author main="true">Тапкин Василий Васильевич</author>
            <author>Пупкина Ленка Ленковна</author>
        </authors>
    </book>
    <book id="13">
        <title>Слоны-людоеды</title>
        <description><![CDATA[Книга создана по материалам расследования серии
 жестоких убийств в местном зоопарке]]></description>
        <price>29.95</price>
        <authors>
            <author main="true">Слоноглазов Глеб Гамбитович</author>
            <author>Слоноухова Виктория Мракобесовна</author>
        </authors>
    </book>
</bookshelf>

Prior to working with xml it should be parsed, this is done either directly in jsp-file or similar work can be performed within java backend-code. Parsing is performed by means of the tag x:parse, for example:

<x:parse var="bookshelf">
<?xml version="1.0" encoding="utf-8"?>
<bookshelf>
    <book id="12">
        <title>Книга про зайцев</title>
        <description><![CDATA[Книга &amp;copy;рассказывает про суровую судьбу
 молодой семьи зайцев, живущих в самый разгар ...]]></description>
        <price>99.95</price>
        <authors>
            <author main="true">Тапкин Василий Васильевич</author>
            <author>Пупкина Ленка Ленковна</author>
        </authors>
    </book>
    <book id="13">
        <title>Слоны-людоеды</title>
        <description><![CDATA[Книга создана по материалам расследования
 серии жестоких убийств в местном зоопарке]]></description>
        <price>29.95</price>
        <authors>
            <author main="true">Слоноглазов Глеб Гамбитович</author>
            <author>Слоноухова Виктория Мракобесовна</author>
        </authors>
    </book>
</bookshelf> 
</x:parse>
<x:parse var="bookshelf2" xml="${helloMachine.bookshelfAsString}"  />

In the first case, all the code is inside the xml tag parse. The second option suggests that a part of the class HelloMachineBean should be a new method (for unreal property) that reads from the disk given earlier xml-document, and returns it to jstl-code in the form of a normal line.

public String getBookshelfAsString() {
   try {
      BufferedReader brin = new BufferedReader(
            new InputStreamReader(getClass().getResourceAsStream("/testi/templates/book.xml")));
      StringBuffer buf = new StringBuffer();
      String line;
      while ((line = brin.readLine()) != null)
         buf.append(line);
      return buf.toString();
   } catch (IOException e) {
      e.printStackTrace();
      return null;
   }
}

Let's try to do something with this xml-file. In the simplest case it is necessary to display any information. We need a tag that works with Xpath - x: out, as a parameter for it indicates a select attribute with expression like: Where to look / What to look for Where to look for - a java-variable refers to the xml-tree, its name can be a bookshelf (see. previous example) or contain the name of the context, for example:

pageScope:bookshelf.

Here is an example to select different parts of the xml-document:

<x:parse var="bookshelf">
    <c:import url="book.xml" charEncoding="utf-8" />
</x:parse>

all book content:<x:out select="$bookshelf/bookshelf/book[1]" escapeXml="false"/>
id:<x:out select="$bookshelf/bookshelf/book[1]/@id" />
title:<x:out select="$bookshelf/bookshelf/book[1]/title" />
qty authors:<x:out select="count($bookshelf/bookshelf/book[1]/authors/author)" />

Attribute escapeXML used for escaping. There is a problem: if the xml-document to add a namespace, for example:

<bookshelf xmlns="http://books.com/buki">

So previous code will not run. The solution will be an expression based on short (local) tag names:

all book content:<x:out select="$bookshelf/*[name()='bookshelf']/*[name()='book'][1]" escapeXml="false"/>

id:<x:out select="$bookshelf/*[name()='bookshelf']/*[name()='book'][1]/@id" />
title:<x:out select="$bookshelf/*[name()='bookshelf']/*[name()='book'][1]/*[name()='title']" />
qty authors:<x:out select="count($bookshelf/*[name()='bookshelf']/*[name()='book'][1]/*[name()='authors']/*[name()='author'])" />

When recording complex xpath-expression you can refer to variables declared in jstl, for example, further I want to find a book in the list, the number of which was referred to as an input parameter to the script:

book title by bid: <x:out select="$bookshelf/bookshelf/book[@id = $param:bid]/title" />

Let us turn to the tag x:set. It is very similar to the x: out, but not displays some xpath-part of the input document, and assigns its value to jstl-variable to later process a document agean using the x:out:

<x:set var="bookTitle" select="$bookshelf/bookshelf/book[1]/title" />
book title = <x:out select="$bookTitle/." />

The standard of the jstl have tag forEach, working with lists and arrays. Part jstl, dedicated to xml, have the same name and very similar in the parameters tag forEach. Example of the double-loop:

<x:forEach select="$bookshelf/bookshelf/book" var="book">
    <h1>
        <x:out select="$book/title" />
    </h1>
    <ul>
        <x:forEach select="$book/authors/author" var="author">
            <li>
                <x:out select="$author" />
            </li>
        </x:forEach>
    </ul>
</x:forEach>

To work with the conditions there are two tags: if and choose, similar to those described earlier. Here is an example, for each book, the message "two or more authors" is shown if the book has more than one author:

<x:forEach select="$bookshelf/bookshelf/book" var="book">
    <h1>
        <x:out select="$book/title" />
    </h1>
    <x:if select="count($book/authors/author) >= 2">
        two or more authors
    </x:if>
</x:forEach>

The tag x:fi has optional attributes (var and scope), allowing you to save test conditions in some variable for later reuse. The following example shows the reception when in the condition we can access the variables received as parameters form:

<x:if select="$bookshelf/bookshelf/book[@id = $param:bid]" var="xxx" />

Now we will consider how to work with two or more branches of computing:

<x:forEach select="$bookshelf/bookshelf/book" var="book">
    <h1>
        <x:out select="$book/title" />
    </h1>
    <x:choose>
        <x:when select="count($book/authors/author) = 0">
            The book has no author at all.
        </x:when>
        <x:when select="count($book/authors/author) = 1">
            Only one author
        </x:when>
        <x:otherwise>
            The number of authors is unknown, but is definitely more than one
        </x:otherwise>
    </x:choose>
</x:forEach>

Consider the tag x:transform. It is designed to perform a transformation xslt-xml-document using the xsl-document to another xml or html-document. For example, create a small xsl-file:

transbook.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>    <xsl:template match="/">
        <xsl:for-each select="bookshelf/book">
            <h1>
                <xsl:value-of select="title" disable-output-escaping="yes" />
            </h1>
            <ul>
                <xsl:for-each select="authors/author">
                    <li>
                        <xsl:value-of select="." disable-output-escaping="yes" />
                    </li>
                </xsl:for-each>
            </ul>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

For further example, you need to make sure that the lib folder of web application has a library xerces. The transform tag has two required attributes: xml - contains the input data for transformation, and xslt - sets the rules for the implementation of transformation. Input parameters xslt - is a line of text.

<c:set var="bookshelf">
    <c:import url="book.xml" charEncoding="utf-8" />
</c:set><c:set var="transbook">
    <c:import url="transbook.xsl" charEncoding="utf-8" />
</c:set><x:transform xml="${bookshelf}" xslt="${transbook}" />

SQL в JSTL

It should be noted that the imposition of the logic of the database in JSP - very bad practice, but this feature is supported.

To use all the tags shown below is necessary to connect to the jsp-file following tag library:

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

Create a table in the database for the following examples:

CREATE TABLE `tm_user` (
  `UserID` int(11) NOT NULL AUTO_INCREMENT,
  `UserName` varchar(100) DEFAULT NULL,
  `BirthDate` datetime DEFAULT NULL,
  `Sex` enum('male','female') DEFAULT NULL,
  `Comment` text,
  PRIMARY KEY (`UserID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Fill it:

INSERT INTO `tm_user` (username, birthdate, sex, comment) VALUES
  ('Jim Tapkin', '2006.1.1', 'male', 'bla-bla-bla'),
  ('Ron Baskerville', '2002.7.5', 'male', 'be-be-be'),
  ('Lenka Slonova', '2009.4.1', 'female', 'wow-wow-wow')

Access to the connection can be made either by using JNDI connections, or within the jstl-file you must declare connection object. In the first case, you must have the file META-INF/context.xml (for Tomacat):

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/">
    <Resource name="jdbc/VeloDemoDS" auth="Container" type="javax.sql.DataSource"
              username="jim"
              password=""
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://center/obmachine_t?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=UTF8"
            />
</Context>

The JSTL code necessary to turn to the JNDI and get the connection to the above resource. Then you need to put this object in any scope (eg, pageContext). Now you can try to run a query using one of two tags: query or update. Text query can be specified directly as a body tag query, or attribute value sql.

<%
    InitialContext co = new InitialContext();
    pageContext.setAttribute("ds_jndi", co.lookup("java:comp/env/jdbc/VeloDemoDS"));
%>
<body><sql:query var="users" dataSource="${ds_jndi}">
    select * from tm_user
</sql:query><c:forEach items="${users.rows}" var="row">
    <c:out value="${row.UserName}"/>
</c:forEach>
It can be even shorter: here inside attribute dataSource tag sends a query to the database indicated a JNDI-address:
<sql:query var="users"  dataSource="jdbc/VeloDemoDS">
    select * from tm_user
</sql:query>
If to write a JNDI-address each query inconvenient (or you do not want to insert into the top of the page code extracting from the Context JNDI connection), you can do so:

<syntaxhighlight lang="html5">
<sql:setDataSource dataSource="jdbc/VeloDemoDS" var="velo_simple"/><sql:query var="users" dataSource="${velo_simple}">
    select * from tm_user
</sql:query>

As a result, there was a query variable users. This variable acts as a container for a plurality of variables (or fields) containing the detailed information that was received from the server.

  • rows is a list of the type HashMap <String, Object>, in which the key role played by the field name and value is the value of the field
  • rowsByIndex - a list of arrays; each array is a separate entry in the table, but access to the fields do not need to specify the name of the field and a sequence number (starting from 1)
  • columnNames - a list of field names

For example, you can print the names of all selected fields:

<c:forEach items="${users.columnNames}" var="col">
    <c:out value="${col}"/>
</c:forEach>
  • rowCount - the number of selected rows.
  • limitedByMaxRows - a sign that the number of selected records has been limited

Tag query has some additional attributes:

  • scope - the context in which to put a variable with the result of the selection of the data;
  • Attributes maxRows startRow and serve to limit the sample

You can create parametric queries. To do this, apart from the inside of the tag query query text must be placed with param elements. Each has a value attribute, which will be inserted into the text of the request (be careful with the order of the parameters).

<sql:query var="users" dataSource="${ds_jndi}">
    select * from tm_user where UserID between ? and ?
    <sql:param value="${param.minID}" />
    <sql:param value="${param.maxID}" />
</sql:query>

There subspecies tag param - date Param. It is recommended to apply in cases where the field, which is inserted into the text of the query is of type date / time:

<sql:query var="users" dataSource="${ds_jndi}">
    select * from tm_user where BirthDate = ?
   <sql:dateParam value="${date}"/>
</sql:query>

The second kind of queries - to update the data - done by a tag update, the rules for its use are identical to the above for the query (you need to specify the data source, the query text, you can use the parameters), but the variable "var" is contains not fetched records and the number of records that have been modified.

<sql:update var="qtyInsterted" dataSource="${ds_jndi}">
    insert into `tm_user` (username, birthdate, sex, comment) values
      ('Jim Tapkin', '2006.1.1', 'male', 'bla-bla-bla'),
      ('Ron Baskerville', '2002.7.5', 'male', 'be-be-be'),
      ('Lenka Slonova', '2009.4.1', 'female', 'wow-wow-wow')
</sql:update>count affected records = <c:out value="${qtyInsterted}" />

The jstl has support for working with transactions. The transaction represented by the tag "transaction". Its attributes are the data source for which the transaction is initiated, and the level of insulation (isolation).

<sql:transaction dataSource="${ds_jndi}">
    <sql:update>
        delete from tm_user
    </sql:update>
    <sql:update>
        delee adfs adasd
    </sql:update>
</sql:transaction>

The second command within a transaction, obviously, should lead to an error - an exception is thrown. Visually, the screen will render the text of the error message and executing of further jstl code is interrupted. Methods of processing exceptions in jstl is trivial. If an exception did not occur inside the catch, the generation of the page is interrupted. If potentially dangerous activity were within the catch, when the exception is generated and its object is placed into the variable specified by the attribute var. Then you need to check what is the variable. If it is not null, then an error occurred.

<c:catch var="e_sql">
    <sql:transaction dataSource="${ds_jndi}">
        <sql:update>
            delete from tm_user
        </sql:update>
        <sql:update>
            delee adfs adasd
        </sql:update>    </sql:transaction>
</c:catch><c:if test="${e_sql != null}">
    error occurred: <c:out value="${e_sql}"/>
</c:if>

The second way to configure the connection to the database - specify explicitly in jstl code the driver and access credentials:

<sql:setDataSource driver="com.mysql.jdbc.Driver" user="jim" password=""
   url="jdbc:mysql://center/obmachine_t?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=UTF8"
   var="velo_local" scope="application"
/>

We now have a connection object, and it can be used as well as the previously obtained from jndi.

Formatting and localization

The jstl includes a set of tags for creating localized applications: representation of dates and numbers in accordance with certain regional settings and tools to download text resources from the

ResourceBoundle. Let's start with the connection tag library fmt:

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

The most frequently used tag in this library is requestEncoding - set the encoding of the input data to the Web server correctly made their decoding:

<fmt:requestEncoding value="utf-8" />

Two tags are requred to work with dates: formatDate (converts the date to a string) and parseDate (object Date constructed on the basis of string). The only required attribute is the value - a value date that you want to format. If you do not specify an attribute value var, then the formatted result will be displayed instead of setting the intermediate variable. Pattern attribute specifies the format string.

<jsp:useBean id="beanNow" class="java.util.Date" />
<fmt:formatDate value="${beanNow}" var="s_now" pattern="yyyy.MMM.dd hh:mm:ss" />
<c:out value="${s_now}" />

Below is an example of reverse conversion from string to date:

<fmt:parseDate pattern="dd.MM.yyyy" value="12.04.2001" />

You can adjust the formatting / parsing by use of attribute timeZone and parseLocal (tag parseDate). You can also place the formatting operation inside the tag timeZone, then formatting will be carried out according to certain rules:

<fmt:timeZone value="Europe/Minsk">
     <fmt:formatDate value="${beanNow}" pattern="yyyy.MMM.dd hh:mm:ss" />
</fmt:timeZone><fmt:timeZone value="Antarctica/Casey">
    <fmt:formatDate value="${beanNow}" pattern="yyyy.MMM.dd hh:mm:ss" />
</fmt:timeZone>

You can use the tag setLocale to change the locale, for example:

<fmt:setLocale value="ja_JP"/>
<fmt:formatDate value="${beanNow}" pattern="yyyy.MMM.dd hh:mm:ss" />

To work with the numbers using two tags: formatNumber и parseNumber: Сначала из числа в строку:

<fmt:formatNumber pattern="#,##0.0#" value="234234.23423" />

And now the opposite:

<fmt:parseNumber value="234,234.23" pattern="#,##0.0#" />

To work with localized messaging two tags are used: setBundle and message. The first one loads the Resource Bundle, the second - displays messages based on the Resource Bundle. At the message tag must be specified attribute key - the name of the property that stores the message in the appropriate language. If no attribute var specified, then the message will be displayed immediately, otherwise the message will be placed in an intermediate variable.

<fmt:setBundle basename="testi.messages" var="loc" /><fmt:message bundle="${loc}" key="MSG_1" /><fmt:message bundle="${loc}" key="MSG_2"  var="m_2"/>
<c:out value="${m_2}" />

Funtions

Consider the functions that can be used when recording jstl-expressions. Connect:

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

Lets start to understand the functions. The first of these "fn: contains" (the names of all functions must be preceded by the prefix "fn:" - that is what we hooked up at the beginning of jsp-file). contains is used to verify that the string is contained within another substring.

<c:set value="boy goes to school" var="boy" /><c:if test="${fn:contains(boy, 'goes')}">
    <h1>
        He goes to School. Realy.
    </h1>
</c:if>

If you need to check the condition case-insensitive, then use the containsIgnoreCase:

<c:if test="${fn:containsIgnoreCase(boy, 'GOES')}">
    <h1>
        He goes to School. Realy.
    </h1>
</c:if>

To check whether a certain string begins with a given substring, use startsWith, ends - endsWith:

<c:if test="${fn:startsWith(boy, 'boy')}">
    <h1>
        Starts from BOY
    </h1>
</c:if><c:if test="${fn:endsWith(boy, 'school')}">
    <h1>
        Ends with SCHOOL
    </h1>
</c:if>

For the escaping escapeXml function can be used (do not forget that in the c:out there is an attribute that provides similar functionality):

<c:set value="boy goes &amp;copy; to school" var="boy" />
<c:out value="${boy}" />
<c:out value="${fn:escapeXml(boy)}" />
<c:out value="${boy}" escapeXml="true" />

For the analysis of the line is a set of functions. The position from which to start another line:

<c:set value="boy goes to school" var="boy" />
<c:out value="${fn:indexOf(boy, 'to' )}" />

Cut out of the initial part of the string, starting with the first entry "to":

<c:set value="boy goes to school" var="boy" />
<c:out value="${fn:substring(boy, fn:indexOf(boy, 'to' ), 100)}" />

The third parameter is a number - up to which character you need to cut a piece. In this example, only two characters are cut from the string:

<c:out value="${fn:substring(boy, fn:indexOf(boy, 'to' ), fn:indexOf(boy, 'to' )+2)}" />

In order to cut a piece of string to a position before the end, you can specify any negative number as the last parameter of the function:

<c:out value="${fn:substring(boy, fn:indexOf(boy, 'to' ), -1)}" />

length – universal function and is able to consider not only the length of the line, but an arbitrary collection:

<sql:query var="users"  dataSource="jdbc/VeloDemoDS">
    select * from tm_user
</sql:query><c:set value="boy goes to school" var="boy" />

Sample line length:

<c:out value="${fn:length(boy)}" />

Calculate length of list of records (how many records have been selected from the table):

<c:out value="${fn:length(users.rows)}" />

substringAfter и substringBefore:

<c:set value="boy goes to school" var="boy" />
After:<c:out value="${fn:substringAfter(boy, 'to')}" />
Before:<c:out value="${fn:substringBefore(boy, 'to')}" />

Convert to upper case and lower case could be performed by the functions toLowerCase и toUpperCase:

<c:set value="boy goes to school" var="boy" />
<c:out value="${fn:toLowerCase(boy)}" />
<c:out value="${fn:toUpperCase(boy)}" />

To remove whitespace characters placed at both ends of the line use trim:

<c:set value="  boy goes to school   " var="boy" />
<h1><c:out value="${fn:trim(boy)}"/></h1>

To replace a symbol in the line to the other, use the function replace:

<c:set value="boy goes to school" var="boy" />
<c:out value="${fn:replace(boy, 'school', 'bar')}"/>

split и join divide and join lines:

<c:set value="1,2,3,4" var="str_digits" /><c:set value="${fn:split(str_digits, ',')}" var="arr_digits" />
<c:set value="${fn:join(arr_digits, '!')}"  var="str2_digits"/>

References