|
Sponsored Links
Resources
Enterprise Java Research Library
Get Java white papers, product information, case studies and webcasts
|
News
News
News
|
Messages: 49
Messages: 49
Messages: 49
Printer friendly
Printer friendly
Printer friendly
Post reply
Post reply
Post reply
XML
XML
XML
|
 |
Redirect After Post 2
In Michael Jouravlev's first article he discussed a Redirect-after-Post pattern to get around problems with reloading a post. This article jumps into an implementation of the solution.
Conclusion Do you think that this approach is anything but special? Well, it is. But it is far from being a standard.
Recently I decided to use my eBay account again, but I forgot the password. I went to the password recovery page and filled out a small form. After I submitted the form, eBay informed me that a link to the password reset page was sent to my email address. Still having the confirmation page displayed, I clicked Refresh buttons several times. Guess, how many emails I received? What if instead of password recovery confirmation it were a payment confirmation?
Read Redirect After Post 2
|
|
Message #144899
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Errata #1
The action mapping "scope" attribute was lost in the process of cutting the fat off the working code. All action mappings must have scope = "request".
|
|
Message #144902
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Erratum #2
Mozilla/Firefox does not reload page marked "no-cache", if a user goes back in the browser session history.
Mozilla/Firefox reloads a page marked "no-store", if a user goes back in the history. This behavior is "as designed" for Mozilla, but have been broken for a while and was recently fixed in Firefox 1.0 RC (see Mozilla bug 252023).
Pages which are marked as "no-cache", but which are served over SSL, are always reloaded by Mozilla.
MSIE reloads a page in all aforementioned cases.
If you want to keep your pages in sync with Model while using Mozilla, you need to mark your responses as "no-store". Struts has the convenient setting <controller nocache="true"/> in struts-config.xml file, but it does not set "no-store" header, it sets only the following headers:
response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 1);
so you would need to patch Struts code.
|
|
Message #144920
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Redirect After Post 2
Conclusion Do you think that this approach is anything but special? Well, it is. But it is far from being a standard. Recently I decided to use my eBay account again, but I forgot the password. I went to the password recovery page and filled out a small form. After I submitted the form, eBay informed me that a link to the password reset page was sent to my email address. Still having the confirmation page displayed, I clicked Refresh buttons several times. Guess, how many emails I received? What if instead of password recovery confirmation it were a payment confirmation? Read Redirect After Post 2 Well good point about multiple emails sent. However I consider calling business logic from forms a hack and also I think that there are simplest ways to keep the last inserted/edited id (along with other usefull information like the page in a item list you've started insertion/update) in session scope, not that I'd be disturbed by the approach you've taken but I have seen too many overcomplicated dynamic web sites just for the sake of having a wonderfull mechanism to remember one or two things.
Also if I remember well, WebWork allows you to redirect to an url with wildcards that would allow you to specify later the inserted/updated item id (e.g. viewItem.action?id={0} ).This reminds me of how many times I have promissed myself to take a closer look to WebWork (meaning to make a damn simple thing with it and get the feel of using it).
Anyway "Redirect after post" is the way to go if you don't want your clients/customers to get the annoying Page expired, Want to resubmit etc., messages from browsers.
|
|
Message #144921
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Why don't use state-aware framework?
If a web app framework aware of user session state is used instead on second and subsequent post you would get 'stale link' exception that can be processed in graceful way e.g. bringing used back to the page of 'last known good' session state.
I've successfully implemented this in Tapestry to avoid glitches in 9-step online ordering process. It is completely insensitive to nasty 'back' button.
I'm not sure you can do this with Struts out of the box (that's one of the reasons I switched to Tapestry) but the pattern is obvious: don't process same action twice, pay attention to the state change, if state is invalid for the action.
|
|
Message #144928
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Care to share?
I have been looking into tapestry recently. Would you care to share how you did this?
Regards,
Joshua
|
|
Message #144940
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Care to share?
Sure.
I've put my own page (in a sense of Tapestry pages) instead of standard StaleLink in .application file. And in this page I've implemented checking user session state and sending internal redirect to page which processed "last known good" request from this user. As Tapestry keeps states of pages within the scope of the user session, from user point of view it was completely transparent. You press 'back' you click on link or submit a form, and you get again the page where you've pressed 'back' for a first time. You can also add some message to the top of the page like "hey you don't touch that 'back' button anymore!"
|
|
Message #144950
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
event epoch counter
wings is using an event epoch counter internally, that is incremented whenever an action has fired. As an application developer, you don't even see outdated events. The user gets the current session state displayed.
|
|
Message #144956
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Why don't use state-aware framework?
If a web app framework aware of user session state is used instead on second and subsequent post you would get 'stale link' exception that can be processed in graceful way e.g. bringing used back to the page of 'last known good' session state. * If you are performing a re-POST, how do you avoid nasty browser messages "POSTDATA must be resent"? * I don't think that accepting a re-POST, evaluating it and comparing to a previous one is the right thing to do. I do not want to judge, did a user make a mistake and erroneously resubmitted a FORM, or did he do it because he wanted, say, to submit another order. I believe that it is easier to prevent resubmits, than to analyze them and to decide is it the same one as a previous one, and is not a "real" resubmit.
|
|
Message #144967
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Redirect After Post 2
This is a valid idiom. Spring Framework actually has built-in support for it in its own MVC web layer, just by using a RedirectView...
One thing that people should be aware of is that when this mechanism is used with something like Apache in front of the Servlet engine, is that if instead of using something like a direct Apache to servlet engine connector, you are using proxying, where the servlet engine doesn't even know the real external path the user used to get in, Apache needs to be configured to do proper URL rewriting/fixing on returned data (including the redirect sent back for this use case).
|
|
Message #145008
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
GET and side-effects
These two statements bothered me:
"Note: createItem was originally invoked using pushbutton and POST method. But Struts throws an exception if an action corresponding to HTML FORM does not define a form bean. Because createItem action does not use form beans, the HTML FORM had to be changed to a link. Thus, createItem is now called using GET method."
"deleteItem action removes an item from persistent storage. It receives item ID from the link on viewList.jsp page. Updating model in response to GET request is against semantics of GET method, but I decided to keep it that way."
I know the site is a device to discuss your idiom. but using GET to incur a side-effect is terribly bad design. The framework of choice is not an excuse. Please fix these and update your article.
|
|
Message #145013
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
GET and side-effects
These two statements bothered me:"Note: createItem was originally invoked using pushbutton and POST method. But Struts throws an exception if an action corresponding to HTML FORM does not define a form bean. Because createItem action does not use form beans, the HTML FORM had to be changed to a link. Thus, createItem is now called using GET method.""deleteItem action removes an item from persistent storage. It receives item ID from the link on viewList.jsp page. Updating model in response to GET request is against semantics of GET method, but I decided to keep it that way."I know the site is a device to discuss your idiom. but using GET to incur a side-effect is terribly bad design. The framework of choice is not an excuse. Please fix these and update your article. You are absolutely right, using GET for updating server state is against GET semantics. If you have read my previous article, it explicitly stated that one should use POST for this purpose :) But the provided application is just an example. In case of createItem being called via a link, I wanted to get rid of unneeded form bean and this was the easy (and lazy) solution. I changed button to a link in the article to make listing for struts-config.xml as short as possible, but if you follow the link to the live application you will see, that it still has a pushbutton to create a new item :)
The usssue with deleteItem is surely more bothersome. I have two other links for viewing and editing an item, so I wanted the delete operation to be consistent with other ones. Also, I do not like when a table shows a bunch of buttons. Sadly, ANCHOR tag does not allow to choose the request method type.
Other people do the same anyway :) For example, yahoo mail uses simple links for "Flag message" or "Mark as unread" operations, which changes state of a mailbox. On the other hand, yahoo uses pushbutton for Delete operation.
As I said, I realise (and stated it myself) that GET should return idempotent results. But I decided to get away with the link. The change to the FORM will be not be hard at all and does not affect the approach as a whole.
And please do not forget, that despite the type of request which initiates deleteItem action, it is still redirected to a result page using (another) GET. Thus, the result page provides idempotent view. And only result page is stored in the browser cache.
|
|
Message #145020
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
GET and side-effects
"If you have read my previous article, it explicitly stated that one should use POST for this purpose :) But the provided application is just an example."
It may be just an example, but the fact remains it is a bad example. It's all the more discouraging that you know it's a bad example and cite the fact that others do it as an excuse. I hope you and TSS get around to amending this article.
"As I said, I realise (and stated it myself) that GET should return idempotent results."
Nitpick: GET should not incur side-effects but what you GET is a state representation and may in fact change over time. The point is you don't use GET to change state. If your article had JavaBeans that changed state as a result of getXXX calls I doubt it would get to print.
|
|
Message #145047
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
GET and side-effects
The provided application is just an example. It may be just an example, but the fact remains it is a bad example. It's all the more discouraging that you know it's a bad example and cite the fact that others do it as an excuse. Well, you are right. One cannot evengelize great ideas with bad examples.
(I) To call createItem properly the following changes should be made.
Add itemFormInput form bean to createItem action mapping to make Struts happy:
<action path = "/createItem" type = "com.xorsystem.items.CreateItemAction" name = "itemFormInput" scope = "request" input = "/WEB-INF/items/error.jsp" validate = "false"> <forward name="itemCreated" path="/editItem.do" redirect="true"/> </action>
viewList.jsp: change the following link
<html:link page="/createItem.do">Create Item</html:link>
to a form
<html:form action="/createItem.do"> <html:submit value="Create Item"/> </html:form>
This does with the first issue, and it is how the live app is done.
(II) The solution for deleteItem does not look pretty with buttons. Anyway, it adheres to specs. The easiest way would be to use DispatchAction.
Its definition in struts-config.xml file would look like this:
<action path = "/dispatchItem" type = "com.xorsystem.items.DispatchItemAction" name = "itemListForm" parameter = "method"> <forward name="viewItem" path="/viewItem.do"/> <forward name="editItem" path="/editItem.do"/> <forward name="deleteItem" path="/deleteItem.do"/> </action>
createItem action is called from a separate form directly to its own action.
Create DispatchItemAction class inheriting from DispatchAction, and define methods with the same names as button values. These names will be: View, Edit, Create. I guess, someone can pick on me again that methods names start with capital letter. Well, if you want nice button values and nice method names, you can comb this sample app with your own nice javascript.
Create one HTML form per each item row. Create a button for each operation (or just for deletion if you like) and assign its value attribute a name corresponding to a method name. Also, include item ID as a hidden input field in each form.
This is it. Now you can see cool square buttons instead of links, and delete items using POST method. The source code in the zip file is updated, but the live application may take a while.
|
|
Message #145224
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Use Cocoon flowscript
Still having the confirmation page displayed, I clicked Refresh buttons several times. Guess, how many emails I received? What if instead of password recovery confirmation it were a payment confirmation? Well, if you were using flowscript this would be easy to prevent. Your application could very easily know that it had already sent the email.
|
|
Message #145234
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Why don't use state-aware framework?
I am not sure I understand the problem, but is it so hard to add "actionId" parameter to URL or hidden form field to detect resubmit ?
|
|
Message #145235
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Why don't use state-aware framework?
View source on this page :
<form method="post" name="Form1" action="/tss">
<input type="hidden" name="service" value="direct/0/PostNewsReply/postReply.form"/> <input type="hidden" name="sp" value="S1"/> <input type="hidden" name="Form1" value="messageId,subject,useParentSubject,quoteOriginal,messageBody"/> <input type="hidden" name="messageId" value="l145234"/>
Message id is just generated before submit. Is it something not trivial ?
|
|
Message #145243
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Why don't use state-aware framework?
I am not sure I understand the problem, but is it so hard to add "actionId" parameter to URL or hidden form field to detect resubmit ? It's OK, I can ask it again. If you are performing a re-POST, how do you avoid browser message "POSTDATA must be resent"? Or they do not bother you, and you consider them part of normal user experience?
|
|
Message #145249
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Why don't use state-aware framework?
I am not sure I understand the problem, but is it so hard to add "actionId" parameter to URL or hidden form field to detect resubmit ? It's OK, I can ask it again. If you are performing a re-POST, how do you avoid browser message "POSTDATA must be resent"? Or they do not bother you, and you consider them part of normal user experience?
I see no problem in this message, probably it is possible to dissable this message in browser preferences. If you do not need to attach file then GET method can be used for form too to avoid this message.
|
|
Message #145281
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Why don't use state-aware framework?
I see no problem in this message, probably it is possible to dissable this message in browser preferences. According to RFC2616/9.5, responses to POST request can be made cacheable using appropriate Cache-Control or Expires header fields. But the caching may not work on some simple browsers which do not have caching. Also, most websites set their after-POST results to expire immediately, and most browsers ask for confirmation if the POST is about to be resubmitted while navigating browser history. Anyway, it is much cleaner not to allow resubmit, that to distinguish between a real resubmit and a page refresh.If you do not need to attach file then GET method can be used for form too to avoid this message. This is a no-no, GET should not change server state.
|
|
Message #145287
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Why don't use state-aware framework?
This is a no-no, GET should not change server state. Yes, I do not like this workaround too. If it is asumed GET doe's not change state, then it is very trivial to implement content cache. Probably redirect is not so bad idea too. I like idea to use state machines for this stuff, it is possible to make it configurable and can help to test many ways.
|
|
Message #145305
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Redirect After Post and JSF?
Is there an easy way to get Redirect-After-Post working with JSF? I'm currently looking on a lot of Java Web-Frameworks, and JSF looked nice, but of course it looses a lot if its sex appeal when Redirect-After-Post doesn't work out of the box.
Bye,
Jürgen
|
|
Message #145315
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
GET changing server state
This is a no-no, GET should not change server state. This strikes me as a needlessly pedantic approach. Anyone with a hit counter knows that GET requests change server state all the time.
Likewise, there are plenty of times when you need to use POST when server state is not changing.
Unfortunately we have a spec (HTML) that inappropriately ties the applications intent (GETting information or POSTing information) with non-identical mechanisms to handle those requests. It is akin to saying you can only use TCP to send data and UDP to receive data.
|
|
Message #145349
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Thank you
It is a standard.http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4 Are we nitpicking? Yes, I am aware of RFC2616. What I meant is that this approach is not used in 100% of deployments of web applications. Should have used "commonly accepted" instead of "standard".
Not nitpicking, just annoyed. I'm sick of clicking my "back" button and being warned by my browser that I'm about to re-submit a POST. You are too (or you wouldn't have bothered writing the above article, right?).
The nasty knee-jerk response that I posted was provoked by your choice of framework. Struts is an HTTP hostile framework; it makes GET and POST look the same. They aren't the same.
A framework should support new developers, not subvert them. It shouldn't be necessary to write an article to tell people how to make their framework redirect after a POST, it should be the framework's default behaviour.
|
|
Message #145367
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Thank you
Struts is not HTTP-Hostile. Redirect after post works like a charm: you just need to put redirect="true" in your forward definition.
|
|
Message #145381
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Thank you
I'm sick of clicking my "back" button and being warned by my browser that I'm about to re-submit a POST. You are too (or you wouldn't have bothered writing the above article, right?). You are right, I hate this too.Struts is an HTTP hostile framework; it makes GET and POST look the same. They aren't the same.A framework should support new developers, not subvert them. It shouldn't be necessary to write an article to tell people how to make their framework redirect after a POST, it should be the framework's default behaviour. Well... The article is about the general technique: redirecting after POST and loading the result page with a simple GET. It is not something that I invented, I just wanted to bring it up as a good solution against double submits, and as a way to improve user experience. Struts was my framework of choice to illustrate the solution just because I worked with Struts before. Though you are right, that it were the deficiencies in default Struts request handling that moved me to write this. I guess, if I had a better framework at the first place, I would not even notice the very issue of after-POST.
But I would not say that Struts is HTTP hostile. It allowed me to do what I wanted, though I had to rethink how a request should be processed. After I came up with idea that ONE request should be processed with TWO action mappings, everything got easy and simple.
The ASP.NET approach with its postbacks to the same form and with passing viewstate between forms in the request/response fields does not make me clap my hands either.
|
|
Message #145527
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Redirect After Post and JSF?
Is there an easy way to get Redirect-After-Post working with JSF? I'm currently looking on a lot of Java Web-Frameworks, and JSF looked nice, but of course it looses a lot if its sex appeal when Redirect-After-Post doesn't work out of the box.Bye,Jürgen I have not worked with JSF yet, just skipped really fast through the specs. But from what I've understood, redirection support is very limited. Chapter 2.1.2, "Faces Request Generates Faces Response" does not mention redirection on the diagram or in the text. Chapter 2.1.3, "Faces Request Generates Non-Faces Response" mentions redirection: "A Faces Request needs to be redirected to a different web application resource (via a call to HttpServletResponse.sendRedirect)."
Looks like JSF phase is terminated right here: "It is then necessary to tell the JSF implementation that the response has already been created, so that the Render Response phase of the request processing lifecycle should be skipped. This is accomplished by calling the responseComplete() method on the FacesContext instance for the current request, prior to returning from event handlers or application actions." I understand this paragraph, as that redirection transfers the request outside JSF, thus redirection is supported merely as a way out.
What is even worse, that if I am not mistaken, portlets do not support redirection at all. I cannot find it right now in the specs, but I believe that I've seen it somewhere. Please correct me, if I am wrong.
See the other topic with GridSphere announcement. It supports portlet specification. Try to refresh any of the pages after you submit a form. You will get infamous "POSTDATA will be resent" message. This is sad.
|
|
Message #145604
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Redirect After Post 2 (protecting JSP files)
Michael,
Just scanned your article and had to smile to myself as I recommended just such an approach to a colleague earlier in the day.
The only comment that I have (not read the article in detail yet) is the sentence...
"JSP pages are stored in protected WEB-INF directory and are not accessible from a browser."
...my personal experience in using this technique (which, like me, you probably got from the "Core J2EE Patterns" book) is that it doesn't work for all application servers. Weblogic was the one that I came across, but there may be others. Anyway, the alternative solution is to use the security constraint element within the applications web.xml file. (After moving all JSP files, that are not intended to be accessed from a browser, into the 'jsp' directory) ------------ <security-constraint> <web-resource-collection> <web-resource-name>Sensitive</web-resource-name> <description>Resources that shouldn't be served directly to the browser</description> <url-pattern>/jsp/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>sensitive</role-name> </auth-constraint> </security-constraint> <security-role> <description>This role defines all of the users that are allowed to access JSP files directly (apart from in the root of the app) NOTE: NO users should be assigned this role as it is intended to be used as a blocking constraint.</description> <role-name>sensitive</role-name> </security-role>
------
I can't claim authorship of this as I picked up up from a website (can't remember where) and it's simply part of the servlet spec, as far as I can see. I don't profess to be an expert on this subject but the technique works for me and I'm only too happy to accept any feedback that anybody may offer.
|
|
Message #145805
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Redirect After Post 2 (protecting JSP files)
Bob, I am glad you liked the article, the great minds think alike ;-) Thank you for advice. I borrowed the idea of storing JSPs in WEB-INF directory from Ted Husted's Struts tips, and this works great on Tomcat. I will verify how it works on Weblogic and will try your advice as well. --- michael_jouravlev [at] yahoo [dot] com www.superinterface.com
|
|
Message #145818
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
It works well!
The article is about the general technique: redirecting after POST and loading the result page with a simple GET. It is not something that I invented, I just wanted to bring it up as a good solution against double submits, and as a way to improve user experience. Micheal, Thank you so much for sharing your idea. I will use this idiom, and have introduced to other project leads today, because it's simple and so powerful.
Tak
|
|
Message #146096
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Anything but special
I had posted some comment about this pattern, a few weeks ago in the forums : http://www.theserverside.com/patterns/thread.tss?thread_id=20936#142725
The best thing about this navigation pattern is that you allow users to use the 'Back' button of their browser with safety (I mean, without the scary, sometimes dangerous and often not understood 'RE-POST data ?' message). Great, huh ?
This pattern leads to 2 types of Struts Actions : - 'views' that display a web page, forwarding the request to a JSP, - 'actions' that would execute a transaction (save, delete an item) and end with a sendRedirect.
|
|
Message #146098
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
For instance...
After posting my message, I hit the 'refresh' button of your browser (it's used pretty often by users, I'm sure you've got one, too).. and what do I get ? Yep, the very famous "do you want to re-post data" message. arrrg.
|
|
Message #148031
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Struts and Mozilla update
I did not know when this happened, but Struts team updated their code, so no it includes "no-store" header, if Controller.nocache attribute in struts-config.xml is set to "true". The latest stable version 1.2.4 has this patch.
Mozilla/Firefox 1.0 production release honors response headers only, it does not honor "meta http-equiv" tags on your HTML page to control caching. These tags may be processed by your server software to be converted to HTTP response headers. If your appserver does not do this, then Mozilla would not care. If you use Struts, install the latest release and use Controller.nocache attribute.
|
|
Message #148048
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
IE problem
AFAIK, this nasty confirmation message is an Internet Explorer problem primarily.
Disabling cache control or setting the expiration date to the past or such doesn't help. Also, there does not seem to be a browser option to get rid of this kind of behaviour.
:(
|
|
Message #149341
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
K.I.S.S
I'm amazed that it took the author 2 long articles to basically convey this simple message: Use redirect when changing object state or doing a write operation on a persistent store; otherwise, use forward.
-Yves-
|
|
Message #149446
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
What if a feedback is required?
This seems to work fine. But what if one needs to give a feedback to the user about the previous operation.
For eg. The user enters some data and clicks save, the system saves it and redirects to, say a Listing page, again. Here if the users needs to see a confirmation say "ABC saved", then the GET doesn't support that since there is no where that message is available. Unless of course, one resorts to the query string manipulation or stick it in the session.
Any other ideas / thoughts. ??
|
|
Message #149447
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
What if a feedback is required?
This seems to work fine. But what if one needs to give a feedback to the user about the previous operation.For eg. The user enters some data and clicks save, the system saves it and redirects to, say a Listing page, again. Here if the users needs to see a confirmation say "ABC saved", then the GET doesn't support that since there is no where that message is available. Unless of course, one resorts to the query string manipulation or stick it in the session.Any other ideas / thoughts. ??
|
|
Message #149449
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
What if a feedback is required?
On a second thought.....
After the successful save, the save message can be put in the session. In the listing page, one can pick it up from the session and delete it immediately from the session. Now the messge is available for the display once.
If the user clicks the refresh button again, now that the message string in session is gone, the message part is avoided and just the listing is shown.
So to answer myself : If a feedback is required, then after (post) update put the feedback message in session. Now Redirect after POST. In the new GET page, check for the "feedback" message in session and if available retrieve and delete from session and show it to user. Further refreshes of the get pages should be unaware of the feedback message also.
This seems to work fine. But what if one needs to give a feedback to the user about the previous operation.For eg. The user enters some data and clicks save, the system saves it and redirects to, say a Listing page, again. Here if the users needs to see a confirmation say "ABC saved", then the GET doesn't support that since there is no where that message is available. Unless of course, one resorts to the query string manipulation or stick it in the session.Any other ideas / thoughts. ??
|
|
Message #149455
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
What if a feedback is required?
On a second thought.....After the successful save, the save message can be put in the session. In the listing page, one can pick it up from the session and delete it immediately from the session. Now the messge is available for the display once. If the user clicks the refresh button again, now that the message string in session is gone, the message part is avoided and just the listing is shown.So to answer myself : If a feedback is required, then after (post) update put the feedback message in session. Now Redirect after POST. In the new GET page, check for the "feedback" message in session and if available retrieve and delete from session and show it to user. Further refreshes of the get pages should be unaware of the feedback message also. This is basically what I did in the sample application which is discussed in the article. The UI object which is stored in the session, comprize business data and some UI information, like error messages or page title. Error messages can depend on business data or on previous UI action. If error message was created because of incorrect data operation, it will remain in the UI object and will be shown again on refresh. If error is a result of UI operation, then it will be cleared on refresh.
You can try live application on my website. Create an item, put into some non-numeric data and save. You will get "Value must be a number" error which is not cleaned on refresh. On the other hand, if you create ten items, then when you try to create the eleventh, you will see "Storage exhausted" message. If you refresh the page, this message will disappear. This message is the result of a Store operation, but refreshing a page does not involve Store, so I considered this message inappropriate when the page is refreshed.
|
|
Message #149540
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
What if a feedback is required?
On a second thought.....After the successful save, the save message can be put in the session. In the listing page, one can pick it up from the session and delete it immediately from the session. Now the messge is available for the display once. If the user clicks the refresh button again, now that the message string in session is gone, the message part is avoided and just the listing is shown.So to answer myself : If a feedback is required, then after (post) update put the feedback message in session. Now Redirect after POST. In the new GET page, check for the "feedback" message in session and if available retrieve and delete from session and show it to user. Further refreshes of the get pages should be unaware of the feedback message also. This is basically what I did in the sample application which is discussed in the article. The UI object which is stored in the session, comprize business data and some UI information, like error messages or page title. Error messages can depend on business data or on previous UI action. If error message was created because of incorrect data operation, it will remain in the UI object and will be shown again on refresh. If error is a result of UI operation, then it will be cleared on refresh. You can try live application on my website. Create an item, put into some non-numeric data and save. You will get "Value must be a number" error which is not cleaned on refresh. On the other hand, if you create ten items, then when you try to create the eleventh, you will see "Storage exhausted" message. If you refresh the page, this message will disappear. This message is the result of a Store operation, but refreshing a page does not involve Store, so I considered this message inappropriate when the page is refreshed.
Hi Mike I tried the live application, and when I tried to save the eleventh item, it gave a "storage exhausted" message. I tried to refresh and although the "Post Alert" didn't appear (since you've implemented the GET way), the error message kept appearing for each refresh! Same for UI errors too.
Now in my project, I had a main listing page where a number of records are listed in a table format with edit/delete button. The user chooses one record and say edit. Now the system navigates to another Edit page, where the user edits and clicks save. After the successful save I need to take the user to the original listing page and also show a status of the save request (Like blah blah saved).
I had implemented it the "redirect after post" way. So the error message should appear once, and not on a refresh. I did the session trick and it works!! Of course, along with that the usual evils associated with Session are also present. But I can live with that.
|
|
Message #152904
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Redirect After Post and JSF?
I'm far from being a JSF expert, so please take this with a grain of salt.
In section 7.4.2 Default NavigationHandler Implementation of the JSF spec it says:
If a matching <navigation-case> element was located, the <redirect/> element was specified in this <navigation-case>, and the application is not running in a Portlet environment, use the <to-view-id> element of the matching case to construct a context-relative path that corresponds to that view id, cause the current response to perform an HTTP redirect to this path, and call responseComplete() on the FacesContext instance for the current request.
This sounds to me as if it were usable for the PRG pattern. What are your thoughts?
|
|
Message #153588
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Redirect After Post and JSF?
I'm far from being a JSF expert, so please take this with a grain of salt.In section 7.4.2 Default NavigationHandler Implementation of the JSF spec it says:If a matching <navigation-case> element was located, the <redirect/> element was specified in this <navigation-case>, and the application is not running in a Portlet environment, use the <to-view-id> element of thematching case to construct a context-relative path that corresponds to that view id, cause the current response to perform an HTTP redirect to this path, and call responseComplete() on the FacesContext instance for the current request.This sounds to me as if it were usable for the PRG pattern. What are your thoughts? Andreas, I have to admit that I was wrong. Spec is a little vague about it, but you can use redirect element for navigation rule and it work very well. Because JSF stores view state on the server, nothing is lost during redirect, and you can browse back and forth freely and you can reload result page. I recompiled and run the test application and it works well. My apologies to JSF authors.
|
|
Message #153589
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
What if a feedback is required?
Hi MikeI tried the live application, and when I tried to save the eleventh item, it gave a "storage exhausted" message. I tried to refresh and although the "Post Alert" didn't appear (since you've implemented the GET way), the error message kept appearing for each refresh! Same for UI errors too. Oops, online version differs a little from the one that I have on my development machine, I will update it.
|
|
Message #154071
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Online Version Differs from Zip Version
Hello,
I noticed that the online version of the application works perfectly well in terms of displaying error messages and the such.
Unfortunately, the downloadable source doesn't have the same behaviour.
Example:
Online - when you "create" a new item and supply text when numbers are needed, you get redirect to the editItem.do page with a message saying "Value should be a number, entered:"... as expected.
ZIP - when you do the same thing with the downloaded version of the app, you get redirected to editItem.do but this time, no error message is displayed.
I am wondering what is happening here.
Any thought?
Thanks.
|
|
Message #162411
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
So ? Which framework ?
Michael, I am 100% with you in your struggle for the PRG pattern. You did a good job with your two navigation examples, using forwards and redirects. And I wanted to know what framework do you use to implement it. Struts, Spring MVC, Tapestry, JSF, ? None of those allows to natively implement the framework, and it's a BIG shame. So ? Two solutions : the first is to mess up with the framework, the second is to redefine the navigation layer.
I had a look at your source code, it seems that you chose the first solution. Although your idea to use Output ActionForms as view beans is quite good, Struts was not thought this way : you end up calling your business layer in the validate() method of your OutputActionForm to populate it. That's baaad. Another remark is about how you add the "id=xxx" to the URI before performing the redirect : I think a good PRG implementation should take care of such a mechanism. Final remark, about form non-validation : The errors messages must be saved /temporarily/ in session, so you can display them back to the user after the REDIRECT.
I started thinking about redefining the Struts' RequestProcessor, but it's such a mess to override its behavior. Then, I thought I would create my own PRG framework implementation from scratch - bad idea, there are enough frameworks on the market place. So, before going further, I'm looking now at JSF, but I feel like these navigation rules will quickly drive me crazy. Also, I have to say that I'm not a big fan of using events & eventlisteners in a web environment. They might lead developers to some horrible confusion.
|
|
Message #162442
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
So ? Which framework ?
You did a good job with your two navigation examples, using forwards and redirects. And I wanted to know what framework do you use to implement it. Struts, Spring MVC, Tapestry, JSF, ?None of those allows to natively implement the framework, and it's a BIG shame. So ? Two solutions : the first is to mess up with the framework, the second is to redefine the navigation layer.I had a look at your source code, it seems that you chose the first solution. Although your idea to use Output ActionForms as view beans is quite good, Struts was not thought this way : you end up calling your business layer in the validate() method of your OutputActionForm to populate it. That's baaad. Another remark is about how you add the "id=xxx" to the URI before performing the redirect : I think a good PRG implementation should take care of such a mechanism. It is common now to blame Struts in all possible sins. But Struts is not that bad. It was built on top of servlet/JSP technology, it is easy to understand for anyone who knows servlets/JSP, and it provides some additional helper services. But it keeps the idea of HTTP request/response relatively clean and observable. This is what I like about Struts. It is small. It allows me to work with HTTP, while providing some additional service to define controller components and to route the requests.
So, having some basic HTTP knowledge, then servlet knowledge, then Struts experience, I got used to the simple request/response approach. Page-oriented event-driven design like JSF is something that I consider more restrictive. Struts allows to work closer to the browser, and to do some HTTP tricks that other frameworks do not allow.
Case it point: I need to POST to a certain URL, update the model, then redirect. Then after redirect, I want to check the model state and to forward to a proper JSP. HOW CAN I DO THIS IN JSF? JSF is page-oriented. I must load a certain page, then perform action on it, then it would define the next page. I cannot implement my two-stage approach in JSF without a hack. Which I am thinking on now. Maybe bare JSP scriptlet will do?
And of course, I would not be able to pass request parameters to redirected URL. I think that cannot do this in WebWork either, because in WebWork action returns string mapping only, and actions are separated from HTTP layer.
The benefit of passing URL parameters back to redirected URL is that it allows to access data items uniformly either (1) from a page using link and item ID, or (2) through redirect, adding item ID to the URL. But apparently this does not work in most other frameworks, and even in Struts it is kinda hackish, so I am going to abandon the idea of uniform access, and to use session to store parameters needed after redirect.
Calling business layer from validate() is not bad. Why? I have nothing else to do in validate(), I have the whole method to spare, which is called in the right time. What if it was called prepareView(), would you still think that it is bad? Anyway, if you want to make things "proper", define your own small action class instead of using ForwardAction.
I wrote some thoughts about URL/redirect issues in my blog: Struts, WebWork, redirect and friendly URLs Why Struts form beans suck at validation Have an advice for me?
Final remark, about form non-validation : The errors messages must be saved /temporarily/ in session, so you can display them back to the user after the REDIRECT. Am I not doing that? I am doing that ;) See Error handling
I started thinking about redefining the Struts' RequestProcessor, but it's such a mess to override its behavior. Then, I thought I would create my own PRG framework implementation from scratch - bad idea, there are enough frameworks on the market place.So, before going further, I'm looking now at JSF, but I feel like these navigation rules will quickly drive me crazy. Also, I have to say that I'm not a big fan of using events & eventlisteners in a web environment. They might lead developers to some horrible confusion. Right. The simple "request with params"/"response with page" approach is easier to understand (for me) and is more flexible. This is why I am still stuck with Struts. Actually, I have my own very lean addon for Struts, which makes it simple and easy to do redirects and to to keep messages in session. I am adding another component to it, Easy Wizard, which I use for small controlled flows. Will be ready in about a week. The whole CRUD example application got much simpler. Come back in about 10 days ;)
|
|
Message #162667
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
So ? Which framework ?
Thanks a lot, I'll check your struts "PRG addon" !
Calling business layer from validate() is not bad. You are right, maybe it's just a matter of naming things.
Also, about what you say about "friendly URLs" : I don't know what's a "nice-looking" URL (myapp/viewItem.do?id=6758 or myapp/item6758/view, what's the difference for the final application), and I don't even care about having an URL of the form /servlet/com.foo.bar.MyServlet?id=111. To me, the most important thing is not to have an unrefreshable URL like "deleteItem.do?id=123" displaying a list of items after a POST. And, SADLY, that's how most developers seem to use Struts. Any URL is friendly to me when it contains all the information that the server needs to display the correct page, i.e. when it is bookmarkable. This behavior should be so obvious for anyone...
Finally, one last thing I regret about Struts : it cannot populate ActionForms recursively - or it's very limited on the issue. What if I have an Action Form containing 2 or n sub-forms, or if I want to be able to edit 2 or 3 items at one shot ? I read that it's something that JSF or Spring can do...
By the way, Michael, did you try Struts Shale ?
|
|
Message #175379
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
So ? Which framework ?
Michael, I am 100% with you in your struggle for the PRG pattern. You did a good job with your two navigation examples, using forwards and redirects. And I wanted to know what framework do you use to implement it. Struts, Spring MVC, Tapestry, JSF, ?None of those allows to natively implement the framework, and it's a BIG shame. So ? Two solutions : the first is to mess up with the framework, the second is to redefine the navigation layer. Arnaud, I was busy with another project of mine, the Easy Wizard. Then I was integrating Easy Wizard into Struts, while trying to use the knowledge that I got. So, here it is, the first set of usable PRG components. Or, as I prefer to call this pattern now, "two-phase input processing" components for Struts:
Project homepage: http://struts.sourceforge.net/strutsdialogs Live demos: http://www.superinterface.com/strutsdialog CRUD sample source code: in src\net\sf\dialogs\samples\crudaction directory of the dialogs-1.1.zip file.
|
|
 |
New content on TheServerSide.comNew content on TheServerSide.comNew content on TheServerSide.com |
 |
 |
Reza Rahman explores the features of the proposed JSR 299, Contexts and Dependency Injection for Java EE (CDI). When approved, it promises to be a key feature of Java EE 6.
(November 2, Article)
SAML is an XML-based standard for exchanging authentication and authorization data between security domains. The single most important problem that SAML was created to solve is the Web browser Single Sign-On problem. Many organizations are debating whether to stay with version 1.1 or move to 2.0. This article makes observations about both options.
(September 28, Article)
Joe Ottinger takes a look at how people learn, and applies it to the practice of programming. He notes that understanding how people learn is an essential part of working in a programming team.
(September 22, Article)
Stephen Maryka gave us an article about the Asynchronous Web and posed a number of questions that get examined like an approach to delivering Asynchronous Web capabilities through extensions to existing Java EE technologies.
(July 14, Article)
JavaServer Faces Flex goal is to provide users capability in creating standard Flex components, part of flexSDK which is open sourced through MPL license, as normal JSF components. This article by Ji Hoon Kim will provide an overview of creating a simple multilingual JSF page consisting of JSF Flex tags.
(June 29, Article)
In this session Jeff explores the key characteristics of successful SOA projects. He covers some of the patterns, and anti-patterns, tool sets, and strategies that he himself learned the hard way. Last, he provides a strategy and blueprint for achieving a high likelihood of success in your SOA project.
(June 23, Tech Talk)
Ari Zilka, CTO of Terracotta, Inc., talks about the new features in Terracotta 3.1, announced during JavaOne and available now.
(June 15, Tech Talk)
In this Tech Talk, Josh Long explores an integration challenge using Spring Integration and walks through the implementation, employing and expanding on the basic patterns of Enterprise Application Integration to tie together components into a function integration solution, and then demonstrates how Spring Integration helps address the integration requirements.
(June 15, Tech Talk)
In this Tech Talk, David Geary teaches you: The basics of Google Web Toolkit; How to implement Ajax-enabled applications in Java; Internationalization; Hooking into the browser history mechanism; Remote procedure calls.
(June 4, Tech Talk)
Jon Kern discusses the best architecture/technical solutions and ensure that they are repeated by all developers. By tackling the architecture up-front in a serial manner, subsequent parallel development will be much more manageable and predictable.
(May 28, Tech Talk)
This keynote describes the frustrations of modern knowledge workers in their quest to actually get some work done, and solutions for how to guard yourself against all those distractions. Neal Ford talks about environments, coding, acceleration, automation, and avoiding repetition as ways to defeat the misguided attempts to sap your ability to produce good work.
(May 26, Tech Talk)
Gil demonstrates how new, aggressive uses of already abundant compute capacity by common applications offer competitive value for application designers.
(May 21, Tech Talk)
Chris Keene introduces WaveMaker as a new way to automate the ability to generate Hibernate classes in order to more quickly bring OR mapping into an application.
(May 19, Article)
In this session Nati Shalom demonstrates how to take a standard Java EE web application and scale it out or down dynamically without changes to the application code. Seeing as most web applications are over-provisioned to meet infrequent peak loads, this is a dramatic change because it enables growing your application as needed, when needed, without paying for unutilized resources.
(May 19, Tech Talk)
Download the entire book of Jakarta-Struts Live and learn about Struts MVC, Tiles, the Validator, DynaActionForms, plug-ins, internationalization, and more.
(Book PDF Download)
The Application Server Matrix is a detailed listing of J2EE vendors and their application server products, with information on latest version numbers, J2EE spec support and licensing, pricing, platform support, and links to product downloads and reviews.
(Application Server Comparison Matrix)
|
|