Multiple Request Response Forward - java

I am currently passing some ArrayList's from my servlet to my JSP page using the below code.
RequestDispatcher rd = null;
request.setAttribute("date",al);
request.setAttribute("bau",al1);
request.setAttribute("project",al2);
rd = request.getRequestDispatcher("ResourceChart.jsp");
rd.forward(request,response);
The problem is when I click refresh on the page, the same date is passed again and I end up with odd results. Should I be forwarding to the JSP page as well to avoid the servlet regenerating the variables and passing them?
Whats the best way to implement this?

You're apparently refreshing a POST request and ignoring/confirming the browser's builtin warning that the data would be resent. In that case, the doPost() method will indeed be re-executed with the previously submitted data which would only end up in duplicate entries in the DB.
The canonical approach to avoid the double submit on a refresh of a POST request is to send a redirect after POST request. A redirect implicitly creates a new GET request. Refreshing would then result in only the GET request being re-executed which is totally harmless.
To achieve that, replace all in the question shown lines of the doPost() by the following single line
response.sendRedirect(request.getContextPath() + "/ResourceChart");
(assuming that your servlet is mapped on an URL pattern of /ResourceChart)
and create a new doGet() method wherein you put all those removed lines back, along with the necessary logic to prepare the lists. The only change which you need to make is to put the JSP file in /WEB-INF folder to avoid endusers from being able to open it directly by entering/guessing its URL without calling the servlet's doGet() first.
request.getRequestDispatcher("/WEB-INF/ResourceChart.jsp").forward(request, response);
See also:
Our Servlets wiki page

Related

Unable to redirect to another page in AEM using request dispatcher in sling servlet via POST

I have a scenario where from one page in AEM, I need to call another AEM page in the same application and I need to pass some hidden parameters. I choose to do it via POST and below are the steps which I followed:
From page "A", I did a form submission via POST to the sling servlet and passed some parameters.
2. In the servlet, using request dispatcher I redirected the same request and response to a different page in doPost method using the following code snippet:
request.getRequestDispatcher("/content/company/en/apps/welcomepage.html").forward(request, response);
When I run the code, I am able to call the servlet through form submission but I am not able to redirect to a new page. I see the below error in logs:
18.10.2017 14:41:00.802 ERROR [127.0.0.1 [1508352060795] POST /bin/rap/welcomepage HTTP/1.1] org.apache.sling.servlets.post.impl.operations.ModifyOperation Exception during response processing.
javax.jcr.nodetype.ConstraintViolationException: No matching property definition: appointmentTypeId = platform001d
at org.apache.jackrabbit.oak.jcr.delegate.NodeDelegate.setProperty(NodeDelegate.java:522)
at org.apache.jackrabbit.oak.jcr.session.NodeImpl$35.perform(NodeImpl.java:1375)
at org.apache.jackrabbit.oak.jcr.session.NodeImpl$35.perform(NodeImpl.java:1363)
at org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.perform(SessionDelegate.java:208)
at org.apache.jackrabbit.oak.jcr.session.ItemImpl.perform(ItemImpl.java:112)
at org.apache.jackrabbit.oak.jcr.session.NodeImpl.internalSetProperty(NodeImpl.java:1363)
If I try the same code in doGet method it works fine. Also if I use response.sendRedirect("/content/company/en/apps/welcomepage.html") it works fine too. But the problem with this is it initiates it as a new request to the page and it looses all the parameters which I get from the form submission. Could someone please let me know like how can I redirect a request to a page in AEM via POST since I need to pass some hidden parameters whic should not be visible in the url ?
Here is the way I understand your question
User visits page "A"
User fills a form, then submits.
Your custom servlet handles the submitted POST request and calls:
request.getRequestDispatcher("/content/company/en/apps/welcomepage.html").forward(request, response);
You get the ConstraintViolationException
Why do you get this exception?
Since you are using forward the POST request is forwarded to /content/company/en/apps/welcomepage.html that node is most likely of type cq:Page, which has constraints on which properties can be added. Think of it as a simple post request trying to store parameters on the cq:Page node.
What can you do?
Since I don't understand your use-case and particularly why you need to preserve the submit params, I cannot recommend a specific solution. However, since you don't want the parameters in the URL, here is a potential solution you can try:
In your servlet handler, see those hidden params to cookies on the response.
use response.sendRedirect("/content/company/en/apps/welcomepage.html")
On any of the components in /content/company/en/apps/welcomepage.html, you can get the request cookies and process them however you like. same way you wanted to process those hidden params.
Now the flow becomes:
User visits page "A"
User fills a form, then submits.
Your custom servlet handles the submitted POST request, adds your special params to cookies on the response, then calls response.sendRedirect("/content/company/en/apps/welcomepage.html")
User's browser receives a 301 response with the cookies, sets the cookies in the browser then requests "/content/company/en/apps/welcomepage.html"
Your components handle the request and get the params from the cookies, then retuns the appropriate response.

how to rewrite the url in java web application?

On Form Submit my url changes from
localhost:8080/Workflow/admin/GetReports?fname=Form1
to
localhost:8080/Workflow/admin/EditReport
Form action is EditReport(Servlet Name).
Now on EditReport i perform the databse operations and forward the request to the GetReports?fname=Formname Servlet using Request Dispatcher.So that i am on the same page which is the first one (1) i started from.
Now Everything works fine on the .jsp page But the url remains unchanged that is the second one (2).
So how to rewrite the url i.e. from admin/EditReport to /admin/GetReports?fname=Form1
Are you using dispatcher.forward because you are setting some Attributes in
the Request?
If not, then you don't need to use Forward. Instead of that, use response.sendRedirect("url for GetReports?fname=Form1")
But If you are setting some Attributes in the request, then I am wondering if your workflow is a correct one because URLs like this "Workflow/admin/GetReports?fname=Form1" should Not be arrived upon after doing some processing. They should be simple HTTP GET requests only.

How does doGet() support bookmarks?

Reading below link , I could note that "doGet() allows bookmarks".
http://www.developersbook.com/servlets/interview-questions/servlets-interview-questions-faqs.php : search "It allows bookmarks"
Can anyone tell how and what is the use of it ?
All the parameters of GET request are contained in the url so when you are requesting for a resource using GET request, it can be formed using request URL itself.
Consider an example www.somesite.com.somePage.jsp. This generates a GET request because we are asking for a resource somePage.jsp.
If you are asking for a resource, then it is the GET request.
GET requests are used to retrieve data.
any GET request calls the doGet() method of servlet
GET requests are idempotent, i.e. calling the same resource again and again do not cause any side effects to the resources.
Hence, a GET request can have bookmarks
EDIT :-
As suggested by Jerry Andrews, POST methods do not have the query data unlike GET requests to form the resource properly with the help of only url. Hence they are not bookmarked.
It means that If you bookmark the URL of the servlet that has doGet() implemented, you could always get the same page again when you re-visit. This is very common when you have searches, link for products, news, etc.

Url Shortener redirects to index.html

Yes, yet another url shortener written in java, because I wanted my own, and because why not. Currently everything works, just not they way I want to to. In short, there is only one servlet mapped to "/" in the entire project. There are no frameworks involved, or anything fancy, this is just a basic Servlet "project". on doPost a new shortUrl is created, and you get a JSON response. On doGet, if the URL is "/*{any_valid_short_url}" then a redirect is sent (below).
response.sendRedirect("longUrlString")
The issue I am having is with the index page, when the same doGet is called, I check the requested path, if it is "/" then currently, I use a FileInputStream and stream the index.html page out via response.getOutputStream(), which is pretty hacky in my opinion. I would like to use a requestDispatcher instead, however when I do try to implement that (below) I get into a re-direct loop, and the servlet container (jetty or tomcat) stack overflow's.
getServletContext().getRequestDispatcher("/index.html").forward(req, res);
Is there something that I am mis-understanding about how this is being done? The project is currently hosted on my github page. https://github.com/justinmburrous/ShortUrl
You need to make this check more narrower, because for all requests this condition is true and hence for all requests are forwarded to 'index.html' again and again
if(requestedPath.equals("/")){
//tried with multiple variations of /index.html, renamed to jsp, etc...
RequestDispatcher dispatcher = request.getRequestDispatcher("index.html");
dispatcher.forward(request, response);
}
Edit:
Since your servlet is mapped as default servlet , all forwards or request will be handled by this Servlet.
You should map the url to more specific range.
RequestDispatcher - forward - produces infinite loop
Okay, I have figured this one out with thanks to How to access static resources when mapping a global front controller servlet on /*
My github page has the working code along with the Filter, modified servlet and web.xml for.

Java Servlets, how to keep request attribute alive across several forwards?

I have a home-grown MVC implementation. A ControllerServlet like so:
/controller?cmd=EditUser&userid=55
From this URL, the controller creates a EditUserCommand.class instance and calls an execute() method which returns the result page (ex. user.jsp) to display.
The controller servlet then does a ...
getRequestDispatcher(resultPage).forward(request, response);
... and the resulting page is shown.
One of the things the controller does is set messages (error, info, and so on) as request attribtues. For example:
request.setAttribute("infoMessage", "User was edited successfully.");
And that message gets pulled out of the request in the user.jsp page and displayed.
Works fine.
Now here comes my problem.
Sometimes my commands don't return a page like user.jsp but return a URL like cmd=ShowUser&userid=55 for the result. This is because there might be things I want to check before displaying the final page, like permission to view the user and so on.
When I do this the "infoMessage" I placed in the request never appears because the result is a URL that makes a new call to the servlet, which is a new request. The new request doesn't maintain the request attributes from the first request; which makes sense, I just didn't forsee this happening.
How can I make my request variable "stay alive" until it's actually displayed on the final page that results from the original request?
Any suggestions or advice are appreciated. Just FYI, I can't re-write the entire app to go to something like Struts, Spring MVC, of JSF. It's not an option.
Thanks!
Rob
redirect generally looses request data because of brand new request from browser. One possible approach may be append your message to url string as attribute and read it when you need.
Based on your EDIT: After your edit also, my answer make sense. But, only one correction is, it is not brand new request because forward happens on server side.
Have you tried using a RequestDispatcher instead of a Redirect?
RequestDispatcher dispatcher = request.getRequestDispatcher("/myNextPage.jsp");
dispatcher.forward(request, response);
You may be giving a simple example, but your control flow causes the "Resend" Error, perhaps? Basically, after making any change to the data, the controller must immediately do a "Get" via a redirect and the screen should be displayed completely stateless.
Please take a look:
http://en.wikipedia.org/wiki/Post/Redirect/Get
As such, Attributes are not a great help. What you may want to consider is, maintaining a Bean/Object for every login user, and persist this object in a LRU cache (JCache or MemcacheD), and retrieve it on every entry to the application. Once you have that, you can maintain a pseudo-state such as previous results in that object.
In any case, using Attributes to retain state will severely constrain your options. You need to have a more generic flexible routing-independent mechanism.

Categories