Client/Server Programming -- Week 12
Introduction
This week we'll cover Java Server Pages.
Note that the links from this page are to handouts that will be distributed the night of class. Only print out those handouts if you could not attend class.
Main topics this week:
Assignment 9-1 Due
Server Side Scripting
Java Server Pages
JSP Scriptlets
Variable Scope in Scriptlets
Conditionals and Looping
Printing Shortcut
Predefined Scriptlet Variables
Advanced Scriptlet Techniques
The JSP Classpath
Servlet to JSP Examples
Assignment 12-1 Assigned
Next Week
Your assignment 9-1 is due this week for full credit. You may turn it in up to next week for 10% off.
Last week we looked at using templates to make servlets easier to write. One way of writing a template was to embed scripts into the HTML file. A technology called server side scripting takes this concept one step further, and embeds all the code needed by the web page into the HTML file...there is no servlet anymore that contains program logic. Instead, all the scripting needed by the dynamic web page is embedded into the web page itself.
This concept is used by technologies such as Java Server Pages (JSP), Active Server Pages (ASP), PHP, and others.
One of the prime disadvantages of server side scripting is the need to execute the scripts in the HTML page every time the page is displayed. Most server side scripting technologies get around this by compiling the HTML page into some more efficient form. Java Server pages is no exception.
When a web page containing JSP scripts is first requested, it is compiled into a .class file. This process is called "translation". From then on, the compiled code is used to display the page. If the HTML file changes, the page is translated again. The compiled .class file is actually a kind of servlet which is executed by the web server when the page is requested.
A web server that supports JSPs will have a special servlet called PageCompile. This servlet is called when a request is made for a JSP. The PageCompile servlet takes care of compiling the page as needed, and calling the methods on the compiled page to produce output to the user.
Where do I put my Java Server Pages?
If you have a web server that supports JSPs, such as Tomcat, the web server will have its own requirements on where to put them. In Tomcat, a JSP is part of a web application, and should go into the subdirectory structure for the web application. Typically a JSP will go into the root of the web application, along with any static HTML pages you have.
The JSP must have the extension ".jsp". That tells the web server that the page needs compiled and executed. To test that you can properly execute a Java Server Page, take any static HTML page and rename it to have the .jsp extension. Put it into the root of a web application directory structure, and then open it in your web browser. The web page should display the same as always, but now you can find the compiled form of the page in the /tomcat/work directory structure (look down into the directory structure). Note that the process of displaying the page is now much less efficient than if it had simply remained a static HTML page...so only use .jsp for pages that really contain JSP code.
When is JSP appropriate?
JSP is designed to provide dynamic pages of textual data. So a listing of users obtained from a database or another server would be a good use of JSP.
The term scriptlet was coined because you're embedding actual Java code into an HTML page. The Java code you embed in the HTML page can use some predefined variables, such as the variable "out" to represent the PrintWriter that is being used to output the web page.
Here's an example of a scriptlet:
<html>
<head>
<title>A simple scriptlet</title>
</head>
<body><%
out.println ("<p>Hello World!</p>");
%>
</body>
</html>
Save this to a .jsp file and open it in your web browser, and you'll see a page that says "Hello World!".
Note that while you do have some predefined variable to use, you can also include your own variables (remember, you're embedding actual Java code into the HTML page, so anything legal in Java is legal in a scriptlet). For example:
<html>
<head>
<title>A simple scriptlet</title>
</head>
<body><%
String name = "Jay";
out.println ("<p>Hello " + name + "</p>");
%>
</body>
</html>
The name variable declared above will be good in *any* of the script blocks in the same page. For example, the following is legal:
<html>
<head>
<title>A simple scriptlet</title>
</head>
<body><%
String name = "Jay";
out.println ("<p>Hello " + name + "</p>");
%>
<p>This is some static text</p>
<%
out.println ("So, " + name + ", how do you like the page?");
%>
</body>
</html>
To see why this variable is still in scope in the second block, you should examine the code generated by the web server. For this example, the code is:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent
{
private static java.util.Vector _jspx_dependants;
public java.util.List getDependants() {
return _jspx_dependants;
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException
{
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
try {
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<title>A simple scriptlet");
out.write("</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
String name = "Jay";
out.println ("<p>Hello " + name + "</p>");
out.write("\r\n");
out.write("<p>This is some static text");
out.write("</p>\r\n");
out.println ("So, " + name + ", how do you like the page?");
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
}
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}
You can see that all the blocks of scriptlet code are put into the same method in the generated code. So a variable defined in the first scriptlet block is available in all future scriptlet blocks. If you want a variable only available in one scriptlet block, then you should use curly braces to create an inner scope for that scriptlet block:
<html>
<head>
<title>A simple scriptlet</title>
</head>
<body><%
{
String name = "Jay";out.println ("<p>Hello " + name + "</p>");
}%>
<p>This is some static text</p>
<%
out.println ("So, " + name + ", how do you like the page?");
%>
</body>
</html>
In this example, the first scriptlet block uses curly braces to create a local scope, so the variable name is only available within those curly braces. The second scriptlet block that tries to use name will not find it, and you'll get an error sent back when you try to display the JSP.
You can use normal Java conditionals and loops inside a scriptlet. Since all the scriptlet blocks are part of the same Java method, you can start a curly brace in one scriptlet block and end it in another. Consider this use of an if statement:
<html>
<head>
<title>A simple scriptlet</title>
</head>
<body><%
if (request.getParameter ("gotostatistics") != null)
{
%><p>This is some text that represents a statistics page</p>
<%
}
else if (request.getParameter ("gotoscore") != null)
{
%><p>This is some text that represents the score page</p>
<%
}
%><p>This is some static text that appears at the bottom of all pages.</p>
</body>
</html>
You can intermix scriptlet blocks with HTML in quite complicated ways to ensure that the page appears with the content you need.
Since it's awkward to use "out.println" to print out variables, there's a shortcut that you can more easily mix in with HTML. Using the start tag "<%=" and the end tag "%>", anything between those two tags will be placed inside of an "out.println" line for you. This makes it quite easy to use Java parameters as arguments for HTML tags. For example:
<font color="<%= request.getParameter ("fontcolor")%>">Some text in a color</font>
You can use the printing shortcut anywhere, not just inside HTML tags.
Predefined Scriptlet Variables
By looking at the code the web server generates for a JSP, you can see what other predefined variables there are, besides the "out" variable. We'll look at the most useful ones.
session The session variable represents the HttpSession object for the current user. Use it like you would use a session in a servlet.
request This is the HttpServletRequest object passed into servlets. Use it to get the value of parameters sent from forms.
response This is the HttpServletResponse object. Use it to add cookies or encode URLs for session tracking.
application This represents the entire web application, of which this JSP is a part. Can be used to set "global variables" that are accessible from all the JSPs and servlets that are part of the web application.
config The config variable can be used to retrieve parameters that were set in the web.xml file.
Data Members
You may want to use a data member to remember values between requests to your Java Server Page. Since scriptlet blocks are put into a method, how do you declare a data member? You use the start tag "<%!" to indicate that whatever follows goes outside the method. You can define, then, data members by using:
<%!
String name;
String address;%>
Note that your book contains an example of declaring a data member and does not include a semicolon at the end of the line. This is incorrect, and will cause an error when you try to display the page. The code between the tags must be legal Java code.
Since the code between <%! and %> goes outside of any method, you can use it to define private methods in the class, if you wish.
Page Attributes
A Java Server Page has certain attributes that can control other aspects of the code that is generated. You can modify a page attribute by starting with the "<%@" tag, and ending with the "%>" tag. Inside the tags, you must use the word "page", and then the name of the attribute you are modifying along with the new value for the attribute. Some of the attributes possible are:
import -- This sets any custom import statements you need. All the import statements must be set at once.
session -- You can say whether a session should be created for this page or not. The default is "true", which creates sessions.
isThreadSafe -- You can say whether your JSP can be called by multiple threads.
Including other pages
A JSP can include other pages inside itself by using the "<%@ include file="someurl" %>" directive. This pastes the contents of the other page into the JSP as static content. The results of calling the URL are pasted into the JSP at translation time (e.g. only once), rather than when the JSP page is requested. So even if your URL represents a servlet or another JSP, you will not get dynamic results out of it.
To include another page that may produce dynamic results, you use a different sort of tag:
<jsp:include page="someurl">
</jsp:include>
The contents of the page represented by "someurl" will be pasted into the JSP everytime that the JSP is requested, not just once at translation time. You can include parameters to the page represented by "someurl" by adding other tags:
<jsp:include page="someurl">
<jsp:param name="age" value="29"/>
</jsp:include>
This allows you to call servlets or other JSPs that may be expecting to be called from forms, by providing the values of the fields the forms would have provided.
So, use "<%@ include" if you're including static contents, and use "<jsp:include" if you're including dynamic content.
A JSP page uses the same classpath that its web application uses...in other words, .class files in WEB-INF/classes or .jar files in WEB-INF/lib are both in the classpath. There are a few complications for JSPs, though.
First, a JSP page is compiled by Tomcat to be part of a package. On my version of Tomcat this package is "org.apache.jsp".
Second, in JDK versions 1.4 and above, a class in a package cannot import a class that is not in a package. So your JSP file cannot use any of your classes unless those other classes are in packages.
The way to get your JSP file using classes you have written is as follows:
Now, your JSP files should be able to use all the classes from mypackage.
Here are a couple of examples of converting the Psychologist servlet example into JSP.
The first version is a relatively simple cut and paste of code from the servlet into the JSP.
The second version shows rewriting the servlet using JSP and HTML code intermixed, rather than simply cutting and pasting from the servlet into the JSP.
Both JSPs perform the same tasks as the original servlet.
Assignment 12-1 is assigned this week. This assignment will be due in two weeks.
Next week we will finish Java Server Pages.