diff --git a/apps/mailreader/src/main/java/mailreader-support.xml b/apps/mailreader/src/main/java/mailreader-support.xml
index f84c58ee0..05091bafc 100644
--- a/apps/mailreader/src/main/java/mailreader-support.xml
+++ b/apps/mailreader/src/main/java/mailreader-support.xml
@@ -20,7 +20,7 @@
Like many applications, the MailReader uses mainly String properties.
One exception is the AutoConnect property of the Subscription object.
- On the HTML form, the AutoConnect property is represented by a checkbox,
- and checkboxes need to be handled differently that other controls.
+ On the HTML form, the AutoConnect property is represented by a checkbox.
- The checkbox starts out as a simple enough control.
-
+ When writing web applications, the checkbox can be a tricky control.
The Subscription object has a boolean AutoConnect property,
and the checkbox simply has to represent its state.
The problem is, if you clear a checkbox, the browser client will not submit anything.
Nada. Zip.
It is as if the checkbox control never existed.
- The HTTP protocol has no way to affirm "false".
+ The HTTP protocol has no way to affirm "false".
If the control is missing, we need to figure out it's been unclicked.
- Checkboxes -
- The HTML checkbox is a tricky control.
- The problem is that, according to the W3C specification, a value is
- only guaranteed to be sent
- if the control is checked.
- If the control is not checked, then the control may be omitted from
- the request, as if it was on the page.
- This can cause a problem with session-scope checkboxes.
- Once you set the checkbox to true, the control can't set it to false
- again,
- because if you uncheck the box, nothing is sent, and so the control
- stays checked.
-
- The simplest solution is to employ our old friend Preparable again,
- and reset the checkbox just before a Subscription is saved.
- If the control is not submitted, then the property remains false.
- If the control is submitted, then the property is set to true.
+ In Struts 1,
+ we use the
- But, we only want to reset the checkbox when we are about to save
- a Subscription.
- If we add it to the Subscription class,
- all of the aliases will reset the checkbox,
- which isn't what we want.
- As an alternative, we can give Subscription!save its own class,
- so that it can have it's own preparable method.
-
If we press the SAVE button,
the form will be submitted to the Subscription!save action.
- Since the action has it's own class,
- it can also have its own set of validators.
+ Since the save method needs some additional validation,
+ we can add a validation file.
mailreader-support.xml Login
-<action name="Login!*" class="mailreader2.Login" method="{1}">
+<action name="Login!*" method="{1}" class="mailreader2.Login">
<result name="input">/pages/Login.jsp</result>
<result name="cancel" type="redirect-action">Welcome</result>
<result type="redirect-action">MainMenu</result>
@@ -1967,7 +1967,7 @@ public class AuthenticationInterceptor implements Interceptor {
mailreader-support.xml Subscription element
-<action name="Subscription!*" class="mailreader2.Subscription" method="{1}">
+
@@ -2260,96 +2260,39 @@ public Subscription findSubscription(String host) {
<action name="Subscription!*" method="{1}" class="mailreader2.Subscription">
<result name="input">/pages/Subscription.jsp</result>
<result type="redirect-action">Registration!input</result>
</action>
-
- <s:checkbox label="%{getText('autoConnect')}"
- name="subscription.autoConnect"/>
-Tip:
-
-
-
-
reset method to work around checkbox issues.
+ In Struts 2, checkbox state is handled automatically.
+ The framework can detect when a checkbox tag has not been sent back,
+ and when that happens,
+ a default "false" value is used for the checkbox value.
+ No worries, mate.
-mailreader-support.xml Subscription!save element
-
-<action name="Subscription!save" class="mailreader2.SubscriptionSave">
- <result name="input">/pages/Subscription.jsp</result>
- <result type="redirect-action">Registration!input</result>
- <interceptor-ref name="user-submit" />
- </action>
-SubscriptionSave
-
-public final class SubscriptionSave extends Subscription {
-
- public void prepare() {
- super.prepare();
- // checkbox workaround
- getSubscription().setAutoConnect(false);
- }
-
- public String execute() throws Exception {
- return save();
- }
-}
-
-SubscriptionSave-validation.xml
+Subscription-Subscription!save-validation.xml
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
@@ -2369,17 +2312,9 @@ public Subscription findSubscription(String host) {
- If validation succeeds, the execute method of SubscriptionSave will fire.
- Just to keep all the code together,
- all the execute method does is call save on the parent Subscription class.
+ If validation succeeds, the save method of Subscription will fire.
public String execute() throws Exception {
- return save();
-}
+ When we pressed the SAVE button, there was one step that we overlooked. + The Mailreader application uses a "double submit" guard to keep people + from clicking the SAVE button multiple times and submitting the form again. +
+ +
+ To add the double-submit guard, we can change the actions default processing
+ stack to user-submit.
+ But, we don't want to just copy and paste the other action settings from
+ the main Subscription action.
+ What we can do is put the subscription actions in their own package,
+ so that they can share result types.
+
+</package>
+
+<package name="subscription" namespace="/" extends="mailreader-support">
+
+ <global-results>
+ <result name="input">/Subscription.jsp</result>
+ <result type="redirect-action">Registration!input</result>
+ </global-results>
+
+ <action name="Subscription!save" method="save" class="mailreader2.Subscription">
+ <interceptor-ref name="user-submit" />
+ </action>
+
+ <action name="Subscription!*" method="{1}" class="mailreader2.Subscription" />
+
+</package>
+
+<package name="wildcard" namespace="/" extends="mailreader-support">
+
+ <action name="*" class="mailreader2.MailreaderSupport">
+ <result>/{1}.jsp</result>
+ </action>
+
+</package>
+}
++ Aftering a successful save, + the Subscription Action will return "success", + and the framework will redirect us back to Registration input. +
+At this point, we've booted the application, logged on,