0% found this document useful (0 votes)
41 views29 pages

02 Page Navigation

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 29

© 2005 Marty Hall

JSF: Controlling
Page Navigation

Core Servlets & JSP book: www.coreservlets.com


More Servlets & JSP book: www.moreservlets.com
Servlet/JSP/Struts/JSF Training: courses.coreservlets.com
http://courses.coreservlets.com/ -- Hands-on, customized training for Java, servlets, JSP, Struts, and JSF.

© 2005 Marty Hall

For live JSF training, please see


JSP/servlet/Struts/JSF training courses at
http://courses.coreservlets.com/.
Taught by the author of Core Servlets and JSP, More
Servlets and JSP, and this tutorial. Available at
public venues, or customized versions can be held
on-site at your organization.
http://courses.coreservlets.com/ -- Hands-on, customized training for Java, servlets, JSP, Struts, and JSF.
Topics in This Chapter
• JSF flow of control
• The basic steps in using JSF
• Static navigation
– One result mapping
• Dynamic navigation
– Multiple result mappings

4 J2EE training and tutorials: http://www.coreservlets.com

JSF Flow of Control


• A form is built from a palette of GUI
components and displayed to the user
• The form is submitted to itself
– I.e., both original URL and ACTION URL are
http://…/blah.faces
• A bean is created that represents the form
data
• The action designated by the form is
invoked
– This method uses the data from the form bean, invokes
business-logic and data-access logic, and creates/stores
results beans
• The action method returns a condition
• The page corresponding to the condition is
5
displayed J2EE training and tutorials: http://www.coreservlets.com
Steps in Using JSF
1. Create a bean to represent the form data
• Postponed until next section
2. Use f:view and h:form to create an input
form
3. Specify the action controller with the
action attribute of h:commandButton
4. Create an action controller that reads the
form data, invokes business logic, stores
results beans, and returns conditions
5. Use faces-config.xml to declare the form
bean and navigation rules
6. Create JSP pages corresponding to each
return condition
7. Protect raw JSP pages from access
6 J2EE training and tutorials: http://www.coreservlets.com

Example 1: Static Navigation


• Started by copying jsf-blank and renaming it
to jsf-test
• Original URL will be
http://hostname/jsf-test/register1.faces
• When form submitted, a static page
(result1.jsp) is displayed
• No business logic, beans, or Java code of
any sort
• Main points
– Format of original form
– Use of the faces-config.xml file

7 J2EE training and tutorials: http://www.coreservlets.com


Main Points of This Example
• Input form has following format:
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<f:view>
HTML markup
<h:form>
HTML markup and h: tags
</h:form>
HTML markup
</f:view>
• You use faces-config.xml to declare mappings:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE faces-config PUBLIC …>
<faces-config>
<navigation-rule>
<from-view-id>/blah.jsp</from-view-id>
<navigation-case>
<from-outcome>some string</from-outcome>
<to-view-id>/WEB-INF/results/something.jsp</to-view-id>
</navigation-case>
</navigation-rule>
8 </faces-config> J2EE training and tutorials: http://www.coreservlets.com

Step 1: Create Form Bean


• Postponed until next section
– This example ignores form data

9 J2EE training and tutorials: http://www.coreservlets.com


Step 2: Create Input Form
• Basic format
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<f:view>

<BODY>

<h:form>

</h:form>

</BODY>
</f:view>
• Invoking page
– Actual file is blah.jsp
– URL is blah.faces

10 J2EE training and tutorials: http://www.coreservlets.com

Step 2: Create Input Form


• The h:form element
– ACTION is automatically self (current URL)
– METHOD is automatically POST
• Elements inside h:form
– Use special tags to represent input elements
• h:inputText corresponds to <INPUT TYPE="TEXT">
• h:inputSecret corresponds to <INPUT TYPE="PASSWORD">
• h:commandButton corresponds to <INPUT TYPE="SUBMIT">
– In later sections, we will see that input elements will be
automatically associated with bean properties
– For static navigation, specify arbitrary string as action of
h:commandButton
• String must match navigation rule from faces-config.xml
• More info on h:blah elements
– http://java.sun.com/j2ee/javaserverfaces/1.1/docs/tlddocs/

11 J2EE training and tutorials: http://www.coreservlets.com


Step 2: Example Code
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<f:view>
<!DOCTYPE …>
<HTML>
<HEAD>…</HEAD>
<BODY>
<CENTER>
<TABLE BORDER=5>
<TR><TH CLASS="TITLE">New Account Registration</TH></TR>
</TABLE>
<P>
<h:form>
Email address: <h:inputText/><BR>
Password: <h:inputSecret/><BR>
<h:commandButton value="Sign Me Up!" action="register"/>
</h:form>
</CENTER></BODY></HTML>
</f:view>

12 J2EE training and tutorials: http://www.coreservlets.com

Step 3: Specify Action Controller


• Use the action attribute of h:commandButton
• For most real cases, you specify a method to be
called when form is submitted
– The method returns various strings, and faces-config.xml maps the
strings to output pages
– See upcoming example for details
• For static navigation, you specify a simple string
– faces-config.xml maps the string to an output page
• Example
<h:form>
Email address: <h:inputText/><BR>
Password: <h:inputSecret/><BR>
<h:commandButton value="Sign Me Up!" action="register"/>
</h:form>

13 J2EE training and tutorials: http://www.coreservlets.com


Steps 2 & 3: Example Results
• File is tomcat_dir/webapps/jsf-test/register1.jsp
• URL is http://localhost/jsf-test/register1.faces

14 J2EE training and tutorials: http://www.coreservlets.com

Step 4: Create an Action


Controller
• Postponed until next section
– This example ignores form data and invokes no logic or
Java code of any sort

15 J2EE training and tutorials: http://www.coreservlets.com


Step 5: Update faces-config.xml
• General format
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE faces-config PUBLIC …>
<faces-config>

</faces-config>
• Specifying the navigation rule

<faces-config>
<navigation-rule>
<from-view-id>/the-input-form.jsp</from-view-id>
<navigation-case>
<from-outcome>string-from-action</from-outcome>
<to-view-id>/WEB-INF/…/something.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
16 J2EE training and tutorials: http://www.coreservlets.com

Step 5: Example Code


<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE faces-config PUBLIC …>
<faces-config>
<navigation-rule>
<from-view-id>/register1.jsp</from-view-id>
<navigation-case>
<from-outcome>register</from-outcome>
<to-view-id>/WEB-INF/results/result1.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>

17 J2EE training and tutorials: http://www.coreservlets.com


Step 6: Create Output JSP Page
• Note that RequestDispatcher.forward is
used behind the scenes
– So page can be in WEB-INF
• Example code:
– …/jsf-test/WEB-INF/results/result1.jsp
<!DOCTYPE …>
<HTML>
<HEAD>…</HEAD>
<BODY>
<CENTER>
<TABLE BORDER=5>
<TR><TH CLASS="TITLE">Success</TH></TR>
</TABLE>
<H2>You have registered successfully.<BR>
(Version 1)</H2>
</CENTER>
</BODY></HTML>
18 J2EE training and tutorials: http://www.coreservlets.com

Step 6: Example Result


• Note that URL is unchanged

19 J2EE training and tutorials: http://www.coreservlets.com


Step 7: Protect Raw JSP Pages
• Filename/URL correspondence
– Actual files are of the form blah.jsp
– URLs used are of the form blah.faces
– You must prevent clients from directly accessing JSP
pages
• Since they would give erroneous results
• Strategies
– You cannot put JSP pages in WEB-INF
• Because URL must correspond directly to file location
– So, use security-constraint entries in web.xml. But:
• Clumsy
• Easy to forget
• Results in confusing error messages
• This is a major drawback to JSF design
20 J2EE training and tutorials: http://www.coreservlets.com

Step 7: Example Code



<web-app>

<security-constraint>
<display-name>
Prevent access to raw JSP pages that are for JSF pages.
</display-name>
<web-resource-collection>
<web-resource-name>Raw-JSF-JSP-Pages</web-resource-name>
<!-- Add url-pattern for EACH raw JSP page -->
<url-pattern>/welcome.jsp</url-pattern>
<url-pattern>/register1.jsp</url-pattern>

</web-resource-collection>
<auth-constraint>
<description>No roles, so no direct access</description>
</auth-constraint>
</security-constraint>
</web-app>

21 J2EE training and tutorials: http://www.coreservlets.com


Step 7: Example Results
• In Tomcat, results in confusing error message
• Cannot easily use error-page and error-code to
make a better error page
– Since 500 status code used for many other Tomcat errors

22 J2EE training and tutorials: http://www.coreservlets.com

Example 2: Dynamic Navigation


• Original URL will be
http://hostname/jsf-test/signup.faces
– Collects info to see if user qualifies for health plan
• When form submitted, one of two possible
results will be displayed
– User is accepted into health plan
– User is rejected from health plan
• Main points
– Specifying an action controller
– Creating an action controller
– Using faces-config.xml to
• Declare controller
• Map results to output pages
23 J2EE training and tutorials: http://www.coreservlets.com
Main Points of This Example
• Specify the controller with #{controllerName.methodName}
<h:commandButton
value="Sign Me Up!"
action="#{healthPlanController.register}"/>
• Controller method returns strings corresponding to conditions
– If null is returned, the form is redisplayed
– Unlike with Struts, the controller need not extend a special class
• Use faces-config.xml to declare the controller as follows
<faces-config>
<managed-bean>
<managed-bean-name>controller name</managed-bean-name>
<managed-bean-class>controller class</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>
• Add multiple navigation-rule entries to faces-config.xml
– One for each possible string returned by the controller
– If no string matches, the form is redisplayed

24 J2EE training and tutorials: http://www.coreservlets.com

Step 1: Create Form Bean


• Step 1: Create Form Bean
– Postponed until next section
• In this example, we ignore all input data
– Modeled accurately after real health insurance practices

25 J2EE training and tutorials: http://www.coreservlets.com


Step 2: Create Input Form
• Same general syntax as in previous example
– Except for action of commandButton
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<f:view>

<h:form>
First name: <h:inputText/><BR>
Last name: <h:inputText/><BR>
...
<h:commandButton
value="Sign Me Up!"
action="#{healthPlanController.signup}"/>
</h:form>…
</f:view>

26 J2EE training and tutorials: http://www.coreservlets.com

Step 3: Specify Action


Controller
• Use action attribute of h:commandButton
• Specify #{controllerName.methodName}
– The designated method takes no args and returns various
strings. faces-config.xml maps the strings to output pages
– The controller must be declared with a managed-beans
entry in faces-config.xml
• Example
<h:form>
First name: <h:inputText/><BR>
Last name: <h:inputText/><BR>...
<h:commandButton
value="Sign Me Up!"
action="#{healthPlanController.signup}"/>
</h:form>

27 J2EE training and tutorials: http://www.coreservlets.com


Steps 2 & 3: Example Results
• File is tomcat_dir/webapps/jsf-test/signup.jsp
• URL is http://localhost/jsf-test/signup.faces

28 J2EE training and tutorials: http://www.coreservlets.com

Step 4: Create an Action Controller


• Does not need to extend any particular
class
– Unlike Struts
• The designated method takes no arguments
and returns a String
– Each string should correspond to navigation rule in
faces-config.xml
– Returning null indicates that the original form should be
redisplayed
• Most controllers access request parameters
via beans
– Covered in next section
– Now, our business logic will be independent of input data
29 J2EE training and tutorials: http://www.coreservlets.com
Step 4: Example Code
package coreservlets;

public class HealthPlanController {


public String signup() {
if (Math.random() < 0.2) {
return("accepted");
} else {
return("rejected");
}
}
}

30 J2EE training and tutorials: http://www.coreservlets.com

Step 5: Update faces-config.xml


• Declaring action controller

<faces-config>
<managed-bean>
<managed-bean-name>
healthPlanController
</managed-bean-name>
<managed-bean-class>
coreservlets.HealthPlanController
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

</faces-config>

31 J2EE training and tutorials: http://www.coreservlets.com


Step 5: Update faces-config.xml
• Specifying navigation rules
– Outcomes should match return values of controller

<faces-config>

<navigation-rule>
<from-view-id>/signup.jsp</from-view-id>
<navigation-case>
<from-outcome>accepted</from-outcome>
<to-view-id>/WEB-INF/results/accepted.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>rejected</from-outcome>
<to-view-id>/WEB-INF/results/rejected.jsp</to-view-id>
</navigation-case>
</navigation-rule>

</faces-config>

32 J2EE training and tutorials: http://www.coreservlets.com

Step 6: Create Output JSP


Pages
• …/jsf-test/WEB-INF/results/accepted.jsp
<!DOCTYPE …>
<HTML>
<HEAD>…</HEAD>
<BODY>
<CENTER>
<TABLE BORDER=5>
<TR><TH CLASS="TITLE">Accepted!</TH></TR>
</TABLE>
<H2>You are accepted into our health plan.</H2>
Congratulations.
</CENTER>
</BODY></HTML>

33 J2EE training and tutorials: http://www.coreservlets.com


Step 6: Create Output JSP
Pages
• …/jsf-test/WEB-INF/results/rejected.jsp
<!DOCTYPE …>
<HTML>
<HEAD>…</HEAD>
<BODY>
<CENTER>
<TABLE BORDER=5>
<TR><TH CLASS="TITLE">Rejected!</TH></TR>
</TABLE>
<H2>You are rejected from our health plan.</H2>
Get lost.
</CENTER>
</BODY></HTML>

34 J2EE training and tutorials: http://www.coreservlets.com

Step 6: Results

35 J2EE training and tutorials: http://www.coreservlets.com


Step 7: Protect Raw JSP Pages

<web-app>

<security-constraint>
<display-name>
Prevent access to raw JSP pages that are for JSF pages.
</display-name>
<web-resource-collection>
<web-resource-name>Raw-JSF-JSP-Pages</web-resource-name>
<!-- Add url-pattern for EACH raw JSP page -->
<url-pattern>/welcome.jsp</url-pattern>
<url-pattern>/register1.jsp</url-pattern>
<url-pattern>/signup.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<description>No roles, so no direct access</description>
</auth-constraint>
</security-constraint>
</web-app>

36 J2EE training and tutorials: http://www.coreservlets.com

Example 3:
Reading Request Data Manually
• Original URL will be
http://hostname/jsf-test/register2.faces
• When form submitted, one of three possible
results will be displayed
– Error message re illegal email address
– Error message re illegal password
– Success
• Main points
– Reading request data "by hand" in action controller

37 J2EE training and tutorials: http://www.coreservlets.com


Main Points of This Example
• Most real JSF apps use form beans
– Java classes that are created automatically and
automatically populated based on incoming request
parameters
• See next section
• This example reads by hand
– Requires slightly obscure code
• See next slide
– Done moderately frequently in real apps
• To read request headers or to access scoped variables that
are not related to form bean

38 J2EE training and tutorials: http://www.coreservlets.com

Step 1: Create Form Bean


• Postponed until next section
– This example reads form data the old fashioned way:
by directly calling request.getParameter.
– To do so, you first look up the ExternalContext, which
gives you access to the standard servlet and JSP objects
(request, response, ServletContext, session, etc.) Eg:
ExternalContext context =
FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest request =
(HttpServletRequest)context.getRequest();
String param1 = request.getParameter("name1");
– The ExternalContext also has methods to access params
and other data out hash tables.
• Request data
– getRequestParameterMap, getRequestCookieMap,
getRequestHeaderMap, etc
• Scoped variables
39 – getRequestMap, getSessionMap, getApplicationMap
J2EE training and tutorials: http://www.coreservlets.com
Step 2: Create Input Form
• Same as previous example, except
– h:form is given an id attribute
– h:inputText and h:inputSecret are also given an id
– The actual request param name is formID:elementID
• Only needed if you read request params manually!
• Example code
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<f:view>

<h:form id="form2">
Email address: <h:inputText id="email"/><BR>
Password: <h:inputSecret id="password"/><BR>
<h:commandButton value="Sign Me Up!"
action="#{registrationController.register}"/>
</h:form>…
</f:view>

40 J2EE training and tutorials: http://www.coreservlets.com

Step 3: Specify Action


Controller
• Use the action attribute of
h:commandButton
• Specify #{controllerName.methodName}
– Same as last example
• The designated method takes no args and returns various
strings. faces-config.xml maps the strings to output pages
• The controller must be declared with a managed-beans
entry in faces-config.xml
• Example
<h:form id="form2">
Email address: <h:inputText id="email"/><BR>
Password: <h:inputSecret id="password"/><BR>
<h:commandButton value="Sign Me Up!"
action="#{registrationController.register}"/>
</h:form>

41 J2EE training and tutorials: http://www.coreservlets.com


Steps 2 & 3: Example Results
• File is tomcat_dir/webapps/jsf-test/register2.jsp
• URL is http://localhost/jsf-test/register2.faces

42 J2EE training and tutorials: http://www.coreservlets.com

Step 4: Create an Action Controller


• Does not need to extend any particular
class
– Unlike Struts
• The designated method takes no arguments
and returns a String
– Each string should correspond to navigation rule in
faces-config.xml
– Returning null indicates that the original form should be
redisplayed
• Most controllers access request parameters
via beans
– We have not covered this yet
– We will use the manual approach via the ExternalContext
– ExternalContext useful in real life anyhow
• Cookies, session data, request headers, etc.
43 J2EE training and tutorials: http://www.coreservlets.com
Step 4: Example Code
package coreservlets;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.faces.context.*;

public class RegistrationController {


public String register() {
ExternalContext context =
FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest request =
(HttpServletRequest)context.getRequest();
String email = request.getParameter("form2:email");
String password = request.getParameter("form2:password");
if ((email == null) ||
(email.trim().length() < 3) ||
(email.indexOf("@") == -1)) {
return("bad-address");
} else if ((password == null) ||
(password.trim().length() < 6)) {
return("bad-password");
} else {
return("success");
44 }}} J2EE training and tutorials: http://www.coreservlets.com

Step 5: Update faces-config.xml


• Declaring action controller

<faces-config>
<managed-bean>
<managed-bean-name>
registrationController
</managed-bean-name>
<managed-bean-class>
coreservlets.RegistrationController
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

</faces-config>

45 J2EE training and tutorials: http://www.coreservlets.com


Step 5: Update faces-config.xml
• Specifying navigation rules
– Outcomes should match return values of action

<faces-config>

<navigation-rule>
<from-view-id>/register2.jsp</from-view-id>
<navigation-case>
<from-outcome>bad-address</from-outcome>
<to-view-id>/WEB-INF/results/bad-address2.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>bad-password</from-outcome>
<to-view-id>/WEB-INF/results/bad-password2.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/WEB-INF/results/result2.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>

46 J2EE training and tutorials: http://www.coreservlets.com

Step 6: Create Output JSP


Pages
• …/jsf-test/WEB-INF/results/bad-address2.jsp
<!DOCTYPE …>
<HTML>
<HEAD>…</HEAD>
<BODY>
<CENTER>
<TABLE BORDER=5>
<TR><TH CLASS="TITLE">Illegal Email Address</TH></TR>
</TABLE>
<P>
Address must be of the form username@host.
Please <A HREF="register2.faces">try again</A>.
</CENTER>
</BODY></HTML>

47 J2EE training and tutorials: http://www.coreservlets.com


Step 6: Example Result for Bad
Email Address
• Input

48 J2EE training and tutorials: http://www.coreservlets.com

Step 6: Example Result for Bad


Email Address
• Output

49 J2EE training and tutorials: http://www.coreservlets.com


Step 6: Create Output JSP
Pages
• …/jsf-test/WEB-INF/results/bad-
password2.jsp
<!DOCTYPE …>
<HTML>
<HEAD>…</HEAD>
<BODY>
<CENTER>
<TABLE BORDER=5>
<TR><TH CLASS="TITLE">Illegal Password</TH></TR>
</TABLE>
<P>
Password must contain at least six characters.
Please <A HREF="register2.faces">try again</A>.
</CENTER>
</BODY></HTML>

50 J2EE training and tutorials: http://www.coreservlets.com

Step 6: Example Result for Bad


Password
• Input

51 J2EE training and tutorials: http://www.coreservlets.com


Step 6: Example Result for Bad
Password
• Output

52 J2EE training and tutorials: http://www.coreservlets.com

Step 6: Create Output JSP


Pages
• …/jsf-test/WEB-INF/results/result2.jsp
<!DOCTYPE …>
<HTML>
<HEAD>…</HEAD>
<BODY>
<CENTER>
<TABLE BORDER=5>
<TR><TH CLASS="TITLE">Success</TH></TR>
</TABLE>
<H2>You have registered successfully.<BR>
(Version 2)</H2>
</CENTER>
</BODY></HTML>

53 J2EE training and tutorials: http://www.coreservlets.com


Step 6: Example Result for
Good Input
• Input

54 J2EE training and tutorials: http://www.coreservlets.com

Step 6: Example Result for


Good Input
• Output

55 J2EE training and tutorials: http://www.coreservlets.com


Step 7: Protect Raw JSP Pages

<web-app>

<security-constraint>
<display-name>
Prevent access to raw JSP pages that are for JSF pages.
</display-name>
<web-resource-collection>
<web-resource-name>Raw-JSF-JSP-Pages</web-resource-name>
<!-- Add url-pattern for EACH raw JSP page -->
<url-pattern>/welcome.jsp</url-pattern>
<url-pattern>/register1.jsp</url-pattern>
<url-pattern>/signup.jsp</url-pattern>
<url-pattern>/register2.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<description>No roles, so no direct access</description>
</auth-constraint>
</security-constraint>
</web-app>

56 J2EE training and tutorials: http://www.coreservlets.com

Value-Change Listeners
• All our examples used action attribute of
h:commandButton
– Specifies code to run when form is submitted
• How to respond to finer-grained events?
– Textfield value has changed
• E.g., fill in state automatically when ZIP code is entered
– New list entry has been selected
• Necessary ingredients
– Specify code that should run
• <h:inputText valueChangeListener="#{bean.method}"…/>
• Note that code runs before action controller
– Force form to be submitted when events occur
• <h:inputText valueChangeListener="#{bean.method}"
onclick="submit()" …/>
57 J2EE training and tutorials: http://www.coreservlets.com
Summary
• Basic steps to using JSF
– Create a bean to represent the form data
– Use f:view and h:form to create an input form
– Specify action controller with action of h:commandButton
– Create an action controller
– Use faces-config.xml to declare form bean and navigation rules
– Create JSP pages corresponding to each return condition
– Protect raw JSP pages from access
• Static navigation
– Specify outcome as action of button
• Outcome mapped by faces-config.xml to output page
• Dynamic navigation
– Specify method as action of button
– Method returns outcomes
• Outcomes mapped by faces-config.xml to output pages

58 J2EE training and tutorials: http://www.coreservlets.com

© 2005 Marty Hall

Questions?

Core Servlets & JSP book: www.coreservlets.com


More Servlets & JSP book: www.moreservlets.com
Servlet/JSP/Struts/JSF Training: courses.coreservlets.com
http://courses.coreservlets.com/ -- Hands-on, customized training for Java, servlets, JSP, Struts, and JSF.

You might also like