JSP

Goals

Concepts

Library

Dependencies

Preview

<%-- About page written in JSP. --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ page import="java.time.Year" %>
<!DOCTYPE html>
<html lang="en-US">
<head>
  <meta charset="UTF-8"/>
  <title>About Acme Company</title>
</head>
<body>
  <h1>About Acme Company</h1>
  <p>In business for ${Year.now().value - 2000} years!</p>
</body>
</html>

Preparation

You will need a servlet/JSP container, such as Tomcat.

Lesson

With the web technology learned this far in the course, you can make sites that are viewable, but their content is completely static. The information shown in the pages is exactly that shown in the source code. Static sites do not allow any variation; what one user sees is what all users see.

Server-Side Dynamic Sites

While a simple static site is useful for “landing page” provide information about a project, web applications need to process information and present different content based upon inputs. A static site is limited even for simple lists. It would be possible to create a site for a vehicle database listing, if the vehicle lists were hard-coded into the HTML source code. But every time the database were updated, the site would need to be regenerated, and even simple queries would be unmanageable because all vehicles would always be included in the list.

For user interaction the site needs to be dynamic in some way. There are two approaches to making a dynamic site, and they can work together. The oldest approach is server-side dynamic, in which the server actually modifies the content or even generates it from scratch when the user requests it. The other approach is client-side dynamic, in which logic in the browser interacts with the user and updates the page as needed after it is loaded. These approaches are by no means mutually-exclusive. It is entirely possible for the server to modify the content before sending it to the user, but program pages to modify themselves as well when needed. This lesson introduced server-side dynamic sites. Client-side dynamic sites will be presented in a future lesson.

Servlets

As an example of dynamic content, suppose you wish to include the sentence, “In business for 10 years!” in the “About” page of your company. There is a problem with even this simple phrase: with each year that passes, your company will have been in business another year. The page will become outdated if no one remembers to update it.

Let's assume that your company was created in the year 2000. Thinking back to the lesson on servlets, you might come up with the idea to make a servlet that generates the entire HTML page when invoked. You would merely need to map the servlet to the expected HTML file name. Instead of providing a static HTML file, the servlet would generate everything that the original file included, calculating and inserting the number of years in business.

Generating an About page using a servlet mapped to about.html.
@WebServlet("/about.html")
public class AboutServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html");
    response.setCharacterEncoding(StandardCharsets.UTF_8.name());
    response.getWriter().println("<!DOCTYPE html>");
    response.getWriter().println("<html lang=\"en-US\">");
    response.getWriter().println("<head>");
    response.getWriter().println("  <meta charset=\"UTF-8\"/>");
    response.getWriter().println("  <title>About Acme Company</title>");
    response.getWriter().println("<head>");
    response.getWriter().println("<body>");
    response.getWriter().println("  <p>In business for ");
    response.getWriter().println(Year.now().getValue() - 2000);
    response.getWriter().println("  years!</p>");
    response.getWriter().println("</body>");
    response.getWriter().println("</html>");
  }

}

As far as the browser knows or cares, the HTML file it received was a static about.html file stored on the server. In reality the server completely generates the entire page for each request; the complete about.html contents never exists in a static file at any time. There is one small difference: the server would likely send HTML headers to allow a static about.html file to be cached, while the servlet version would likely indicate that the browser should not assume that the content is unchanged, and instead request the content from the server rather than relying on a cached local version.

JavaServer Pages

About the only downside to this approach is that it is unwieldy. Encoding a page as a servlet seems unnatural, and HTML tools are not tuned to think of HTML pages as a series of  response.getWriter().println() statements. JavaServer Pages (JSP) is a server-side dynamic technology that takes a static HTML template file and automatically creates a servlet to generate its contents.

Because JSP is part of Java EE, you can include the equivalent of the above servlet simply by including the file about.jsp shown below. The file has the same format as the HTML file the browser expects to receive, except for the delimiters <% and %> which contain special information for JSP template processing. The file would be placed in src/main/webapp in a standard Maven web application project.

Generating an About page using a JSP file about.jsp.
<%-- About page written in JSP. --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ page import="java.time.Year" %>
<!DOCTYPE html>
<html lang="en-US">
<head>
  <meta charset="UTF-8"/>
  <title>About Acme Company</title>
</head>
<body>
  <h1>About Acme Company</h1>
  <p>In business for ${Year.now().value - 2000} years!</p>
</body>
</html>

Whenever a file with the jsp extension is requested, the Java EE container will compile the JSP source file and generate a servlet virtually identical to the one presented earlier in this lesson. After that the container will continue to use the servlet, unless that original source file changed. Using JSP is just as efficient as using a servlet—with the small overhead of the initial request, which compiles the JSP source code to produce the servlet.

Imports

Before using Java classes in your page, you must import the classes just as you would in a Java program. Use the import page directive. As you saw earlier, to include the java.time.Year class use  <%@ page import="java.time.Year" %>. You can use wildcard imports, too, such as java.time.*.

Scripting Elements

The power of intermingling Java code with user presentation data in JSP is obvious. But mixing program logic and presentation is difficult to maintain. You've already seen how the concept of separation of concerns leads us to separating a program into layers and modules, each with its own responsibility. Rather than integrating entire scripts into your JSP, restrict yourself to JSP tags and JavaBeans that encapsulate logic, and connect them using simple expressions. These concepts will be explained later in the lesson.

Scriptlets

Unfortunately when JavaServer Pages were first introduced, people abused the framework's power by essentially including entire sections of program code in a JSP. The JSP feature that most promoted this is the scriptlet. Between a scriptlet's delimiters of <% and %>, any Java code at all can be included. Printing out the number of years a company has been in business, from the above example, could be done entirely in a scriptlet.

Abusing a scriptlet to calculate and generate content.
…
<body>
<%
  final Year currentYear = Year.now();
  final int yearsInBusiness = currentYear.getValue() - 2000; 
  response.getWriter().println("  <p>In business for ");
  response.getWriter().println(yearsInBusiness);
  response.getWriter().println("  years!</p>");
%>
</body>
</html>

Scriptlets allow variable declarations, calculations, method calls—just about anything! You can see that JSP even provides the HttpServletResponse for you to use, already assigned to the variable response. But this is difficult to understand and even harder to maintain. Do not include Java code in scriptlets unless absolutely necessary.

Script Expressions

An expression element uses the <%= and %> delimiters. Between them they output the result of some calculation. It is similar to the ${Year.now().value - 2000} provided in the example above, except that only a valid Java expression may be used. The equivalent to the above example using an expression element would be <%= Year.now().getValue() - 2000 %>. The difference in form will be explained below under Expression Language. Expression directives are no longer recommended; use options such as such as <c:out> instead.

Script Declarations

A declaration directive takes the form <%! … %> allows you to declare a variable or a function in your JSP, such as allowing declarations such as <%! int x; %> or <%! int x=5; %>. A declaration contains Java code that is used as if it were in the source code of the servlet. Thus it is really a lighter version of a scriptlet, and likewise not recommended. Do not use declarations; many options such as <c:set> are more appropriate.

Expression Language

The original JSP specification included <%= … %> expression elements which use normal Java expressions as would appear in a Java program. Later versions introduced a completely new Expression Language (EL) to simplify expressions and facilitate access to data. An EL expression is always included with ${…} delimiters and may appear both in HTML markup (such as an attribute value) or in child text content as you saw in the first JSP examples.

EL allow most of the same operators of Java expressions, including the ternary operator, along with some additional features. Most prominently, in addition to the customary operator symbols, EL provides many word synonyms: div (/), mod (%), eq (==), ne (!=), lt (<), le (<=), gt (>), gte (>=), and (&&), or (||), not (!). The word forms are useful because they do not require XML/HTML escaping, as would be required with e.g. &&.

Objects

The initial example showed how to create a new object on the fly in an expression using Year.now(). JSP's use of objects is more powerful then this, however. There are some objects available in all JSP pages, ready for you to use. You can even create your objects that can be reused on the page or even across multiple pages.

Implicit Objects

Every page provides several implicit objects, variables already defined and initialized. You already saw how that if we create a servlet, the doGet(HttpServletRequest request, HttpServletResponse response) method for example already provides request and response variables. JSP, built on top of servlets, is no different, and provides additional implicit objects that are available to an embedded scriptlet, including out, the writer generating the page output!

As discussed earlier scriptlets should not be used in modern JSP code. JSP thus provides a separate set of implicit objects that you can use in EL expressions, allowing access to much of the same information. The following variables are already ready for you to use in EL expressions in any JSP. EL does not allow access to the actual request and response objects, but these are available via the pageContext object.

pageContext
The page context for the JSP; an instance of javax.servlet.jsp.PageContext, giving access to all sorts of information about the page itself. The pageContext object provides access to the underlying servlet environment, including implicit objects exposed directly to scriptlets.
PageContext.getPage()
Returns the servlet itself.
PageContext.getRequest()
Returns the initial client request invoking the page; an instance of javax.servlet.ServletRequest. On web pages the object is usually of a subtype of javax.servlet.http.HttpServletRequest.
PageContext.getResponse()
Returns the response to the request; an instance of javax.servlet.ServletResponse. On web pages the object is usually of a subtype of javax.servlet.http.HttpServletResponse.
PageContext.getServletConfig()
The servlet configuration; an instance of javax.servlet.ServletConfig.
PageContext.getServletContext()
The servlet context; an instance of javax.servlet.ServletContext.
PageContext.getSession()
An object keeping track of several related requests (see side note); an instance of javax.servlet.http.HttpSession.
pageScope
A map of all page-scoped attributes for lookup by name.
requestScope
A map of all request-scoped attributes for lookup by name.
sessionScope
A map of all session-scoped attributes for lookup by name.
applicationScope
A map of all application-scoped attributes for lookup by name.
param
A map of single String values corresponding to request parameters by name. If a parameter might have multiple values, use paramValues instead.
paramValues
A map of String[] arrays containing all values for each parameter name.
header
A map of single String values corresponding to headers by name. If a header might have multiple values, use headerValues instead.
headerValues
A map of String[] arrays containing all values for each header name.
cookie
A map of javax.servlet.http.Cookie objects by name. Cookies allow amounts of information to be stored on the browser, often used with session tracking. Cookies and session tracking are advanced topics for a future lesson.
initParam
A map of initialization parameter names, set using the javax.servlet.annotation.WebServlet annotation on the servlet or in the web.xml file.

Scope

You'll remember that in Java a variable lives until the end of its scope, which is usually a closing curly bracket. JSP has several predefined scopes that demarcate the lifetime of objects. These scopes are defined in terms of the JSP life cycle, not in terms of source code brackets. Some scopes live longer than others, so it's important to know which objects are in which scopes.

In addition to implicit objects, you can create your own objects, called attributes, to be used later. When you define an attribute, you not only give it a name (similar to a variable name), you also indicate in which scope it should be stored. Each scope has a separate map of attributes, each keyed to its name. (This is similar to how the JVM keeps track of Java variables during program execution.) When a scope ends, the scope's map of attributes goes away, along with any other implicit objects associated with that scope.

page scope
The page scope manages all the objects created during a single user access of the page. After JSP finishes processing the page and sends the response back to the client, the page scope goes away. There is an implicit object pageScope which is is a map of all attributes in the page scope, with attribute names as the keys.
request scope
As you see later, a single user request may span multiple pages and/or invoke other servlets. The request scope is available to all pages/servlets interacting in a single user request, and goes away when the request is finished. The implicit object requestScope is a map of request scope attributes.
session scope
Even though HTTP is stateless (with each request independent of all others), JSP and all Java servlet-based technologies have the ability to recognize multiple requests from the same user. Java keeps track of these related requests through a session, which will be discussed further in a future lesson. If an attribute is associated with session scope, it will be available across requests until the session ends. Not every page is associated with a session; some pages may disable sessions, or the user's browser may not join the session. Session scope attributes are stored in the implicit object sessionScope.
application scope
Attributes in the application scope are accessible by all pages in the web application, even those not part of sessions, and remain available until the application ends. The implicit object applicationScope is a map providing access to the application scope attributes.

Resolution

EL is extremely helpful in locating variables in the various scopes, a process called resolution. If you provide a reference to some variable such as ${fooBar}, JSP will search for an attribute named fooBar in the various scopes. The search starts at the most specific scope: first the page scope, and then each intermediate scope until finally the application scope. The first attribute found is used; if no such attribute is found, null is used.

JavaBeans

While it's nice to be able to use expressions to display data, your page still needs a way to connect back to your application to get data. The JSP approach is through JavaBeans which you can instantiate and access when the page is being evaluated. You'll remember that a JavaBean is really no different than a normal Java object, except that follows several conventions: it has a no-arguments constructor and uses getters and setters to access data. You can create any JavaBean class you want for your application, and JSP can instantiate it and access its data. It's even possible to use objects that aren't technically JavaBeans, as long as you create them at the right time and put them in the correct scope, as you'll see in future lessons.

In addition to directives and scripting elements, a third type of JSP element is classified as an action. This type of element may change the output stream or modify objects. The JSP action for accessing a JavaBean is jsp:useBean, and it is embedded in a page as if it were an XML/HTML element. The general syntax is <jsp:useBean id="beanVar" class="com.example.BeanClass"/>, where com.example.BeanClass is the full name of the JavaBean class to instantiate, and beanVar is the name of the variable you want to assign it to.

The above calculation of the number of years in business of Acme Company, though simple, could itself be placed in a JavaBean to localize business logic. You could create a BusinessBean that knows when the business was established and that can automatically calculate the number of years in business. You could update the about.jsp page to use this bean. Note the EL allows the getter to be accessed as a property using acme.yearsInBusiness.

Putting business logic in a JavaBean.
package com.example.acme;

import java.time.Year;

public class BusinessBean {

  public static final Year YEAR_ESTABLISHED = Year.of(2000);

  /** @return The number of years since {@link #YEAR_ESTABLISHED}. */
  public int getYearsInBusiness() {
    return Year.now().getValue() - YEAR_ESTABLISHED.getValue();
  }

}
<%-- about.jsp --%>
…
<jsp:useBean id="acme" class="com.example.acme.BusinessBean" />
…
<body>
  <p>In business for ${acme.yearsInBusiness} years!</p>
</body>
…

Scope

Setting the scope of a bean.
…
<jsp:useBean id="acme" class="com.example.acme.BusinessBean" scope="application" />
…

By default a new JavaBean is placed in page scope, but you can add a scope attribute to indicate a different scope. When JSP creates a bean using <jsp:useBean> it first checks to see if an attribute with that name already exists in that scope. If so, that value is used; if not, a new one is created. This mechanism allows you to place an object in a long-lived scope and refer the same instance repeatedly across requests. You could modify the above example to only create one BusinessBean instance, stored in an attribute named acme, created once for the life of the entire application.

Setting Properties

An InventoryBean with a setter that filters output.
/* InventoryBean.java */
package com.example.warehouse;
…
/**
 * A JavaBean that functions as a query builder
 * for listing items in inventory.
 */
public class InventoryBean {

  /** The max stock filter, or <code>-1</code> for no filtering. */
  private int maxStock = -1;

  /**
   * Sets maximum low-stock filter for querying low stock.
   * @param maxStock The cutoff limit for low stock.
   */
  public void setMaxStock(final int maxStock) {
    this.maxStock = maxStock;
  }

  /** @return The items in the inventory, filtered as requested. */
  public List<ItemStock> getItems() {
    //TODO load from some sort of repository in a real application
    Stream<ItemStock> inventory = Stream.of(new ItemStock("table", 20),
      new ItemStock("chair", 15), new ItemStock("balloon", 99),
      new ItemStock("kite", 5),  new ItemStock("doll", 10));
    if(maxStock > 0) { //filter if needed
      inventory = inventory.filter(
          item -> item.getStock() <= maxStock);
    }
    return inventory.collect(toList());
  }

}

JSP allows you to configure your JavaBean before retrieving values from it. With this approach, the bean acts as sort of like a query builder: setting one bean value provides some input or query parameter that affects later value retrieval from the bean's other properties.

Returning to the ongoing example of the store owner with furniture and toys, suppose you created an InventoryBean to query the stock of items from the warehouse database. By default the bean would return all items using its getItems() getter method. In addition it would provide a setMaxStock(int maxStock) setter that would indicate the items should be filtered by stock, so that only items low on stock could be listed, for example. The example shows hard-coded items; in real life it would be better to look them up from a database or a general repository.

A value class ItemStock to encapsulate an item and its stock.
/* ItemStock.java value object */
package com.example.warehouse;
…
public class ItemStock {
  public String getName() {…}
  public int getStock() {…}

  //TODO add hashCode(), equals(), etc.

  @Override
  public String toString() {
    return getName();
  }
}
Setting Properties Manually

Setting a bean property in JSP is done using the jsp:setProperty action, which has two forms. The first form is for setting a value manually, using some expression, using the markup <jsp:setProperty name="beanVar", property="propertyName", value="newValue" />. Here beanVar is the variable you assigned to the bean when you created it using the jsp:useBean action. The newValue is some value or EL expression to assign to the named property, using the JavaBean's setter for that property.

Setting a JavaBean property manually.
<%-- inventory.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<jsp:useBean id="warehouse" class="com.example.warehouse.InventoryBean" />
<!DOCTYPE html>
<html lang="en-US">
<head>
  <meta charset="UTF-8" />
  <title>Warehouse Inventory</title>
</head>
<body>
  <h1>Warehouse Inventory</h1>
  <h2>All Items</h2>
  <p>${warehouse.items}</p>
  <h2>Low Inventory Items</h2>
  <jsp:setProperty name="warehouse" property="maxStock" value="15" />
  <p>${warehouse.items}</p>
</body>
</html>
Warehouse Inventory
All Items
[table, chair, balloon, kite, doll]
Low Inventory Items
[chair, kite, doll]

We want to call the InventoryBean.setMaxStock(int maxStock) method, which in JavaBean terms means settings its maxStock property. The example JSP below shows how the bean's items property returns different items after setting maximum stock to 15.

Using a literal to set a value is not the only option. You can set values using properties from other beans! Imagine that the BusinessBean introduced above has a getLowStockLevel() method to indicate when items should be restocked. You could use this value via an expression when setting the maximum stock of warehouse litems to list.

Setting a JavaBean manually using an expression.
public class BusinessBean {
  …
  /** @return The stock level indicating restocking is needed. */
  public int getLowStockLevel() {
    return 15; //TODO retrieve from business configuration
  }
}
<%-- inventory.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<jsp:useBean id="acme" class="com.example.acme.BusinessBean" />
<jsp:useBean id="warehouse" class="com.example.warehouse.InventoryBean" />
  …
  <h2>Low Inventory Items</h2>
  <jsp:setProperty name="warehouse" property="maxStock" value="${acme.lowStockLevel}" />
  <p>${warehouse.items}</p>
</body>
</html>
Setting Properties from URI Query Parameters

The other approach to setting bean properties is to use request parameters. So far we have been creating web pages, not RESTful services. But even an HTTP GET request to a single web page can include URL query parameters. Servlets and JSP detect query parameters and make them available via ServletRequest.getParameter(String name) and related methods. Instead of indicating a value, indicate a request parameter's value to use with the form <jsp:setProperty name="beanVar", property="propertyName", param="paramName" />, where paramName is the name of the request parameter to be read. If the request parameter is not present, the bean's property is not changed, allowing request parameters to be optional.

Setting a JavaBean property from a request parameter.
<%-- inventory.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<jsp:useBean id="warehouse" class="com.example.warehouse.InventoryBean" />
  …
  <h2>Low Inventory Items</h2>
  <%-- example: inventory.jsp?lowStockLevel=15 --%>
  <jsp:setProperty name="warehouse" property="maxStock" param="lowStockLevel" />
  <p>${warehouse.items}</p>
</body>
</html>

JSTL

Although JSP's JavaBean facility allows you to access application data and business logic, you sometimes need some sort of procedural logic when generating content, going beyond mere expression evaluation and substitution. One thing that makes JSTL particularly extensible is the ability to create a tag library, in which you can create your own action elements. This allows you to include logic in a declarative manner, making the semantics more apparent and isolating the code itself into the library.

You can include any tag library in your JSP with the taglib directive. It takes the general format <%@ taglib uri="http://example.com/jsp/mytaglib" prefix="my" %>, where http://example.com/jsp/mytaglib is the URI that uniquely identifies your tag library and my is the prefix to use to access the tag library actions within your JSP.

JSTL Tag Libraries
Tag Library URI Prefix
JSTL Core http://java.sun.com/jsp/jstl/core c
XML Processing http://java.sun.com/jsp/jstl/xml x
Internationalization http://java.sun.com/jsp/jstl/fmt fmt
SQL http://java.sun.com/jsp/jstl/sql sql
Functions http://java.sun.com/jsp/jstl/functions fn
Prefixes are those used by convention.

JSP already has a tag library, the JSP Standard Tag Library (JSTL), which provides common actions useful for manipulating and formatting display content. The JSTL actually consists of several tag libraries, shown in the figure. The most commonly used tag library is JSTL Core, conventionally using the prefix c.

Iteration with <c:forEach>

A real-world program usually needs some sort of iteration capability to display arbitrary collections of elements, like the inventory items above. Of course you could embed a Java loop using a scriptlet, but you've learned that it's best to keep business logic out of JSP pages. The solution is to use the the JSTL Core c:forEach action.

Using <c:forEach> to iterate over numbers.
<%-- numbers.jsp --%>
…
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
…
  <h2>Even Numbers</h2>
  <p><c:forEach var="num" begin="0" end="8" step="2">
    ${num}
  </c:forEach></p>
…
Even Numbers
0 2 4 6 8

There are two forms of this action. One form functions almost like a traditional for() loop, and take the form <c:forEach var="varName" begin="firstVal" end="lastVal" [step="stepVal"]>. In Java terms this is is much the same as using for(int varName = firstVal; varName < lastVal; varName += stepVal). If no stepVal is given, it defaults to 1. Within the action element content, you can then reference varName in EL expressions. The following shows how you could display the first five even numbers:

A more modern form of this action is <c:forEach var="varName" items="collection">. This form corresponds to Java's enhanced for() loop. It iterates over items in a collection, which can actually be an instance of any of the following types:

This form makes it easy to display the details of inventory items in a warehouse.

Using <c:forEach> to iterate over a collection.
<%-- inventory.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<jsp:useBean id="warehouse" class="com.example.warehouse.InventoryBean" />
…
  <h1>Warehouse Inventory</h1>
  <ul><c:forEach var="item" items="${warehouse.items}">
    <li>${fn:escapeXml(item.name)} (${item.stock})</li>
  </c:forEach></ul>
…
Warehouse Inventory
• table (20)
• chair (15)
• balloon (99)
…

Outputting Content with <c:out>

Escaping output using <c:out>.
<%-- inventory.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<jsp:useBean id="warehouse" class="com.example.warehouse.InventoryBean" />
…
  <h1>Warehouse Inventory</h1>
  <ul><c:forEach var="item" items="${warehouse.items}">
    <li><c:out value="${item.name}" /> (${item.stock})</li>
  </c:forEach></ul>
…

Printing the inventory using the above example will go well until one day you start stocking a new game with the name “Snakes & Ladders” or a gadget advertised “… <as seen on TV!>”. Characters such as & and < need to be escaped in XML and in HTML. If they are included directly without modification, they can corrupt the source document.

JSTL provides a tag <c:out value="value" [escapeXml="true|false"] [default="defaultValue"] /> for outputting values in your JSP. It works essentially the same as including a value directly using ${…} except that by default <c:out> escapes XML content, which is essential to making your page robust and secure. This means that you should always use <c:out> or fn:escapeXml() when including values in your page.

The <c:out> tag also allows you to specify a default value if the given value is null. You can provide the default value in the defaultValue attribute, or include the default value in the body of the element, such as <c:out value="${foo.bar}">No foobar was found.</c:out>.

Setting a Value with <c:set>

You already know how to set JavaBean properties using <jsp:setProperty>. The JSTL <c:set> tag provides the same functionality, and has variations to set even general variables in various scopes. The syntax for setting the property of an object, duplicatint the functionality of <jsp:setProperty>, is <c:set value="value" target="target", property="propertyName" />. So instead of <jsp:setProperty name="warehouse" property="maxStock" value="15" /> in one of the above examples, you could use <c:set target="${warehouse}" property="maxStock" value="15" />. Note that you must indicate the target using EL.

The other form is <c:set value="value" var="varName" [scope="page|request|session|application"] />, which lets you set an arbitrary variable in any scope! By default the scope is page, so that <c:set var="foo" value="bar" /> will assign the string "bar" to the foo variable in page scope. Of course you can use EL in the value, so that <c:set var="foo" value="${bar}" /> assigns the value in the bar variable to foo.

Escaping XML with fn:escapeXml

EL expressions include their actual results directly into your page, with no forms of escaping. This means that if an expression contains HTML code it will be interpreted specially by the browser. If a value from the database were to contain < or & it could break your page. Still worse, if the values were entered by a user, a malicious user could even enter <script> codes that change how your program operates.

JSTL provides fn:escapeXml, which is an EL function rather than an action. It is meant to be used inside an EL expression, wrapped around the original expression the result of which is to be escaped. As in the example above, each item name ${item.name} can be escaped using ${fn:escapeXml(item.name)}, making your program more robust and secure.

Conditional Actions <c:if> and <c:choose>

Conditional evaluation using <c:if>.
<c:if test="${item.stock < 15}">
  Item ${fn:escapeXml(item.name)} has low stock.
</c:if>

JSTL allows you to make the processing of a section of JSP dependent on some condition. It takes the form <c:if test="testCondition" [scope="page|request|session|application"] /> and functions like if(…) in Java. If the testCondition is true, the body of the action is evaluated; otherwise it is ignored. There is another form of <c:if> that instead of a body provides a varName and exports the value of the test expression.

Conditional evaluation using <c:choose>.
<c:choose>
  <c:when test="${item.stock < 15}">
    Low stock.
  </c:when>
  <c:when test="${item.stock > 999}">
    We shouldn't run out anytime soon
  </c:when>
  <c:otherwise>
    Stock is normal.
  </c:otherwise>
</c:choose>

If an expression results in several mutually exclusive possibilities, you may want to use the <c:choose> action instead. Inside the action place one or more <c:when test="testCondition" /> actions, with an optional <c:otherwise> action for the default.

Together these work like the Java switch(…) statement. Unlike switch(…), which contains a value that is compared with case values, <c:choose> places the entire expression to be tested at the <c:when> level. In this way it is more similar to the searched case expression in SQL.

Linking with <c:url>

You're already comfortable using HTML links. If you wanted to show the inventory page with a low stock level of 15, you might include <a href="inventory.jsp?lowStockLevel=15">Show Inventory</a> in your page. If you want to dynamically include the stock level to be passed as as query parameter, you could use EL expressions such as <a href="inventory.jsp?lowStockLevel=${lowStockSetting}">Show Inventory</a>, assuming lowStockSetting (perhaps an application configuration setting or a value configured by the user) was stored in some scope.

JSTL provides a more comprehensive, if verbose, approach to forming links using the <c:url value="value" [var="varName"] [scope="page|request|session|application"] /> action. The syntax is similar to the <c:set> action, and <c:url> can store the resulting URL in a variable if varName is given. But <c:url> provides processing specific to URIs, and can add parameters using <c:param> actions, which have the same syntax as <jsp:param> actions. <c:url> and <c:param> will ensure that the included values are escaped and encoded as needed for HTML and for URI syntax.

If the given value is an absolute path, beginning with /, the URI is changed to be relative to the servlet/JSP context. Each <c:param> results in a query parameter being added to the URI. Finally extra query parameters are added if necessary to maintain information about the session. The resulting URI is output or stored in the indicated variable so that it may be used later.

Using <c:url> to form a hyperlink to another page.
<c:url value="inventory.jsp" var="inventoryUrl">
  <c:param name="lowStockLevel" value"${lowStockSetting}" />
</c:url>

<a href="${inventoryUrl}">Show Inventory</a>

Including Content

The more web pages you write, the more you will see certain elements repeated such as whether sidebars and menus Following the principle of Don't Repeat Yourself (DRY), JSP provides a few rudimentary ways to reduce redundancy by consolidating pieces of a page into a file and including that file in other pages. Two approaches correspond to two of the three types of JSP elements: directives and actions. A third approach uses JSTL.

The include Directive

Including content using the include directive.
<%-- about.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ page import="java.time.Year" %>
<!DOCTYPE html>
<html lang="en-US">
…
<body>
  <h1>About Acme Company</h1>
  <%@ include file="welcome.jspf">
  <p>In business for ${Year.now().value - 2000} years!</p>
</body>
</html>
<%-- welcome.jspf --%>
<%-- requires import of java.time.Year --%>
<p>Welcome to Acme!</p>
<p>We'll help you make ${Year.now()}
  the <em>best</em> year ever.</p>
About Acme Company
Welcome to Acme!
We'll help you make 2018 the best year ever.
In business for 18 years!

Directives provide information to the JSP compiler, as you've seen with the page directive for example. The include directive tells the compiler to insert the literal text of another file into the page being compiled. The result is no different than if you had copied and pasted the content into the current yourself. This directive takes the form <%@ include file="relativePath" %>, where relativePath is the path to the file to include, relative to the including page.

The included content is called a segment, and the segment file conventionally has a .jspf extension. JSP segments were originally called “fragments”, which gave rise to the .jspf extension. You can include any static content, even HTML partials, using the include directive.

The <jsp:include> Action

Including content using the <jsp:include> action.
<%-- about.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html lang="en-US">
…
<body>
  <h1>About Acme Company</h1>
  <jsp:include page="established.jsp">
    <jsp:param name="yearEstablished" value="2000" />
  </jsp:include>
</body>
</html>
<%-- established.jsp --%>
<%@ page pageEncoding="UTF-8" %>
<%@ page import="java.time.Year" %>
<p>In business for
  ${Year.now().value - param.yearEstablished} years!</p>
About Acme Company
In business for 18 years!

In addition to the include directive, JSP also provides the <jsp:include> action. While directives indicate instructions for the JSP compiler, actions are evaluated dynamically at request time. Resources that are included using <jsp:include> are compiled just like JSP pages—and in fact the other resource could be another .jsp file, although it might not be helpful to include an entire “page” of HTML output inside another. The included resource will be invoked to generate included content each time the including page is rendered.

The general form is <jsp:include page="urlSpec" />, where urlSpec can be a URL relative to the including page (as with the include directive), or a URL starting with a slash / character which is resolved relative to the web application context. Because <jsp:include> includes a resource dynamically, the including page can pass parameters to the resource at request time. In this case one or more <jsp:param name="name" value="value" /> parameter actions are included in the body of the <jsp:include> action. These values result in request parameters that the included resource can access! The parameter values and even the included page URL can be specified by an EL expression that is evaluated at request time.

The <c:import> Action

In addition two the two native JSP approaches for including content, the JSTL provides yet another alternative. The general form of the action is <c:import url="url" [var="varName"] [scope="page|request|session|application"] />. The <c:import> action can be used exactly like the <jsp:include> action, including parameters (although with you must use <c:param> instead, which has the same format as <jsp:param>). In addition <c:import> brings two powerful capabilities:

Changing Pages

Forwarding a Request with <jsp:forward>

There are two basic ways to transfer control to another page. The first changes the dispatch of the request, or how the request is routed. The <jsp:foward page="urlSpec"> action will forward the request, or transfer control, to another JSP page or even a servlet. The urlSpec indicates the page to transfer control to, and follows the same page resolving rules as does <jsp:include>. And as with <jsp:include>, you can use <jsp:param> to send parameters to the page receiving control.

Redirecting a Request with <c:redirect>

Unlike forwarding, which is done within a single HTTP request, the JSTL <c:redirect url="value"> action sends back an HTTP temporary redirect response code 302 (Found). The Location HTTP response header will indicate the new location provided in the url attribute. The browser will then see the redirect response and issue a new request to the indicated URL, which may or may not even be a JSP page—or even in the same web application.

As with other JSTL actions dealing with URLs, the URL value can be a relative path within the current context, or an absolute path relative to the current context. You can even specify a true URL with a scheme, such as https://example.com/, if you want to redirect to a page outside the current web application. As with <c:url>, a path within the same context will have the session information included if necessary. Also similar to <c:url>, the <c:redirect> action permits child <c:param> actions to help in appending URL query parameters to the destination.

Configuring JSP

You can change how the JSP container processes pages by setting the configuration in the WEB-INF/web.xml file. As you will remember from the lesson on servlets, web.xml file is a configuration file for Java servlet technology and web applications in general. In Maven, place the file at src/main/webapp/WEB-INF/web.xml. You can have Eclipse generate the file for you automatically if it doesn't already exist, using Right-ClickJava EE Tools → Generate Deployment Descriptor Stub for your project in Project Explorer.

Boilerplate of a Java EE 8 web.xml file.
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    version="4.0">
  …
</web-app>

JSPs are configured in a <jsp-config> section. Sets of pages are grouped into a <jsp-property-group> section so that those pages can be configured independently from other groups.

JSP Extension

Configuring the extension for JSP pages.
…
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.foo</url-pattern>
    </jsp-property-group>
  </jsp-config>
…

By default the container compiles all *.jsp files to JSP. You can configure your web.xml so that the container will interpret other files as JSP as well. For example you could configure files with the .foo extension to be compiled and installed as JSP files by adding another <jsp-property-group> indicating the <url-pattern> to match:

Page Encoding

Configuring the page encoding for all JSP pages.
<!-- web.xml -->
…
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <page-encoding>UTF-8</page-encoding>
    </jsp-property-group>
  </jsp-config>
…
<%-- JSP --%>
<%@ page contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html lang="en-US">
…

Rather than including the encoding a <%@ page contentType="text/html; charset=UTF-8" %> directive at the top of each an every page, you can configure a default encoding. (This would apply to included pages as well, removing the need to add a <%@ page pageEncoding="UTF-8" %> to them, as explained above in <jsp:include>.) Because contentType defaults to text/html in JSP pages, you could then dispense with the <%@ page contentType="text/html" %> directive altogether. Note that you would still need to indicate a content type of text/html for JSP pages encoded as XML, as their default content type is text/xml, discussed below under JSP Documents and XML.

Trim Directive Whitespace

Just as you can remove extra whitespace from directives using the trimDirectiveWhitespaces page directive, you can configure JSP to remove whitespace around directives on all pages using the trim-directive-whitespaces element with a value of true.

Removing directive whitespace from all JSP pages.
<!-- web.xml -->
…
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <page-encoding>UTF-8</page-encoding>
      <trim-directive-whitespaces>true</trim-directive-whitespaces>
    </jsp-property-group>
  </jsp-config>
…
<%-- JSP --%>
<%@ page trimDirectiveWhitespaces="true" %>
<!DOCTYPE html>
<html lang="en-US">
…

Disabling Scripting

Disabling scripting elements for all JSP pages.
…
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.foo</url-pattern>
      <scripting-invalid>true</scripting-invalid>
    </jsp-property-group>
  </jsp-config>
…

You've seen how scripting elements are outdated, and do not promote the best practice of separating the presentation of information from the program logic. It's best not to use scripting elements such as scriptlets, script expressions, and script declarationgs, at all. To enforce this policy you can disable scripting elements altogether in your JSP by provding the scripting-invalid element a value of true.

Review

Gotchas

In the Real World

JSP Documents and XML

The JavaServer Pages specification was released in the era in which XML was becoming increasingly popular. XML tools were proliferating, and as you have seen the W3C was even attempting to refashion HTML with modularized XML schemas in XHTML. There was a desire to edit JSP pages using the syntax highlighting, well-formedness checking, and other benefits of an XML workflow. But JSP pages use a special syntax, most prominent in its directives (e.g. <%@ page contentType="text/html; charset=UTF-8" %>), that is not compatible with XML.

Sun Microsystems thus added an XML syntax for JSP, complete with namespace support. A page written in the XML syntax is referred to as a JSP document, and usually has a .jspx extension. Directives have special XML forms; for example the page directive in the previous paragraph would appear as <jsp:directive.page contentType="text/html; charset=UTF-8" />. Although not strictly necessary, it is usually easiest to add an enclosing <jsp:root> element for declaring namespaces. A special action called <jsp:text> is used to output literal text—something necessary just to create the standard HTML5 document type declaration! Note that the document type now has to be XML-encoded so that it won't be interpreted as part of the original document.

Generating an About page using a JSP document about.jspx.
<?xml version="1.0" encoding="UTF-8" ?>
<!-- About page written as a JSP document. -->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.3">
<jsp:directive.page contentType="text/html; charset=UTF-8" />
<jsp:directive.page import="java.time.Year" />
<jsp:text>&lt;!DOCTYPE html&gt;</jsp:text>
<html lang="en-US">
<head>
  <meta charset="UTF-8"/>
  <title>About Acme Company</title>
</head>
<body>
  <p>In business for ${Year.now()["value"] - 2000} years!</p>
</body>
</html>
</jsp:root>

Whatever theoretical benefits JSP document bring, in practice JSP documents have found little use. Their need for additional boilerplate, along with their less-than-helpful output, reduce some of their benefits. Moreover many editors now have syntax highlighting for JSP, and HTML linting may be sufficient for JSP as well.

Think About It

Self Evaluation

Task

Upgrade your Booker search page to include its first actual search capabilities! Show a table of all publications on the search page, with appropriate columns to show book details. Allow the user to pass an isbn query parameter in the search page URL. If an isbn query is present, filter the table to only show the book with the indicated ISBN.

See Also

References

Resources

Acknowledgments