<meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> <!-- data-ad-client=ca-pub-4320963827702032 --> <!-- --><style type="text/css">@import url(https://www.blogger.com/static/v1/v-css/navbar/3334278262-classic.css); div.b-mobile {display:none;} </style> </head><body><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar.g?targetBlogID\x3d7256432\x26blogName\x3dThe+Frustrated+Programmer\x26publishMode\x3dPUBLISH_MODE_BLOGSPOT\x26navbarType\x3dBLACK\x26layoutType\x3dCLASSIC\x26searchRoot\x3dhttps://frustratedprogrammer.blogspot.com/search\x26blogLocale\x3den_US\x26v\x3d2\x26homepageUrl\x3dhttp://frustratedprogrammer.blogspot.com/\x26vt\x3d4213664491834773269', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe", messageHandlersFilter: gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER, messageHandlers: { 'blogger-ping': function() {} } }); } }); </script>
| Sunday, July 18, 2004

As noted in my last blog entry, Struts's DispatchAction never really integrated with other pieces of the framework. That entry talked about canceling validation, this entry covers kicking off validation. We'll take a look at the MappingDispatchAction introduced in Struts 1.2.1, but lets first look at the problem it was introduced to fix.

Say we have the following forms:

=========buddyList.jsp========
Buddy List:

[ ] Sally
[ ] Billy
[ ] Pat

[Delete] [Add]

=========buddyAdd.jsp========
Buddy Add:

Name: ___________

[Submit]


Now lets say we want to code the CRUD (w/o update) actions in a DispatchAction:

public class BuddyAction extends DispatchAction {
public ActionForward read( ... ) {
request.setAttribute( "buddies", businessLogic.getBuddies( ... ) );
}

public ActionForward delete( ... ) {
businessLogic.deleteBuddy( ... );
}

public ActionForward create( ... ) {
businessLogic.createBuddy( ... );
}
}


Now we get to the crux of the problem. How do you define the action in your struts-config.xml for this puppy? Most people try to define one action for the whole DispatchAction. The problem is, you can only have one ActionForm defined, one validation definition and one 'input' attribute to tell struts where to go if validation fails. (Note you can have multiple validations defined if you use the 'page' attribute on your validation, but that only applies to "wizards".) So in reality, a Struts action needs to be defined for each HTML form you have. So your struts-config.xml might look like this:

<action path="/buddyList"
type="BuddyAction"
name="BuddyListForm"
scope="request"
input="/buddyList.jsp"
parameter="method">
<forward name="readSuccess" path="/buddyList.jsp"/>
<forward name="deleteSuccess" path="/buddyList.jsp"/>
</action>

<action path="/buddyCreate"
type="BuddyAction"
name="BuddyForm"
scope="request"
input="/buddyCreate.jsp"
parameter="method">
<forward name="createSuccess" path="/buddyList.jsp"/>
</action>


So, this works. aside from the problems I described in this blog entry and your wondering 'Where does MappingDispatchAction come in'? Well, look at the URL you need to use to create a buddy:

<a href="/buddyCreate.do?method=create">Create</a>


If you find it too annoying to repeat yourself like this, you can change your Action to extend MappingDispatchAction and change the struts-config.xml to the following:

<action path="/buddyRead"
type="BuddyAction"
parameter="read">
<forward name="success" path="/buddyList.jsp"/>
</action>

<action path="/buddyDelete"
type="BuddyAction"
name="BuddyListForm"
scope="request"
input="/buddyList.jsp"
parameter="delete">
<forward name="success" path="/buddyList.jsp"/>
</action>

<action path="/buddyCreate"
type="BuddyAction"
name="BuddyForm"
scope="request"
input="/buddyCreate.jsp"
parameter="create">
<forward name="success" path="/buddyList.jsp"/>
</action>


Your new URL is just:

<a href="/buddyCreate.do">Create</a>

This also has the advantage that the action definitions are more specific and only define what is needed for each one. For example, no ActionForm is created for the /buddyRead action. These are all good things, but they come at the price of a larger struts-config.xml. If your using a tool like XDoclet to build your config file, I suppose this wouldn't be an issue, but for the rest of the hand-coding Struts world, they will need to make a choice about which method they prefer.