Why does servlet name stay in url after RequestDispatcher.forward? - java

I am making a JSP/Servlet web app which starts with log in page.
After user enters log in information, a servlet, called LoginServlet, processes the data and if the log in is successful the servlet redirects user to MainPage.jsp like this:
RequestDispatcher rd = request.getRequestDispatcher("MainPage.jsp");
rd.forward(request,response);
It works. It takes me to MainPage.jsp, only the URL is NOT:
http://localhost:8080/RestauRec/MainPage.jsp
it is:
http://localhost:8080/RestauRec/LoginServlet
It is not an actual problem, but still, I want to know why this is and how can I change this?
Note: I don't know if it matters or not but, in the action attribute of the form element (in the log in page) I place LoginServlet. Like this:
<form action="LoginServlet" method="POST">
Thanks in advance!

forward is an action that happens within a single request-response cycle. It uses the forward-to resource to complete the response.
Your browser sends a single request to /someUrl and your server handles it, returning a response.
It is not an actual problem, but still, I want to know why this is and how can I change this?
You'd have to make your client, the browser, send a different request to another URL, possibly because of a redirect.

forward() method won't change the url. sendRedirect() in HttpServletResponse do change the url as well.
response.sendRedirect("MainPage.jsp");
Remember that a new request gets hit to the container when you do redirect. That means all the previous data vanishes and you'll get a brand new request.

Related

How to set an attribute in a jsp page with hyperlink (request scope)

I think the title above is a bit confusing.
What I'm trying to achieve:
I have a jps page(located in WEB-INF) with a hyperlink in it that will call another jsp (in WEB-INF) via servlet.
I understand that this can be achieved using the following:
Go to this page
But because there will be lots of hyperlinks, my idea was to have a general servlet(OpenPagesServlet) to handle all those pages.
Something like this:
JSP page:
<% request.setAttribute("page", "page1.jsp");%>
Page 1
OpenPagesServlet in doGet method:
String page = (String) request.getAttribute("page");
request.getRequestDispatcher("/WEB-INF/" + page).forward(request, response);
I tried the code above and I get:
HTTP Status 404 - Not Found
type Status report
messageNot Found
descriptionThe requested resource is not available.
But if I try with session.setAttribute / sesion.getAttribute the code works fine, but I don't want to have sessions on each time I click on hyperlinks.
The other approach I found was to use:
Page 1
and inside the servlet:
String page = (String)request.getParameter("value");
request.getRequestDispatcher("/WEB-INF/" + page).forward(request, response);
It worked, but this approach is not good because the page can then be accessed directly using the url:
http://localhost:8080/WebApp/OpenPagesServlet?value=page1
So...my question is why request.setAttribute/request.getAttribute is returning 404?
Is there a different approach to achieve what I'm trying to do?
An HttpServletRequest and its attributes only live for the duration of one HTTP request/response cycle. After yo've set the attribute in the JSP, the JSP is rendered and sent as part of the HTTP response body. The Servlet container considers the request handled and clears its attributes. The attribute is now gone.
It is therefore no longer available in the next request that arrives after the user clicks the link.
The session attribute or request parameter is fine. Consider looking into the Front Controller pattern.
Also, consider using the core tag library (in particular the url tag) instead of scriptlets for constructing your links.

Stop form submit after page refresh with DispatcherServlet

I use request.getRequestDispatcher(url).forward(request, response) method in my controller !! I am in trouble. (I know that dispatcher make internal redirect, a forward reuses the current request), when I fill in a form and send request to controller that computes some logic and after forward to some simple page. If I push F5 in browser on my simple page (refresh page) my request will perform again. How to prevent this situation ??
RequestDispatcher will keep request attributes and forward page with same request, that is why if you refresh page controller gets same request and process it again. Use SendRedirect instead.

Servlet redirect doesn't display requested page

I have a page - lets call it page X - where I do an ajax call that populates my table constructed with jqGrid. So here I call localhost:8080/servlet/ajax/Data.json which is a servlet.
Now, if the page expires and the user still wants to access the table (search data for instance) I would like to redirect the request to the Login page.
The ajax call calls the Data.json servlet that is not in the same servletcontext as my Login page (which is localhost:8080/servlet/myapp), therefore I cannot use servlet forward (I am using JBoss 4.2 and I can only forward in the same servletcontext).
I have tried to redirect with sendRedirect, which is able to call the Login page that is actually executed but not displayed. And this is where I got lost. My Login page is executed and I still see page X.
I have tried to write the returned HTML (from Login page) into the response of page X (I also set the Content-Type to text/html). The HTML is returned in the response, but not displayed.
I am using Apache Turbine which is another servlet that retrieves a page when requested.
Do you have any ideas? I don't know what to do.
It looks like your servlet at servlet/ajax/Data.json is telling the AJAX request to redirect to the login page. Then the page is going to try to render the jqGrid table with the login page, which probably won't work.
You need to add code where you are making the AJAX call to servlet/ajax/Data.json to check to see whether the browser itself needs to be redirected. Either if the servlet returns a 302 redirect as a response, or if the servlet returns an error that's simply "SESSION EXPIRED", so the javascript on the browser's end that's making the AJAX call to the servlet knows the session has expired and to redirect the browser to the login page.
Ajax calls are asynchronous calls, sendRedirect call on ajax calls never be effective (ajax response always sends response to initiator).
You may need to use XMLHttpRequest status code to find out the page expiration and then use java script window.location to reset the browser url to login url.

Using JSF 2.0 / Facelets, is there a way to attach a global listener to all AJAX calls?

Is there a way to attach a global listener to all AJAX calls in JSF? Maybe through a phase listener or something?
Here is the conundrum... Lets say you're using f:ajax tags and something like apache shiro and you let your session expire. Then you come back and click a button that has an f:ajax attached to it. The server will respond with a 302 redirect to the login page.
The user sees nothing. They can repeatedly click and invoke the ajax call, but to them the app is just "dead."
So, my though is, is there a way to attach a listener to all ajax calls in JSF? If so, what I'd like to do is monitoring the response code. If it's a redirect, use a window.navigate to send them along their way.
I'm always open to hear how others have solved this problem!
Is there a way to attach a global listener to all AJAX calls in JSF? Maybe through a phase listener or something?
Yes, a PhaseListener can do it. A SystemEventListener also. A Filter also.
If you're inside JSF context, then you can check as follows whether the current request is an ajax request or not.
if (FacesContext.getCurrentInstance().getPartialViewContext().isAjaxRequest()) {
// It's an ajax request.
}
If you're not inside JSF context, e.g. inside a Filter, then you can check as follows whether the current request is a JSF ajax request or not.
if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
// It's a JSF ajax request.
}
Here is the conundrum... Lets say you're using f:ajax tags and something like apache shiro and you let your session expire. Then you come back and click a button that has an f:ajax attached to it. The server will respond with a 302 redirect to the login page.
The user sees nothing. They can repeatedly click and invoke the ajax call, but to them the app is just "dead."
Forcing a redirect on an ajax request requires a special XML response. When you're inside JSF context, then ExternalContext#redirect() already takes this implicitly into account. All you need to do is to write this:
FacesContext.getCurrentInstance().getExternalContext().redirect(url);
If you're not inside JSF context, e.g. inside a Filter, then you'd need to write the whole XML response yourself. E.g.
response.setContentType("text/xml");
response.getWriter()
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
.printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", url);
To redirect a jsf ajax request you need xml as follows
<?xml version="1.0" encoding="UTF-8"?>
<partial-response>
<redirect url="XXX">
</redirect>
</partial-response>
Here XXX is url you want redirect to happen.
On ajax call redirect sent is not as above hence no redirect.
To get the desired result have a filter for all jsf request except few
pages(login page) and check session is valid and if it is really jsf
ajax call by checking header "Faces-Request", its value should be
"partial/ajax". If session has expired and is ajax request send above
xml as response.
It should work.

Login page redirection in Java and Javascript

Ok, so I've got an interesting case of login page redirection going on.
My webservice has a login page (login.html) with some javascript to handle logging in and redirecting to a hardcoded 'default' page. The webservice is written in Java with a servlet filter handling redirection if a user is unauthenticated (so if a user tries to access domain/statistics without being logged in, they are directed to domain/login.html). The redirection from the protected services works: I can redirect to the login page and once a user is authenticated, redirect them to a default page. I am having issues, however, redirecting to the previous page.
I know this is usually handled with the argument document.referrer in the Javascript, which I have tried, but due to the Java's redirection with response.sendRedirect, the Referer header is not sent.
How can I get these two aspects to redirect to the previously called page? Is it something I need to add on the Javascript side, the Java side, or both?
What I've done is to drop the original (redirected) URL into a hidden input field on the login form. The code that does the authentication should just check that parameter, and if it's not empty it can redirect after establishing the session.
You have to be careful doing this to prevent XSS attacks etc., but it's not that hard and it works just fine.
In my framework (Stripes), I can push the original URL (taken from the HttpServletRequest object, a combination of the servlet path, the "path info", and the query string) into a special holding box that will cause the framework to give it back to me on the next request as a parameter. Without that, the simple thing to do is add the URL as a parameter when you redirect. Just URL-encode the original attempted URL and tack it onto the redirect URL with some parameter name. Then, on your login page, you just check for it:
<c:if test='${not empty param.attemptedUrl}'>
<input type='hidden' name='attemptedUrl' value='${fn:escapeXml(param.attemptedUrl)}'>
</c:if>
Then your login action will get that parameter too when the login form is submitted, and it can act on it as appropriate.
Send Redirect will ask to the client to repeat the request to the resource you choose. Have you think of Spring Security with minimal configuration you can achieve this quite easily.
Take a look at this:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html

Categories

Resources