You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by hu...@apache.org on 2006/03/31 00:08:42 UTC
svn commit: r390256 - in /struts/sandbox/trunk/action2: ./
apps/mailreader/src/java/ apps/mailreader/src/java/mailreader2/
apps/mailreader/src/webapp/pages/
Author: husted
Date: Thu Mar 30 14:08:42 2006
New Revision: 390256
URL: http://svn.apache.org/viewcvs?rev=390256&view=rev
Log:
Action2 Apps
* README - Add notes for new cookbook examples and new features (culled from WW Forum)
* Mailreader Tour
** Up to Logon-validation.xml
Modified:
struts/sandbox/trunk/action2/README.txt
struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/Constants.java
struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/MailreaderSupport.java
struts/sandbox/trunk/action2/apps/mailreader/src/java/xwork.xml
struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/Logon.jsp
struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/tour.html
Modified: struts/sandbox/trunk/action2/README.txt
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/action2/README.txt?rev=390256&r1=390255&r2=390256&view=diff
==============================================================================
--- struts/sandbox/trunk/action2/README.txt (original)
+++ struts/sandbox/trunk/action2/README.txt Thu Mar 30 14:08:42 2006
@@ -74,6 +74,25 @@
* Using proxy objects to restrict access to domain objects
** http://forums.opensymphony.com/thread.jspa?threadID=23750&tstart=0
+* Using an authentification interceptor.
+**
+
+* Overriding a bundled UI Tag.
+
+* Creating a custom UI Tag.
+
+* Canceling a form with client-side validation.
+** (Should there be a "validate" attribute to generate the "form.onsubmit=null" script?)
+** (Should ActionSupport provide "public String cancel() {return CANCEL;} ?
+** (Should we support action="!cancel" to be consistent with form tag.)
+*** (Trying !cancel in WW2.2.2 carries cancel over to the next action.)
+
+* Setting form type to "POST"
+** (Should POST be the default?)
+
+* DRY UI Tags
+** http://forums.opensymphony.com/thread.jspa?threadID=24140&tstart=0
+
----
Examples that might involve new development
Modified: struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/Constants.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/Constants.java?rev=390256&r1=390255&r2=390256&view=diff
==============================================================================
--- struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/Constants.java (original)
+++ struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/Constants.java Thu Mar 30 14:08:42 2006
@@ -26,6 +26,11 @@
// --- Tokens ----
/**
+ * <p> The token representing a "cancel" request. </p>
+ */
+ public static final String CANCEL = "cancel";
+
+ /**
* <p> The token representing a "create" task. </p>
*/
public static final String CREATE = "Create";
Modified: struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/MailreaderSupport.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/MailreaderSupport.java?rev=390256&r1=390255&r2=390256&view=diff
==============================================================================
--- struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/MailreaderSupport.java (original)
+++ struts/sandbox/trunk/action2/apps/mailreader/src/java/mailreader2/MailreaderSupport.java Thu Mar 30 14:08:42 2006
@@ -52,6 +52,15 @@
public class MailreaderSupport extends ActionSupport
implements SessionAware, ApplicationAware {
+ /**
+ * Return CANCEL so apropriate result can be selected.
+ * @return "cancel" so apropriate result can be selected.
+ */
+ public String cancel() {
+ return Constants.CANCEL;
+ }
+
+
// ---- ApplicationAware ----
/**
Modified: struts/sandbox/trunk/action2/apps/mailreader/src/java/xwork.xml
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/action2/apps/mailreader/src/java/xwork.xml?rev=390256&r1=390255&r2=390256&view=diff
==============================================================================
--- struts/sandbox/trunk/action2/apps/mailreader/src/java/xwork.xml (original)
+++ struts/sandbox/trunk/action2/apps/mailreader/src/java/xwork.xml Thu Mar 30 14:08:42 2006
@@ -52,6 +52,7 @@
<result type="redirect-action">MainMenu</result>
<result name="input">/pages/Logon.jsp</result>
<result name="expired" type="chain">ChangePassword</result>
+ <result name="cancel" type="redirect-action">Welcome</result>
</action>
<action name="ChangePassword">
Modified: struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/Logon.jsp
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/Logon.jsp?rev=390256&r1=390255&r2=390256&view=diff
==============================================================================
--- struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/Logon.jsp (original)
+++ struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/Logon.jsp Thu Mar 30 14:08:42 2006
@@ -15,13 +15,13 @@
<saf:form method="POST" validate="true">
<saf:textfield label="%{getText('username')}" name="username"/>
- <saf:password label="%{getText('password')}" name="password"/>
+ <saf:password label="%{getText('password')}" name="password" showPassword="true"/>
<saf:submit value="%{getText('button.save')}"/>
<saf:reset value="%{getText('button.reset')}"/>
- <saf:submit action="Welcome" value="%{getText('button.cancel')}"
+ <saf:submit action="Logon!cancel" value="%{getText('button.cancel')}"
onclick="form.onsubmit=null"/>
</saf:form>
Modified: struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/tour.html
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/tour.html?rev=390256&r1=390255&r2=390256&view=diff
==============================================================================
--- struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/tour.html (original)
+++ struts/sandbox/trunk/action2/apps/mailreader/src/webapp/pages/tour.html Thu Mar 30 14:08:42 2006
@@ -3,10 +3,8 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
- <meta name="generator"
- content="HTML Tidy for Windows (vers 1st July 2003), see www.w3.org"/>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"/>
- <link rel="stylesheet" type="text/css" href="../mailreader.css"/>
+ <link rel="stylesheet" type="text/css" href="../css/mailreader.css"/>
<title>A Walking Tour of the Action 2 MailReader Application</title>
</head>
@@ -66,19 +64,17 @@
</li>
<li>
- <a href="#Logon.jsp">Logon.jsp</a>
- </li>
+ <a href="#Logon.jsp">Logon Page</a>
+ <ul>
- <li>
- <a href="#Logon.jsp">Logon.jsp</a>
+ <li><a href="#Logon-validation.xml">Logon-validation.xml</a></li>
+
+ <li><a href="#Logon.java">Logon.java</a></li>
- <ul>
<li><a href="#xwork.xml">xwork.xml</a></li>
<li><a href="#MailreaderSupport">MailreaderSupport</a></li>
- <li><a href="#Logon.java">Logon.java</a></li>
-
</ul>
</li>
@@ -190,42 +186,42 @@
<hr/>
<h5>web.xml - The Web Application Deployment Descriptor</h5>
<pre><code><?xml version="1.0" encoding="ISO-8859-1"?>
-<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd">
-<web-app>
-
- <display-name>Action2 Mailreader</display-name>
-
-<strong> <filter>
- <filter-name>Action2</filter-name>
- <filter-class>
- com.opensymphony.webwork.dispatcher.FilterDispatcher
- </filter-class>
- </filter></strong>
+ <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+ "http://java.sun.com/dtd/web-app_2_3.dtd">
+ <web-app>
+
+ <display-name>Action2 Mailreader</display-name>
+
+ <strong> <filter>
+ <filter-name>Action2</filter-name>
+ <filter-class>
+ com.opensymphony.webwork.dispatcher.FilterDispatcher
+ </filter-class>
+ </filter></strong>
- <filter-mapping>
+ <filter-mapping>
<filter-name><strong>Action2</strong></filter-name>
<url-pattern>/*</url-pattern>
- </filter-mapping>
+ </filter-mapping>
- <listener>
+ <listener>
<listener-class>
- org.springframework.web.context.ContextLoaderListener
+ org.springframework.web.context.ContextLoaderListener
</listener-class>
- </listener>
+ </listener>
- <!-- Application Listener for MailReader database -->
- <listener>
+ <!-- Application Listener for MailReader database -->
+ <listener>
<listener-class>
- mailreader2.ApplicationListener
+ mailreader2.ApplicationListener
</listener-class>
- </listener>
+ </listener>
- <welcome-file-list>
+ <welcome-file-list>
<welcome-file>index.html</welcome-file>
- </welcome-file-list>
+ </welcome-file-list>
-</web-app></code></pre>
+ </web-app></code></pre>
<hr/>
<p>
@@ -283,12 +279,12 @@
<hr/>
<h5>MailReader's index.html</h5>
<pre><code><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<html><head>
- <META HTTP-EQUIV="Refresh" CONTENT="0;<strong>URL=Welcome.do</strong>">
-</head>
-<body>
- <p>Loading ...</p>
-</body></html></code></pre>
+ <html><head>
+ <META HTTP-EQUIV="Refresh" CONTENT="0;<strong>URL=Welcome.do</strong>">
+ </head>
+ <body>
+ <p>Loading ...</p>
+ </body></html></code></pre>
<hr/>
<p>
@@ -309,8 +305,8 @@
<hr/>
<h5>A simple "forward thru" action element</h5>
<pre><code> <action name="<strong>>Welcome</strong>">
- <result><strong>/pages/Welcome.jsp</strong></result>
-</action></code></pre>
+ <result><strong>/pages/Welcome.jsp</strong></result>
+ </action></code></pre>
<hr/>
<p>
@@ -367,7 +363,6 @@
<p>
OK ... but why would a Welcome Action want to choose between "success" and
"error"?
-
</p>
<p>
@@ -393,29 +388,29 @@
<h5>The Welcome Action class</h5>
<pre><code>package mailreader2;
-public class Welcome extends MailreaderSupport {
+ public class Welcome extends MailreaderSupport {
- public String execute() throws Exception {
+ public String execute() throws Exception {
// Confirm message resources loaded
String message = getText(Constants.ERROR_DATABASE_MISSING);
if (Constants.ERROR_DATABASE_MISSING.equals(message)) {
- addActionError(Constants.ERROR_MESSAGES_NOT_LOADED);
+ addActionError(Constants.ERROR_MESSAGES_NOT_LOADED);
}
// Confirm database loaded
if (null==getDatabase()) {
- addActionError(Constants.ERROR_DATABASE_NOT_LOADED);
+ addActionError(Constants.ERROR_DATABASE_NOT_LOADED);
}
if (hasErrors()) {
- return ERROR;
+ return ERROR;
}
else {
- return SUCCESS;
+ return SUCCESS;
+ }
}
- }
-}</code></pre>
+ }</code></pre>
<hr/>
<p>
@@ -438,10 +433,10 @@
<hr/>
<h5>MailReader's global-result element</h5>
<pre><code> <global-results>
- <result name=<strong>"error"</strong>><strong>/pages/Error.jsp</strong></result>
- <result name="invalid.token">/pages/Error.jsp</result>
- <result name="login" type="redirect-action">Logon!input</result>
-</global-results></code></pre>
+ <result name=<strong>"error"</strong>><strong>/pages/Error.jsp</strong></result>
+ <result name="invalid.token">/pages/Error.jsp</result>
+ <result name="login" type="redirect-action">Logon!input</result>
+ </global-results></code></pre>
<hr/>
<p>
@@ -467,10 +462,10 @@
<hr/>
<h5>mailreader2.ApplicationListener</h5>
<pre><code> <listener>
- <listener-class>
+ <listener-class>
<strong>mailreader2.ApplicationListener</strong>
- </listener-class>
-</listener></code></pre>
+ </listener-class>
+ </listener></code></pre>
<hr/>
<p>
@@ -493,18 +488,18 @@
<hr/>
<h5>The "seed" user element from the MailReader database.xml</h5>
<pre><code><user username="<strong>user</strong>" fromAddress="John.User@somewhere.com"
- fullName="<strong>John Q. User</strong>" password="pass">
- <subscription host="mail.hotmail.com" autoConnect="false"
- password="bar" type="pop3" username="user1234">
- </subscription>
- <subscription host="mail.yahoo.com" autoConnect="false" password="foo"
+ fullName="<strong>John Q. User</strong>" password="pass">
+ <subscription host="<strong>mail.hotmail.com"</strong> autoConnect="false"
+ password="bar" type="pop3" username="user1234">
+ </subscription>
+ <subscription host="<strong>mail.yahoo.com</strong>" autoConnect="false" password="foo"
type="imap" username="jquser">
- </subscription></user></code></pre>
+ </subscription></user></code></pre>
<hr/>
<p>
The "seed" user element creates a registration record for "John Q. User",
- with the detail for his hotmail account (or "subscription").
+ with the subscription detail for his hotmail and yahoo accounts.
</p>
<h4><a name="resources.properties" id="resources.properties">Message Resources</a>
@@ -512,15 +507,16 @@
<p>
As mentioned, MailReader is an internationlized application.
- The message resources for the application are loaded through a reference in the webwork.properites file.
- Like the database contents, the webwork.propeties file is kept under
- /src/java/webwork.properties.
+ The message resources for the application are loaded through a reference in the
+ webwork.properites file.
+ Like the database contents, the webwork.properties file is kept under
+ /src/java/ in the source tree.
</p>
<hr/>
<h5>webwork.properties</h5>
<pre><code>webwork.custom.i18n.resources = <strong>resources</strong>
-webwork.action.extension = <strong>do</strong></code></pre>
+ webwork.action.extension = <strong>do</strong></code></pre>
<hr/>
<p>
@@ -543,10 +539,10 @@
<hr/>
<h5>Message Resource entries used by the Welcome page</h5>
<pre><code><strong>index.heading=</strong>MailReader Application Options
-<strong>index.logon=</strong>Log on to the MailReader Application
-<strong>index.registration=</strong>Register with the MailReader Application
-<strong>index.title=</strong>MailReader Demonstration Application
-<strong>index.tour=</strong>A Walking Tour of the MailReader Demonstration Application</code></pre>
+ <strong>index.logon=</strong>Log on to the MailReader Application
+ <strong>index.registration=</strong>Register with the MailReader Application
+ <strong>index.title=</strong>MailReader Demonstration Application
+ <strong>index.tour=</strong>A Walking Tour of the MailReader Demonstration Application</code></pre>
<hr/>
<h4><a name="Welcome.jsp" id="Welcome.jsp">Welcome Page</a></h4>
@@ -558,45 +554,45 @@
<hr/>
<h5>Welcome.jsp</h5>
<pre><code><%@ page contentType="text/html; charset=UTF-8" %>
-<strong><%@ taglib uri="/webwork" prefix="saf" %></strong>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
+ <strong><%@ taglib uri="/webwork" prefix="saf" %></strong>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title><strong><saf:text name="index.title"/></strong></title>
<link href="<strong><saf:url value="/css/mailreader.css"/></strong>" rel="stylesheet"
type="text/css"/>
- </head>
+ </head>
- <body>
+ <body>
<h3><saf:text name="index.heading"/></h3>
<ul>
- <li><a href="<saf:url action="Registration!input"/>"><saf:text
- name="index.registration"/></a></li>
- <li><a href="<saf:url action="Logon!input"/>"><saf:text
- name="index.logon"/></a></li>
+ <li><a href="<saf:url action="Registration!input"/>"><saf:text
+ name="index.registration"/></a></li>
+ <li><a href="<saf:url action="Logon!input"/>"><saf:text
+ name="index.logon"/></a></li>
</ul>
<h3>Language Options</h3>
<ul>
- <li><a href="<saf:url action="Welcome?request_locale=en"/>">English</a></li>
- <li><a href="<saf:url action="Welcome?request_locale=ja"/>">Japanese</a></li>
- <li><a href="<saf:url action="Welcome?request_locale=ru"/>">Russian</a></li>
+ <li><a href="<saf:url action="Welcome?request_locale=en"/>">English</a></li>
+ <li><a href="<saf:url action="Welcome?request_locale=ja"/>">Japanese</a></li>
+ <li><a href="<saf:url action="Welcome?request_locale=ru"/>">Russian</a></li>
</ul>
<hr/>
<p><strong><saf:i18n name="alternate"></strong>
- <img src="<saf:text name="struts.logo.path"/>"
- alt="<saf:text name="struts.logo.alt"/>"/>
- </saf:i18n></p>
+ <img src="<saf:text name="struts.logo.path"/>"
+ alt="<saf:text name="struts.logo.alt"/>"/>
+ <strong></saf:i18n></strong></p>
<p><a href="<saf:url action="Tour" />"><saf:text name="index.tour"/></a></p>
</body>
- </html></code></pre>
+ </html></code></pre>
<hr/>
<p>
@@ -696,356 +692,220 @@
<p>
Note that both the username and password are case sensitive.
Better yet, try omitting or misspelling the username and password in
- various combinations to
- see how the application reacts.
+ various combinations to see how the application reacts.
</p>
<hr/>
<h5>Login.jsp</h5>
-<pre><code><%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
- <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
-
- <html:xhtml/>
- <html>
- <head>
- <title><bean:message key="logon.title"/></title>
- </head>
-
- <<strong>html:errors</strong>/>
-
- <<strong>html:form</strong> action="/SubmitLogon" focus="username"
- onsubmit="return validateLogonForm(this);">
- <table border="0" width="100%">
-
- <tr>
- <th align="right">
- <bean:message key="prompt.username"/>:
- </th>
- <td align="left">
- <<strong>html:text</strong> property="username" size="16"
- maxlength="18"/>
- </td>
- </tr>
-
- <tr>
- <th align="right">
- <bean:message key="prompt.password" bundle="alternate"/>:
- </th>
- <td align="left">
- <<strong>html:password</strong> property="password" size="16"
- maxlength="18"
- redisplay="false"/>
- </td>
- </tr>
+<pre><code><%@ page contentType="text/html; charset=UTF-8" %>
+<%@ taglib uri="/webwork" prefix="saf" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title><saf:text name="logon.title"/></title>
+ <link href="<saf:url value="/css/mailreader.css"/>" rel="stylesheet"
+ type="text/css"/>
+ </head>
- <tr>
- <td align="right">
- <<strong>html:submit</strong> property="Submit" value="Submit"/>
- </td>
- <td align="left">
- <<strong>html:reset</strong>/>
- </td>
- </tr>
+ <body onLoad="self.focus();document.Logon.username.focus()">
- </table>
+ <strong><saf:actionerror/></strong>
+ <strong><saf:form method="POST" validate="true"></strong>
- </html:form>
+ <strong><saf:textfield label="%{getText('username')}" name="username"/></strong>
+ <strong><saf:password label="%{getText('password')}" name="password"/></strong>
+ <strong><saf:submit value="%{getText('button.save')}"/></strong>
+ <strong><saf:reset value="%{getText('button.reset')}"/></strong>
+ <saf:submit <strong>action="Logon!cancel" onclick="form.onsubmit=null"</strong>
+ value="%{getText('button.cancel')}"/>
- <<strong>html:javascript</strong> formName="LogonForm"
- dynamicJavascript="true"
- staticJavascript="false"/>
- <script language="Javascript1.1" src="StaticJavascript.jsp"></script>
+ </saf:form>
- <jsp:include page="Footer.jsp" />
- </body>
- </html></code></pre>
+ <jsp:include page="Footer.jsp"/>
+ </body>
+</html></code></pre>
<hr/>
<p>
- We saw some of these tags on the Welcome page. Let's focus on the new
- tags.
+ We already saw some of the tags used by the Logon page on the Welcome page.
+ Let's focus on the new tags.
</p>
<p>
- The first new tag on the logon page is <strong>html:errors</strong>.
- The credentials you entered are validated and processed by a "LogonAction"
- class.
- If the credentials are incorrect,
- the LogonAction posts an appropriate error message and forwards back to
- the input page.
- If the html:errors tag sees that one or more messages were posted, the tag
- ouputs the messages to the page.
- The text of the messages can be specified in the MessageResource bundle,
- making them easy to localize.
+ The first new tag on the Logon page is <strong>actionerrors</strong>.
+ Most of the possible validation errors are related to a single field.
+ If you don't enter a username,
+ the framework can place an error message near the tag prompting you to
+ enter a username.
+ But some messages are not related to a single field.
+ For example, the database might be down.
+ If the action returns an "Action Error", as opposed to a "Field Error",
+ the message is rendered in place of the "actionerror" tag.
+ The text for the validation errors, whether they are Action Errors or
+ Field Errors, can be specified in the resource bundle,
+ making the messages easy to localize.
</p>
<p>
- The second new tag is <strong>html:form</strong>.
- This tag renders a html form tag.
- The "action" attribute tells the tag to use "SubmitLogon.do" for the
- form's action.
- The "focus" attribute tells the tag to generate a little Javascript into
- the form that
- sets its focus to the "username" field.
- The "onsubmit" attribute tells the form to run a Javascript when the form
- is submitted.
- (Just like the corresponding attribute on the standard form tag.)
+ The second new tag is <strong>form</strong>.
+ This tag renders a HTML form tag.
+ By default, the form will submit back to whatever action invoked the page.
+ The "validate=true" setting enables client-side validation,
+ so that the form can be validated with Javascript before being sent
+ back to the server.
+ The framework will still validate the form again, just to be sure, but the
+ client-side validation can save a few round-trips to the server.
+ You can use the method attribute to designate "GET" or "POST",
+ just like the HTML form tag.
</p>
<p>
- Within the html:form tag,
- we see five more new tags: "html:text", "html:password", "html:submit",
- "html:reset", and "html:javascript".
-</p>
-
-<p>
- The <strong>html:text</strong> tag renders a "input type=text" tag.
- The "property" attribute becomes the input tag's "name" attribute.
-</p>
-
-<p>
- The <strong>html:password</strong> tag renders a "input type=password"
- tag.
- The "redisplay" attribute tell the tag not to render the password back
- into the file, if the submit fails.
- The <strong>html:submit</strong> and <strong>html:reset</strong> tags
- render buttons of the corresponding types.
-</p>
-
-<p>
- Following the form is a <strong>html:javascript</strong> tag.
- This tag works with the Struts Validator component to generate a
- JavaScript that can validate input
- before it is submitted to the LogonAction.
-</p>
-
-<hr/>
-<h5>Tip:</h5>
-<blockquote>
- <p><font class="hint">
- Most of these tags have many more options than the ones we use in this
- application.
- For the complete documentation for each tag,
- see the Tag Developer Guides in the Struts Taglib documentation
- bundle.
- </font></p>
-</blockquote>
-<hr/>
-
-<p>
- But, how do these tags know so much?
- How does the Javascript tag know what scripts to write?
- How do the text and password tags know what values to redisplay?
+ Within the form tag,
+ we see five more new tags: "textfield", "password", "submit",
+ and "reset". We also see a second form of "submit" that utilizes an
+ "action" attribute.
</p>
<p>
- For the answers, we need to turn back to the Struts Action Framework
- configuration files,
- "struts-config.xml" and "validation.xml".
+ When we place a control on a form, we usually need to place a set of
+ HTML tags to do everything we want to do.
+ Usually, we do not just want a plain "input type=text" tag.
+ We want the input field to have a label too, and possibily
+ a tooltip. And, of course, a place to print a message
+ should invalid data be entered.
</p>
-<h4><a name="struts-config.xml" id="struts-config.xml">struts-config.xml</a>
-</h4>
-
<p>
- The Struts configuration file is parsed by the ActionServlet when the
- application first load.
+ The UI Tags support templates and themes so that a set of HTML tags can be
+ rendered from a single UI Tag. For example, the single tag
</p>
-<h5>web.xml -- Action Servlet Configuration</h5>
<pre><code>
- <servlet>
- <servlet-name>action</servlet-name>
- <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
- <init-param>
- <param-name>config</param-name>
- <param-value><strong>/WEB-INF/struts-config.xml</strong></param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
+ <saf:textfield label="%{getText('username')}" name="username"/>
</code></pre>
-<hr/>
-<h5>The SubmitLogon action element</h5>
-<pre><code> <!-- Process a user logon -->
- <action
- <strong>path="/SubmitLogon"</strong>
- type="org.apache.struts.apps.mailreader.actions.LogonAction"
- <strong>name</strong>="LogonForm"
- <strong>scope</strong>="request"
- <strong>validate</strong>="request"
- <strong>input</strong>="Logon">
- <<strong>exception</strong>
- key="expired.password"
- type="org.apache.struts.apps.mailreader.dao.ExpiredPasswordException"
- path="/ChangePassword.jsp"/>
- <forward
- name="Success"
- path="/MainMenu.do"/>
- </action></code></pre>
-<hr/>
-
<p>
- We saw the path and type attributes in the Welcome action.
- Let's look at the new attributes: "name", "scope", "input", and
- "exception".
+ generates a wad of HTML markup.
</p>
-<h4>The "name" attribute</h4>
+<hr/>
+<pre><code><tr>
+ <td class="tdLabel"><label for="Logon_username" class="label">Username:</label></td>
+ <td>
+ <input type="text" name="username" value="" id="Logon_username"/>
+ </td>
+</tr></code></pre>
+<hr/>
<p>
- The <strong>name</strong> attribute specifies something Struts Action
- calls an "ActionForm".
- The ActionForm buffers input from a form and delivers it to an Action
- class as an object.
- The ActionForm can also be used to validate input.
- If validation fails, the tags can rewrite the input values from the
- ActionForm.
+ If for some reason you don't like the markup generated by a UI Tag,
+ each tag is driven by an easy-to-edit template,
+ that can be updated on a tag-by-tag basis.
+ For example, here is the default template that generates the markup for the ActionErrors tag:
</p>
-<p>
- The ActionForms are defined in the "form-beans" section of struts-config.
-</p>
+<hr/>
+<pre><code><#if (actionErrors?exists && actionErrors?size > 0)>
+ <ul>
+ <#list actionErrors as error>
+ <li><span class="errorMessage">${error}</span></li>
+ </#list>
+ </ul>
+</#if></code></pre>
<p>
- ActionForms can be "conventional" or "dynamic".
- MailReader uses dynamic ActionForms.
- Rather than cobble up an actual JavaBean class,
- we specify the properties the ActionForm can accept in the configuration
- file.
+ If you wanted ActionErrors displayed in a table instead of a list,
+ you could edit a copy of this file, save it under the file name "actionerror.ftl",
+ and place this one file somewhere on your classpath.
</p>
<hr/>
-<h5>The form-bean element for LogonForm</h5>
-<pre><code> <!-- LogonAction form bean -->
- <form-bean
- name="LogonForm"
- <strong>extends="BaseForm"/></strong></code></pre>
+<pre><code><#if (actionErrors?exists && actionErrors?size > 0)>
+ <table>
+ <#list actionErrors as error>
+ <tr><td><span class="errorMessage">${error}</span></td></tr>
+ </#list>
+ </table>
+</#if></code></pre>
<hr/>
-<p>
- Hmmmm. That doesn't seem to tell us much.
- The LogonForm "extends" the BaseForm, but doesn't add any attributes.
- What about the BaseForm element that LogonForm extends?
-</p>
+ <p>
+ Under the covers, Struts Action 2 uses
+ <a href="http://freemarker.sourceforge.net/">Freemarker</a>
+ for its standard templating language.
+ FreeMarker is similar to
+ <a href="http://jakarta.apache.org/velocity/">Velocity</a>,
+ but offers better error reporting and some additional features.
+ If you prefer, Velocity and JSP templates can also be used to create your own UI Tags.
+ </p>
-<hr/>
-<h5>BaseForm - An "abstract" form-bean</h5>
-<pre><code> <!-- BaseAction form bean (abstract) -->
- <form-bean
- name="BaseForm"
- type="org.apache.struts.validator.DynaValidatorForm">
- <strong><form-property</strong>
- name="username"
- type="java.lang.String"/>
- <form-property
- name="password"
- type="java.lang.String"/>
- <form-property
- name="task"
- type="java.lang.String"
- initial="Create"/>
- </form-bean></code></pre>
-<hr/>
+ <p>
+ The <strong>password</strong> tag renders a "input type=password"
+ tag, along with the usual template/theme markup.
+ By default, the password tag will not retain input if the submit fails.
+ If the username is wrong,
+ the client will have to enter the password again too.
+ If you did want to retain the password when validation fails,
+ you can set the tag's "showPassword" property to true.
+ </p>
-<h5>Note:</h5>
-<blockquote>
- <p><font class="hint">
- <strong>Extends</strong> - In the Struts configuration file,
- we can use the "extends" attribute to adopt default settings from
- another element.
- Extends makes using XML elements more like object-orientated
- programming.
- You can setup a base element, and then only specify the behavior that
- changes.
- </font></p>
-</blockquote>
-<hr/>
+ <p>
+ Unsurprisingly, the <strong>submit</strong> and <strong>reset</strong> tags
+ render buttons of the corresponding types.
+ </p>
-<p>
- Struts creates the ActionForms automatically, regardless of whether the
- form-bean is conventional or dynamic.
- The ActionForm lets us specify which properties we want to extract from
- the incoming request.
- If a property is not specified by the ActionForm,
- the value is not automatically transferred from the request, validated,
- or passed to the Action class.
-</p>
+ <p>
+ The second submit button is more interesting.
+ </p>
-<h4>The "scope" attribute</h4>
+<pre><code> <saf:submit <strong>action="Logon!cancel" onclick="form.onsubmit=null"</strong>
+ value="%{getText('button.cancel')}"/>
+</code></pre>
-<p>
- The <strong>scope</strong> attribute in the "SubmitLogon" action element
- tells the controller whether to store the ActionForm in the request,
- rather than in the user's session.
-</p>
+ <p>
+ Here we are creating the Cancel button for the form.
+ The button's attribute <em>action="Logon!cancel"</em> tells the framework to submit
+ to the Logon's "cancel" method instead of the usual "execute" method.
+ The <em>onclick="form.onsubmit=null"</em> script defeats client-side validation.
+ On the server side, "cancel" is on a special lists of aliases that bypass validation,
+ so the request will go directly to the Action's cancel method.
+ (Other special aliases on the bypass list include "input" and "back".)
+ </p>
<hr/>
-<h5>Best Practice:</h5>
+<h5>Tip:</h5>
<blockquote>
<p><font class="hint">
- Use request scope for single-page forms that contain all the
- properties needed by the Action.
- There is usually no need to maintain form input across requests.
+ The UI tags have options and capabilities beyond what we have shown here.
+ For more see, the <a href="http://wiki.opensymphony.com/display/WW/Tags">UI Tag documentation.</a>
</font></p>
</blockquote>
<hr/>
-<h4>The "validate" attribute</h4>
-
<p>
- The <strong>validate</strong> attribute controls whether the framework
- will automatically validate
- the ActionForm.
- Conventional ActionForms have a stub "validate" method that you can
- implement.
- MailReader uses the Validator framework instead,
- so the validations are specified in another configuration file.
+ OK, but how do the UI Tags know that both of these fields are required?
+ How do they know what message to display when the fields are empty?
</p>
-<h4>The "input" attribute</h4>
-
<p>
- If validation fails, Struts looks for the forward specified by the
- <strong>input</strong> attribute.
- In this case, invoking the global "Logon" forward sends control back to
- the Logon page.
+ For the answers, we need to look at another flavor of Action 2 configuration file:
+ the "validation" file.
</p>
-<h4>The "exception" element</h4>
-
-<p>
- Within the SubmitLogon action element is another new element, <strong>
- exception</strong>.
- When a user logons on, it's possible that an "ExpiredPasswordException"
- will be thrown.
- Should this happen, Struts will catch the exception and send control to
- the "ChangePassword" action.
-</p>
-
-<hr/>
-<h5>Change Password screen</h5>
-<blockquote>
- <p>
- Your password has expired. Please ask the system administrator to
- change it. <u>Try Again</u>
- </p>
-</blockquote>
-<hr/>
+<h4><a name="Logon-validation.xml" id="Logon-validation.xml">Logon-validation.xml</a>
+</h4>
<p>
- OK, it's not the greatest "Change Password" screen -- but, remember, this
- is still the first iteration!
+ While it is not hard to code data-entry validation into an Action class,
+ the framework provides an even easier way to validate input.
</p>
-<h4><a name="validations.xml" id="validations.xml">validations.xml</a></h4>
-
<p>
In the Logon page, we mentioned that the html:javascript tag confers with
the Struts Validator components.
- The Validator is configured through another XML document, the <strong>
- validation.xml</strong>.
+ The validation framework is configured through another XML document, the <strong>
+ Logon-validation.xml</strong>.
</p>
<hr/>
@@ -1297,6 +1157,193 @@
and be very sure that everyone knows how to spell "Success". :)
</p>
+<h5>web.xml -- Action Servlet Configuration</h5>
+<pre><code>
+ <servlet>
+ <servlet-name>action</servlet-name>
+ <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
+ <init-param>
+ <param-name>config</param-name>
+ <param-value><strong>/WEB-INF/struts-config.xml</strong></param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+</code></pre>
+
+<hr/>
+<h5>The SubmitLogon action element</h5>
+<pre><code> <!-- Process a user logon -->
+ <action
+ <strong>path="/SubmitLogon"</strong>
+ type="org.apache.struts.apps.mailreader.actions.LogonAction"
+ <strong>name</strong>="LogonForm"
+ <strong>scope</strong>="request"
+ <strong>validate</strong>="request"
+ <strong>input</strong>="Logon">
+ <<strong>exception</strong>
+ key="expired.password"
+ type="org.apache.struts.apps.mailreader.dao.ExpiredPasswordException"
+ path="/ChangePassword.jsp"/>
+ <forward
+ name="Success"
+ path="/MainMenu.do"/>
+ </action></code></pre>
+<hr/>
+
+<p>
+ We saw the path and type attributes in the Welcome action.
+ Let's look at the new attributes: "name", "scope", "input", and
+ "exception".
+</p>
+
+<h4>The "name" attribute</h4>
+
+<p>
+ The <strong>name</strong> attribute specifies something Struts Action
+ calls an "ActionForm".
+ The ActionForm buffers input from a form and delivers it to an Action
+ class as an object.
+ The ActionForm can also be used to validate input.
+ If validation fails, the tags can rewrite the input values from the
+ ActionForm.
+</p>
+
+<p>
+ The ActionForms are defined in the "form-beans" section of struts-config.
+</p>
+
+<p>
+ ActionForms can be "conventional" or "dynamic".
+ MailReader uses dynamic ActionForms.
+ Rather than cobble up an actual JavaBean class,
+ we specify the properties the ActionForm can accept in the configuration
+ file.
+</p>
+
+<hr/>
+<h5>The form-bean element for LogonForm</h5>
+<pre><code> <!-- LogonAction form bean -->
+ <form-bean
+ name="LogonForm"
+ <strong>extends="BaseForm"/></strong></code></pre>
+<hr/>
+
+<p>
+ Hmmmm. That doesn't seem to tell us much.
+ The LogonForm "extends" the BaseForm, but doesn't add any attributes.
+ What about the BaseForm element that LogonForm extends?
+</p>
+
+<hr/>
+<h5>BaseForm - An "abstract" form-bean</h5>
+<pre><code> <!-- BaseAction form bean (abstract) -->
+ <form-bean
+ name="BaseForm"
+ type="org.apache.struts.validator.DynaValidatorForm">
+ <strong><form-property</strong>
+ name="username"
+ type="java.lang.String"/>
+ <form-property
+ name="password"
+ type="java.lang.String"/>
+ <form-property
+ name="task"
+ type="java.lang.String"
+ initial="Create"/>
+ </form-bean></code></pre>
+<hr/>
+
+<h5>Note:</h5>
+<blockquote>
+ <p><font class="hint">
+ <strong>Extends</strong> - In the Struts configuration file,
+ we can use the "extends" attribute to adopt default settings from
+ another element.
+ Extends makes using XML elements more like object-orientated
+ programming.
+ You can setup a base element, and then only specify the behavior that
+ changes.
+ </font></p>
+</blockquote>
+<hr/>
+
+<p>
+ Struts creates the ActionForms automatically, regardless of whether the
+ form-bean is conventional or dynamic.
+ The ActionForm lets us specify which properties we want to extract from
+ the incoming request.
+ If a property is not specified by the ActionForm,
+ the value is not automatically transferred from the request, validated,
+ or passed to the Action class.
+</p>
+
+<h4>The "scope" attribute</h4>
+
+<p>
+ The <strong>scope</strong> attribute in the "SubmitLogon" action element
+ tells the controller whether to store the ActionForm in the request,
+ rather than in the user's session.
+</p>
+
+<hr/>
+<h5>Best Practice:</h5>
+<blockquote>
+ <p><font class="hint">
+ Use request scope for single-page forms that contain all the
+ properties needed by the Action.
+ There is usually no need to maintain form input across requests.
+ </font></p>
+</blockquote>
+<hr/>
+
+<h4>The "validate" attribute</h4>
+
+<p>
+ The <strong>validate</strong> attribute controls whether the framework
+ will automatically validate
+ the ActionForm.
+ Conventional ActionForms have a stub "validate" method that you can
+ implement.
+ MailReader uses the Validator framework instead,
+ so the validations are specified in another configuration file.
+</p>
+
+<h4>The "input" attribute</h4>
+
+<p>
+ If validation fails, Struts looks for the forward specified by the
+ <strong>input</strong> attribute.
+ In this case, invoking the global "Logon" forward sends control back to
+ the Logon page.
+</p>
+
+<h4>The "exception" element</h4>
+
+<p>
+ Within the SubmitLogon action element is another new element, <strong>
+ exception</strong>.
+ When a user logons on, it's possible that an "ExpiredPasswordException"
+ will be thrown.
+ Should this happen, Struts will catch the exception and send control to
+ the "ChangePassword" action.
+</p>
+
+<hr/>
+<h5>Change Password screen</h5>
+<blockquote>
+ <p>
+ Your password has expired. Please ask the system administrator to
+ change it. <u>Try Again</u>
+ </p>
+</blockquote>
+<hr/>
+
+<p>
+ OK, it's not the greatest "Change Password" screen -- but, remember, this
+ is still the first iteration!
+</p>
+
+
<h4><a name="MainMenu.do" id="MainMenu.do">MainMenu.do and MainMenu.jsp</a>
</h4>
@@ -2239,9 +2286,9 @@
<h3><a name="subcription.jsp" id="subcription.jsp">Subscription.jsp</a></h3>
<p>
- Saving the best for last, Subscription.jsp utilizes two interesting Struts
- custom form tags,
- "html:options" and "html:checkbox".
+Saving the best for last, Subscription.jsp utilizes two interesting Struts
+custom form tags,
+"html:options" and "html:checkbox".
<p>
In Registration.jsp, the Struts iteration tag was used to write a list of
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org