9.3 JavaServer Pages
JavaServer Pages are the Java way to build web-based user interfaces using Java as a scripting language for generating dynamic
XHTML. In other words, JSP enables you to embed Java code inside your XHTML so that the full content of the XHTML page can be dependent on the state of the system when a user requests a page. Example 9-3 shows your obligatory "Hello World" application as a JSP page.
Example 9-3. A simple JSP page
<%@ page info="Hello World" %> <% String msg = "Hello World!"; %> <html> <head> <title><%=msg%></title> </head> <body> <h1><%=msg%></h1> <p> Though this example is largely uninteresting, it does demonstrate how Java can be embedded in an XHTML page to generate content dynamically. </p> </body> </html>
As with any "Hello World" application, this one is mind-numbingly dull. What you should take from it, however, is the basic structure that enables you to call methods in Java objects and drive content from Java values. Though I used a simple String instance in this example, the <title> and <h1> values could have been drawn from a database.
The web server or application server in which the JSP runs interprets anything between <% and %> as Java code and anything between <%= and %> as values to be printed out. When a request is made for a JSP page, that page is turned into a Java object. Your embedded Java code becomes part of that compilation. The XHTML in your page becomes a string to send out. The server then executes the method into which your Java code was compiled.
This compile happens only once as long as the server remains running and no one changes the JSP source. If you make a change to the JSP source, however, the server will recompile it the next time it is requested.
JSPs become interesting when you hook them up to an EJB system or a database. Naturally, we will be doing just that throughout Part II of this book. This section simply describes the basics behind JavaServer Pages.
9.3.1 Page Structure
A JSP page consists of static content, JSP directives, Java code, and JSP tags:
- Static content
Static content is the XHTML into which your JSP code is embedded.
- JSP directives
These elements appear between <%@ and %> markers. They indicate directives to the server prior to compiling the JSP page.
- Java code
Java code is everything between <% and %> and between <%= and %> tags. This code is executed for each page view.
- JSP tags
A JSP tag is an XML-like interface into a library of Java code. The JSP specification prescribes a core set of tags, but you can add your own through custom tag libraries.
As a general rule, the fewer lines of Java code in your JSP page, the better. When you add a lot of Java code to a JSP page, you, in a sense, defeat the purpose of using JSPs over the Java Servlet API. Specifically, defining your user interface as a set of JSPs enables you to transfer the work of user interface writing to XHTML programmers instead of Java programmers. This transfer hopefully results in more creative resources being responsible for UI development.
9.3.2 JSP Programming
Example 9-4 provides a more typical JSP page than the "Hello World" code in Example 9-3.
Example 9-4. A JSP page that drives content from a content management database
<%@ page info="Page Loader" %> <%@ page import="org.dasein.tractatus.jsp.ErrorLog" %> <%@ page import="org.dasein.tractatus.jsp.Tractatus" %> <%@ taglib uri="/WEB-INF/tld/tractatus.tld" prefix="tractatus" %> <jsp:useBean id="user" scope="session" class="org.dasein.security.User"/> <% pageContext.setAttribute(Tractatus.USER, user); %> <% user.setPreferredLocale(request.getLocale( )); %> <tractatus:setTarget/> <% pageContext.setAttribute("template", target.getTemplate( )); %> <% if( target.getContent( ) != null ) { %> <% pageContext.setAttribute("contentTemplate", target.getContent( ).getTemplate( )); %> <% } else { %> <% pageContext.setAttribute("contentTemplate", null); %> <% } %> <tractatus:authorize> <tractatus:allowed> <tractatus:isNull name="template"> <tractatus:true> <tractatus:isNull name="contentTemplate"> <tractatus:true> <tractatus:printContent/> </tractatus:true> <tractatus:false> <jsp:include page="<%=target.getContent( ).getTemplate( ).getRelativeURL( )%>"/> </tractatus:false> </tractatus:isNull> </tractatus:true> <tractatus:false> <jsp:include page="<%=target.getTemplate( ).getRelativeURL( )%>"/> </tractatus:false> </tractatus:isNull> </tractatus:allowed> <tractatus:denied> <% String msg = "<p class=\"error\">Access denied.</p>"; %> <jsp:include page="page.jsp"> <jsp:param name="target" value="<%=target.getSite( ).getErrorPage( ).getPageID( )%>"/> <jsp:param name="error" value="<%=ErrorLog.storeException(msg)%>"/> </jsp:include> </tractatus:denied> <tractatus:unauthenticated> <% response.sendRedirect(target.getSite( ).getLoginPage( ).getRelativeURL( ) + "&previous=" + target.getPageID( )); %> </tractatus:unauthenticated> </tractatus:authorize>
Though all of the content for this page is dynamically generated, very little of it is direct Java code. It starts out with three directives:
<%@ page info="Page Loader" %> <%@ page import="org.dasein.tractatus.jsp.ErrorLog" %> <%@ page import="org.dasein.tractatus.jsp.Tractatus" %> <%@ taglib uri="/WEB-INF/tld/tractatus.tld" prefix="tractatus" %>
The first directive provides metainformation about the JSP page for tools. The second and third directives tell the server what Java import statements to use for this page when compiling it. The final one tells the server where to find definitions for the custom tags in use in this page.
Only the last directive requires any elaboration. When you build a library of Java objects that can serve as JSP tags, you need to create an XML descriptor file that maps tag names to Java classes. The uri value for the taglib directive points to this XML file. The prefix value then names what prefix will appear for the tags in this JSP page. In this case, the prefix is tractatus.
You will use the tag in the next line of code, <jsp:useBean>, in almost all of your JSP pages. It enables you to store and access a regular JavaBean as part of the user session information. In this case, I am storing a User object representing the site visitor.
The next two lines are the first bit of actual Java code:
<% pageContext.setAttribute(Tractatus.USER, user); %> <% user.setPreferredLocale(request.getLocale( )); %>
You probably gather that the user variable in the second line comes from the call to <jsp:UseBean>. On the other hand, it is entirely unclear where the pageContext variable comes from. A JSP page defines several page-level variables to which you have access. The two you will most commonly use are pageContext and request. The pageContext variable represents information about the context of the page execution. In this example, I am setting an attribute that can be used by my custom tags. The Tractatus.USER constant is simply a String constant for "user".
The other variable you will commonly need, request, represents the HTTP request coming in from the browser. It contains information about the requester and the headers of the request. In the second line, I am looking for internationalization information from the request. Specifically, I am trying to find out what locales the browser is set to accept.
The next line is the first custom tag in this JSP page:
<tractatus:setTarget/>
Behind this tag's simplicity is some complex Java code for setting a variable named target to a custom Java object of type org.dasein.tractatus.Page based on the request sent to the server. For example, if the URL was http://www.imaginary.com/page.jsp?target=5, then the <tractatus:setTarget> tag will go to the database, find the Page with a pageID of 5, and then set the target variable to that Page instance.
Perhaps you can imagine the level of complexity I would have added to this page had I not hidden everything behind a JSP tag. Now, XHTML programmers do not need to know anything about looking up custom objects hidden in a database. They simply include this one empty tag and they are all set.
The rest of the code is mostly custom tags with a small mix of Java code. In short, it does the following:
Verifies that the user has access to the requested page. Verifies that the user is disallowed, allowed, or not yet authenticated: If disallowed, the user is redirected to a page telling him he does not have the proper permissions. If allowed, the user is shown the actual content through the <jsp:include> tags. If the user has yet to be authenticated and the web page is not open to the public, the user is redirected to a login page.
9.3.3 Custom Tags
The power of JavaServer Pages lies in the ability to build reusable Java components and then hide them behind custom tags. The creation of custom tags is quite simple. You write a class that implements a specific API and then map that class to a tag name via an XML descriptor file. A simple custom tag looks like Example 9-5.
Example 9-5. A simple custom tag
package org.dasein.tractatus.jsp;
import java.io.IOException; import java.util.Locale;
import javax.servlet.ServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.TagSupport;
import org.dasein.persist.PersistenceException; import org.dasein.security.User; import org.dasein.tractatus.Page;
public class HTMLTitleTag extends TagSupport { public int doEndTag( ) throws JspException { try { Page p = (Page)pageContext.getAttribute(Tractatus.TARGET); User u = (User)pageContext.getAttribute(Tractatus.USER); Locale def = p.getSite( ).getDefaultLocale( ); String ttl;
ttl = "<title>" + p.getTitle(u.getPreferredLocale(def)) + "</title>"; pageContext.getOut( ).println(ttl); } catch( IOException e ) { throw new JspException(e.getMessage( )); } catch ( PersistenceException e ) { throw new JspException(e.getMessage( )); } return EVAL_PAGE; } }
This custom tag extends the TagSupport class from the JSP API and implements a single method, doEndTag( ). This method is triggered when the server reaches the end tag of your custom tag. Because this particular tag is an empty tag, the end happens right after the start. In this example, the tag finds the current target value (previously set by <tractatus:setTarget>) as well as the current user value (previously set by <jsp:useBean>). It then prints out the XHTML for the page's title translated into the user's preferred language.
To add this tag to the web site, you need to edit the XML tag library descriptor file to map a tag name to this class. If this tag were the only tag in the tag library, the descriptor file would look like Example 9-6.
Example 9-6. Sample tag descriptor
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1/EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
<tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>tractatus</shortname>
<tag> <name>htmlTitle</name> <tagclass>org.dasein.tractatus.jsp.HTMLTitleTag</tagclass> <bodycontent>empty</bodycontent> </tag>
</taglib>
The code in bold shows the definition of the custom tag. It maps the name htmlTitle to the class org.dasein.tractatus.jsp.HTMLTitleTag and establishes the constraint that the tag should be an empty tag. Consequently, whenever the server encounters the following in a JSP page:
<tractatus:htmlTitle/>
The server prints out the title of the page referenced by the target variable localized for the user.
Custom tags do get more complicated. Some contain XHTML code, while others contain other custom tags. A full description of this API is well beyond the scope of this book. For more information, take a look at JavaServer Pages (O'Reilly) by Hans Bergsten.
|
No comments:
Post a Comment