You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Erik Weber <er...@mindspring.com> on 2004/07/22 20:43:01 UTC
Re: Tag question (JSP organization)
Sure, Raghuram.
Caution: long post!
It seems every project I've ever seen has an actor called "vendor", so
I'll use that as an example. ;)
Typically these use cases are required:
Add a new vendor account to the system
Remove an existing vendor account from the system
Edit an existing vendor's account details
Find a vendor account using a unique ID
Find a vendor account using some combination of criteria other than
unique ID
Retrieve all account details for a vendor
In other words, for each actor, you have the typical 'CRUD' use cases,
where 'R' might be complex enough to require several of its own sub-use
cases (different ways of viewing, searching).
So, translated to URI tokens that make some sense to an end user:
add
delete
edit
search
view
Now let's make them specific to the actor at hand, and make them into
full-fledged "action" or "command" URIs (Note: I use path mapping, not
extension mapping. Extension mapping changes this whole discussion.)
/vendor/add
/vendor/delete
/vendor/edit
/vendor/search
/vendor/view
But wait, if you've done this before, you know there (typically) are
actually two "commands" associated with each use case. If someone wants
to add a new vendor to the system, first he must visit some "add"
screen, which might contain not much more than a blank form. Then after
he submits the form, the application must process his input, and he must
visit some "result" screen, that lets him know whether his data made it
into the system as a permanent record (this result screen might actually
be the equivalent of another "view" action with the data processing and
feedback sort of "piggybacking" on the navigation; for example, /viewadd
--> submit, process, /viewdetails -- but any way you look at it, it's
normally two HTTP requests to get it all done). You can refer to these
as "setup" and "execute" actions, respectively. So now we have:
/vendor/viewadd (show the blank form)
/vendor/executeadd (process the completed form)
/vendor/viewsearch
/vendor/executesearch
. . .
You might think at this point that the perfect pattern is not going to
hold up. For example, to "view" details of a vendor account, you only
need one action, not two. But it depends on how you look at it. If you
have a "search" screen, or even a simple list of all vendors, you sort
of have your "/viewview", if you will. Once a single vendor is selected,
you have your "/executeview". Also, you might not think of separate
/viewdelete and /executedelete actions. Rather, you might think only of
/executedelete. But, if you have a "confirm" screen (even if it's just a
JavaScript popup that says, "Are you sure you want to delete?"), you
could think of that as /viewdelete -- so the pattern can hold up if you
squint a little. Also you should remember, to hell with the pattern if
it doesn't suit you.
So you can literally organize your JSPs this way, according to actor:
web/vendor/add_or_update.jsp
web/vendor/view_details.jsp
web/someOtherActor/add_or_update.jsp
. . . and so on. Notice the shared page for add and edit (aka "update").
Typically the form is the same, or close to the same, for each of the
two usecases. So why not parameterize that form and reuse it, if you
can? Rick Reumann's site ( www.*reumann*.net/do/struts/main ) might be
of some help on this topic. I know that some of his posts to this list
will. In your controller configuration, both /vendor/viewadd and
/vendor/viewedit would map to the same JSP (add_or_update.jsp).
So now we have the trailing end of our action URIs, but we still need
the leading end. That part consists of the application context path (if
any), and the controller Servlet path (if any). I say "if any" because
the default context and default Servlet mapping (both the equivalent of
"/") might suffice. But I like to use an explicit controller Servlet
path, such as "/services", because it allows me to delegate other
Servlets to "controlling" other things besides the services proper --
such as the dispensing of images (again, if you use extension mapping,
you might never have had to consider this).
So if your controller is mapped to "/services*" or "/services/*", then
action URIs that you want to route through the controller Servlet look
like this:
<app context>/services/vendor/viewadd
And other URIs (that won't be routed to the controller, might be routed
to another Servlet or might just be served directly) might look like this:
<app context>/images/vendor/rainy_day.gif.
I always liked that song by Oscar the Grouch, "Let a Frown Be Your
Umbrella (on a rainy, rainy day . . . )". Remember how, on the old Mac
OS, Oscar lived in the desktop garbage can?
Finally, restricting access to *.jsp in your web-resource-collection
element of web.xml can force your users to use the controller
Servlet-relative action URIs and prevent them from accessing JSPs directly.
Also, I solved the problem that led to this post by putting an
init-param in web.xml called "controllerPath". I set its value as an
application scope attribute in a plug-in class. Now I can create
controller-relative hyperlinks like this, using the JSTL-like tags:
<html:link page="${controllerPath}/vendor/home">home</html:link>
If someone wants to use extension mapping, I just set controllerPath to
be the empty String.
Now, what I want to know is, what flies out the window when I decide to
learn JSF? I'm afraid to look. ;) By the time I learn JSF, someone will
have developed a "CRUD IDE" that builds your entire app in five minutes,
based on actor names and a CSS stylesheet. In a few years, we will have
highly-paid "stack trace" experts. The average "corporate developer"
will see a stack trace and run for the hills, having always thought they
were a myth. The manager will have to call in a stack trace expert, who
will, at the rate of $700 per hour, begin to explain to all the
remaining developers what a "stack" is . . .
But seriously, hope this helps a newbie or two. Criticism is always welcome!
Erik
Raghuram Kanadam wrote:
>If you had the time Erik would you explain your method of arranging JSPs by the actor, seemed a beautiful approach.
>
>-----Original Message-----
>From: Erik Weber [mailto:erikweber@mindspring.com]
>Sent: Thursday, July 22, 2004 1:16 AM
>To: Struts Users Mailing List
>Subject: Re: Tag question
>
>
>Sorry if this post repeats -- I find that occasionally they are not
>making it . . .
>
>
>
>Jim, "actor" is precisely what I meant!
>
>It goes /context/controller/actor/usecase (in my case)
>
>Sorry I didn't say that correctly.
>
>But as you point out, I think it doesn't change the point of
>the post, that I need to manually make sure the name of the controller
>servlet gets into the hyperlinks.
>
>I wonder if a mapping of "/services" work better than "/services/*".
>Haven't tried that . . .
>
>Thanks,
>Erik
>
>
>
>Jim Barrows wrote:
>
>
>
>>
>>
>>
>>
>>>-----Original Message-----
>>>From: Erik Weber [mailto:erikweber@mindspring.com]
>>>Sent: Wednesday, July 21, 2004 11:32 AM
>>>To: Struts Users Mailing List
>>>Subject: Re: Tag question
>>>
>>>
>>>Sorry, I should have explained better what I am doing.
>>>
>>>My controller Servlet is mapped to /services/*
>>>
>>>All requests for JSP pages go through the controller, via action
>>>mappings. The actions have paths like:
>>>
>>>/usecase/view_edit_page
>>>/usecase/save_existing_record
>>>/usecase/view_add_page
>>>/usecase/add_new_record
>>>
>>>So the full links look like:
>>>
>>><context>/services/usecase/view_edit_page
>>>
>>>meanhwhile other resources have paths like:
>>>
>>><context>/images/some_image.gif
>>>
>>>This keeps other resources out of the scope of the controller (and
>>>perhaps into the scope of some other servlet). Also, direct
>>>JSP access
>>>is prohibited.
>>>
>>>So in places where I am building hyperlinks (within JSPs), I
>>>need to get
>>>"/services" into each link, in front of the action URI, but
>>>behind the
>>>context. And I want to do this in a portable way (in case the Servlet
>>>mapping changes).
>>>
>>>
>>>
>>>
>>If you use html:link and forwards then you can do whatever you want, and won't have to change the links themselves. This would be pretty portable as well.
>>
>>
>>
>>
>>
>>>So the idea is to put something like <html:rewrite
>>>page="${controller_path}<action_URI_here>"> which literally would be
>>>"/services" + "/usecase/action" or
>>>"/services/usecase/action". Using the
>>>"page" attribute to the tag makes it come out right
>>>("/context/services/usecase/action").
>>>
>>>(When I say "usecase" here I really should say "collection of
>>>usecases"
>>>or "function group" to be more accurate).
>>>
>>>I would be interested in hearing other mapping strategies.
>>>
>>>
>>>
>>>
>>I map jsp and directories by actor rather then use case, or use case package. Makes everything easier (especially declaritive security, then again I've kept the *.do mapping, rather then what you're doing.
>>That would make your url something like services/actor/useCase, which doesn't get around your problem.
>>
>>
>>
>>
>>
>>>For now I'm
>>>making sure the JSP can call a method or access a variable
>>>that returns
>>>"/services".
>>>
>>>Erik
>>>
>>>
>>>
>>>Christian D Hahn wrote:
>>>
>>>
>>>
>>>
>>>
>>>>Are you mapping the jsp to /services in the web.xml? if you do,
>>>>getServletPath should return the path you are looking for.
>>>>
>>>><servlet>
>>>><servlet-name>jsp</servlet-name>
>>>><jsp-file>/usecase/page.jsp</jsp-file>
>>>></servlet>
>>>>
>>>><servlet-mapping>
>>>><servlet-name>jsp</servlet-name>
>>>><url-pattern>/services</url-pattern>
>>>></servlet-mapping>
>>>>
>>>>-Chris
>>>>
>>>>Erik Weber wrote:
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>>Hmm I must be doing something wrong. That's giving me the
>>>>>
>>>>>
>>>>>
>>>>>
>>>same value
>>>
>>>
>>>
>>>
>>>>>as Erez's example. Strange, I would have expected it to give me
>>>>>"/services". I wonder how I am causing it to give me
>>>>>"/usecase/page.jsp".
>>>>>
>>>>>atta-ur rehman wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>>Hi Erik,
>>>>>>
>>>>>>This one worked for me:
>>>>>>
>>>>>><c:set var="v">
>>>>>><%= request.getServletPath() %>
>>>>>></c:set>
>>>>>>
>>>>>><c:out value="${v}"/>
>>>>>><bean:write name="v"/>
>>>>>>
>>>>>>HTH,
>>>>>>
>>>>>>ATTA
>>>>>>
>>>>>>On Tue, 20 Jul 2004 16:20:30 -0400, Erik Weber
>>>>>><er...@mindspring.com> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>>How can I set a variable (I assume with c:set) that will
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>hold the
>>>
>>>
>>>
>>>
>>>>>>>value
>>>>>>>of request.getServletPath, so that I can use it in el tags?
>>>>>>>
>>>>>>>Thanks,
>>>>>>>Erik
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>---------------------------------------------------------------------
>>>
>>>
>>>
>>>
>>>>>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>>>>>For additional commands, e-mail: user-help@struts.apache.org
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>---------------------------------------------------------------------
>>>
>>>
>>>
>>>
>>>>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>>>>For additional commands, e-mail: user-help@struts.apache.org
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>---------------------------------------------------------------------
>>>
>>>
>>>
>>>
>>>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>>>For additional commands, e-mail: user-help@struts.apache.org
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>>
>>>---------------------------------------------------------------------
>>>
>>>
>>>
>>>
>>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>>For additional commands, e-mail: user-help@struts.apache.org
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>---------------------------------------------------------------------
>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>For additional commands, e-mail: user-help@struts.apache.org
>>>
>>>
>>>
>>>
>>>
>>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>For additional commands, e-mail: user-help@struts.apache.org
>>
>>
>>
>>
>>
>>
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>For additional commands, e-mail: user-help@struts.apache.org
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>For additional commands, e-mail: user-help@struts.apache.org
>
>
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org