JSP
Goals
- Learn about the evolution of dynamic web technologies.
- Understand the difference between server-side and client-side dynamic sites.
- Use JSP technology.
- Utilize JavaBeans in a JSP pages.
- Become familiar with web application attribute scopes.
- Access request query parameters dynamically.
- Use JSTL actions to include partials and display repeated content.
Concepts
- action
- Active Server Pages (ASP)
- application scope
- attribute
- client-side dynamic
- directive
- Don't Repeat Yourself (DRY)
- dispatch
- dynamic
- Expression Language (EL)
- forward
- function
- implicit object
- JavaServer Faces (JSF)
- JavaServer Pages (JSP)
- JSP document
- JSP Standard Tag Library (JSTL)
- page scope
- partial
- PHP: Hypertext Preprocessor (PHP)
- request scope
- resolution
- scope
- scriptlet
- segment
- server-side dynamic
- session
- session scope
- tag library
- URL rewriting
Library
javax.servlet.ServletConfig
javax.servlet.ServletContext
javax.servlet.ServletRequest
javax.servlet.ServletRequest.getParameter(String name)
javax.servlet.ServletResponse
javax.servlet.annotation.WebServlet
javax.servlet.http.Cookie
javax.servlet.http.HttpServletRequest
javax.servlet.http.HttpServletResponse
javax.servlet.http.HttpSession
javax.servlet.jsp.HttpJspPage
javax.servlet.jsp.HttpJspPage._jspService(HttpServletRequest request, HttpServletResponse response)
javax.servlet.jsp.JspPage
javax.servlet.jsp.JspPage.jspDestroy()
javax.servlet.jsp.JspPage.jspInit()
javax.servlet.jsp.PageContext
javax.servlet.jsp.PageContext.getPage()
javax.servlet.jsp.PageContext.getRequest()
javax.servlet.jsp.PageContext.getResponse()
javax.servlet.jsp.PageContext.getServletConfig()
javax.servlet.jsp.PageContext.getServletContext()
javax.servlet.jsp.PageContext.getSession()
Dependencies
javax.servlet:javax.servlet-api:4.0.1
(scope: provided)javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
(scope: provided)javax.servlet.jsp:jstl:1.2
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.
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.
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.
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. &&
.
- EL treats JavaBean style getters and setters as properties, allowing access via the
.
symbol. Thus the methodYear.getValue()
is considered a property namedvalue
, allowing${Year.now().value - 2000}
as in the initial JSP example. - Properties can also be accessed using
["property"]
notation, with single or double quotes. Using this approach the example would appear${Year.now()["value"] - 2000}
. This format makes it easier to use another variable as the name of the property to retrieve. - The
[]
operator has been extended to theList
interface so thatmyList[5]
can be used as if it were an array. - The operator
empty
has been added as a shortcut to check if a reference isnull
; the empty string""
; or an empty collection or map. - You can call certain EL functions in the form
func(args…)
.
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. ThepageContext
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 ofjavax.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 ofjavax.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, useparamValues
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, useheaderValues
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 theweb.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
.
Scope
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
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.
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.
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 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.
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.
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 |
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.
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:
- array
Collection
Iterator
Map
Iterates over eachMap.Entry
.java.lang.String
Iterates over each comma-separated token in the string.
This form makes it easy to display the details of inventory items in a warehouse.
Outputting Content with <c:out>
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>
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.
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.
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
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
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:
- While
<jsp:include>
requires a path resolved relative to the application context, the<c:import>
url
can be a complete URL to a location outside the current application—even on another server such ashttps://example.com/foo.html
. - By default
<c:import>
includes the resulting content on the page, but if you provide avarName
the content is instead stored in the given variable in page scope (unless a differentscope
is provided).
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-Click → Java EE Tools → Generate Deployment Descriptor Stub for your project in Project Explorer.
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
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
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
.
Disabling Scripting
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
- Remember that certain characters such as
&
must be escaped in XML/HTML. You may choose to useand
instead of&&
to avoid escaping in EL expressions. - It is dangerous to print strings using EL, especially if they contain user data, because they may include HTML and or JavaScript. Use
fn:escapeXML()
with your EL or use<c:out>
instead. - If you link to a page within your application and the user's browser doesn't allow cookies, the current session may be lost unless you use
<c:url>
to form the link.
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.
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.
- Discuss how the the old
<jsp:useBean>
approach requires a JavaBean with a default constructor. It will bypass any dependency injection or service locator mechanism, which makes it difficult to initialize the bean with access to a repository, for instance. See https://stackoverflow.com/q/43101010/421049 and https://stackoverflow.com/q/7385723/421049. This means the bean must hard-code some reference to a repository or have access to a configuration in order to create a direct connection to the database, neither of which is desirable.
Think About It
- Would you prefer to use the classic JSP format or JSP document XML format? Why would you choose one over the other?
Self Evaluation
- Name some other server-side technologies like JSP for making dynamic sites but using other languages.
- What are the three type of JSP elements? Which type should you seldom if ever use? What is the difference between the other two?
- What is variable resolution and how does it relate to EL?
- What happens if you try to access the property of a
null
variable using EL? What would happen evaluating${car.engine.temperature}
if the card had no engine (car.engine == null
), for example? - What is the difference between the
param
andparamValues
EL implicit objects? Under what circumstances would usingparam
not work as desired? - Identify two ways to retrieve a property from a bean. Assuming the bean is already stored in the session, which approach would require
<jsp:useBean>
before access? - What happens if you set a bean's property indicating a request parameter that isn't present?
- Why is it almost always better to use
<c:out>
rather than a bare EL expression? What other alternative is there to solve this problem? - What are three ways to include external content in a JSP page? What are the differences?
- How is “forwarding” to a different page different from “redirecting” to a different page?
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.
- Configure your
web.xml
file so that the search HTML page will be compiled using JSP.- Continue using the
.html
extension for the page. - Interpret the other
.html
pages as static HTML pages, not as JSP. - Configure the default encoding of
UTF-8
so that this doesn't have to be specified in the HTML page itself. - Remove whitespace from the page directives, still using the
web.xml
configuration, to produce a tidier output. - Disable scripting directives so that they cannot inadvertently be used on your JSP page.
- Continue using the
- Extract your menu into a partial stored in a separate JSP file.
- In the menu partial JSP, allow an optional parameter indicating which menu item is active.
- On the search page, when you include the menu partial pass the appropriate parameter so that the menu item corresponding to the page is shown as active.
- Create a JavaBean to serve as a query builder for your publications.
- Because of the difficulties of connecting a bean to your configured repository in JSP, for now let the bean directly use a
SnapshotRepository
without using dependency injection. You'll learn a better way to connect to your configured repository in an upcoming lesson. - Use a bean property to optionally set the ISBN to display.
- Because of the difficulties of connecting a bean to your configured repository in JSP, for now let the bean directly use a
- Use JSTL
<c:forEach>
to present the publications in the table.
See Also
- The Java EE Tutorial (The Java EE Tutorial Project)
- JSP Tutorial (luv2code - YouTube)
- Getting Started with JSP, a free chapter Sams Teach Yourself JavaServer Pages in 21 Days (Steven Holzner - Sams, 2002).
References
- Java™ Servlet 4.0 Specification (JSR 369) (Java Community Process)
- JavaServer Pages 2.3 Specification (JSR 245) (Java Community Process)
- Expression Language 3.0 (JSR 341) (Java Community Process)
Resources
Acknowledgments
- JavaServer Pages, Third Edition (Hans Bergsten - O'Reilly, 2009)
- Java EE 8 Recipes (Josh Juneau - Apress, 2018)