This is a quick question but I couldn't find a quick answer.
Now I have a servlet BaseServlet,
when user request any of the url below:
host
host/
host/BaseServlet
It should always refer to the same servlet and redirect to the homepage.
When I set
#WebServlet({"/BaseServlet", ""})
Only
host/
host/BaseServlet
works
If I set
#WebServlet({"/BaseServlet", "", "/"})
The BaseServlet will be requested constantly in loop ...
Why?
Edit:
BaseServlet does a forward to the index.html hid in WEB-INF folder and that's it.
getServletContext().getRequestDispatcher("/WEB-INF/index.html").forward(request,response);
The servlet spec says "A string containing only the / character indicates the "default" servlet of the application." So I want the BaseServlet to be my default. Why it doesn't work?
As you state in your Q, if you want the following:
host/
host/BaseServlet
Use
#WebServlet({"/BaseServlet", ""})
If you want the following:
host
Add this to your welcome file (you can't specifiy welcome files using annotations)
<welcome-file-list>
<welcome-file>/BaseServlet</welcome-file>
</welcome-file-list>
The servlet spec says "A string containing only the '/' character indicates the "default" servlet of the application."
But it says straight afterwards
In this case the servlet path is the request URI minus the context path
and the path info is null.
In other words, if your URL is
host
then the servlet path will be
"" (empty string)
so you will need a welcome file list (but index.htm[l] and index.jsp in the webapp directory, not WEB-INF, are included implicitly as a starting welcome file list)
Edit:
If you want to pre-process then you can use Filter with url-pattern "/*" and dispatcher set to REQUEST that way it will ignore forward.
Last value "/" means all request.
Checkout discussion at: http://www.coderanch.com/t/366340/Servlets/java/servlet-mapping-url-pattern
And inside Servlet another forward request for index.html is generated which is also intercepted by servlet.
If you try #WebServlet({"/BaseServlet", "/"}) which is same as #WebServlet({"/BaseServlet", "", "/"}) will result in same error.
You can check this by typing following output statement in servlet:
System.out.println(req.getRequestURL());
Related
When using a request dispatcher in a servlet to forward to a JSP why must the JSP be denoted with a forward slash like the following-:
getServletContext().getRequestDispatcher("/foo.jsp").forward(request, response);
If I use it without the forward slash I get an exception in Tomcat.
But when I use request dispatcher for redirecting to servlets then I can omit the forward slash. The below code fragment works fine provided there is a servlet mapped to the url pattern-:
getServletContext().getRequestDispatcher("bar").forward(request, response);
I know that the / means the root of the web-app but why isn't it required for servlets but only for JSPs ? Servlets also belong to a particular web-app.
Your are mistaken to believe that the forward slash means root of the web app. It can sometimes mean that, but not always.
The forward slash '/' character is used in JSPs within links eg:
Stuff page
and in servlets by the RequestDispatcher.forward() and HTTPResponse.sendRedirect() methods for URL redirections.
It only has an effect when applied at the beginning of your redirection URL.
Here are the rules for how it is interpreted behind the scenes by the your application server:
First of all: Please be aware that the redirection address is always CASE SENSITIVE -even in the domain segment of your redirection-URL. See my comments in example code below to see an illustration of this through examples of what will work and what will fail.
If the redirection commences with 'http://', the ABSOLUTE path as specified, will be used in the redirection.
Otherwise your redirection URL will be applied as a relative URL.
If the redirection URL commences with a forward slash character '/', your application server is instructed to construct a URL RELATIVE to the web container!
For example: relative to localhost:8080
So the command...
response.sendRedirect("/foo/stuff.htm")
from inside a servlet, or
Stuff page
from inside a JSP, will take you to
localhost:8080/foo/stuff.htm.
The ABSENCE of a forward slash at the beginning of your redirection-url (together with the absence of a protocol signature) will instruct the app server to construct its url relative to the ORIGINAL REQUESTED URL! That is, the URL typed into the browser by a user at the client-side.
It is important to be aware that this constructed URL is neither
relative to the domainnor
relative to the web container!
Once again: the url constructed by the application server will be relative to the original url requested by the client!
So for example: if a client provides the URL
http://www.example.com/level1/level2/stuff.htm
then the command... response.sendRedirect("foo/stuff.htm") from within a servlet or,
Stuff page from within a JSP, will redirect you to http://www.example.com/level1/level2/foo/stuff.htm
// WILL NOT WORK! Reason: Case sensitivity.
response.sendRedirect("/teluskolearnings/login.jsp");
// WILL WORK! Reason: Case sensitivity.
response.sendRedirect("/TeluskoLearnings/login.jsp");
// Will redirect to localhost:8080/login.jsp as the forward slash tells app
// server to build the url RELATIVE TO THE APP SERVER.
// So you will be pointed to 'http://localhost:8080/login.jsp'.
// This is not what we want.
response.sendRedirect("/login.jsp");
// Will redirect to localhost:8080/TeluskoLearnings/login.jsp
// as the ABSENCE of forward slash tells app server to build the url
// RELATIVE TO THE URL!
// So you will be pointed to
// 'http://localhost:8080/TeluskoLearnings/login.jsp'.
// This IS what we want.
response.sendRedirect("login.jsp");
// Will redirect to localhost:8080/TeluskoLearnings/foo/login.jsp
// (you can see the redirection in the address bar, even if you get a
// 404 - page not found) as the ABSENCE of forward slash (at the start) tells
// app server to build the URL RELATIVE TO THE REQUESTED URL!
// This also means that if the user entered
// 'http://localhost:8080/TeluskoLearnings/level1/level2/stuff"'
// he will be pointed to
// 'http://localhost:8080/TeluskoLearnings/level1/level2/foo/login.jsp'
// (provided of course, that "/level1/level2/stuff" is captured inside the
// urlPatterns parameter of the #WebServlet() annotation).
response.sendRedirect("foo/login.jsp");
SEE: https://www.safaribooksonline.com/library/view/head-first-servlets/9780596516680/ch04s27.html
All the servlet objects are running at the same place in container but jsp goes to different place.
SERVLET LOCATION AFTER DEPLOYEMENT
You will find all the servlets here
apache-tomcat-7.0.55\webapps\Test\WEB-INF\classes\com\it\servlet
MainController.class
ABC.class
JSP LOCATION AFTER DEPLOYEMENT
apache-tomcat-7.0.55\work\Catalina\localhost\Test\org\apache\jsp
apiTester_jsp.class
Consider the following hierarchy :
When I send redirect like this :
response.sendRedirect("error404.jsp"); // no path here !!!
I reach the page error404.jsp .
But when I use a path :
String addressPath = "/WEB-INF/results/admin/adminPage.jsp";
response.sendRedirect(addressPath); // with path !!!
I get 404 :
HTTP Status 404 -
type Status report
message
description The requested resource is not available.
Apache Tomcat/7.0.50
What am I doing wrong here ?
Much appreciated !
See the javadoc
This method can accept relative URLs;the servlet container must
convert the relative URL to an absolute URL before sending the
response to the client. If the location is relative without a leading
'/' the container interprets it as relative to the current request
URI. If the location is relative with a leading '/' the container
interprets it as relative to the servlet container root. If the
location is relative with two leading '/' the container interprets it
as a network-path reference (see RFC 3986: Uniform Resource Identifier
(URI): Generic Syntax, section 4.2 "Relative Reference").
Note that the argument is not a path within the servlet context like a RequestDispatcher would use, it as a URL used in the Location header of the 302 response.
So this
String addressPath = "/WEB-INF/results/admin/adminPage.jsp";
response.sendRedirect(addressPath); // with path !!!
will be transformed into a 302 response with the header
Location: http://whateverhost.com/WEB-INF/results/admin/adminPage.jsp
which you don't have a handler for, so 404.
On the other hand, this
response.sendRedirect("error404.jsp"); // no path here !!!
becomes
Location: http://whateverhost.com/context-path/error404.jsp
Since error404.jsp is outside WEB-INF, it is accessible and therefore rendered by the JSP servlet and returned as a response.
Because stuff under WEB-INF is not accessible to the client. Don't put your JSPs under WEB-INF if you want them to be accessible.
Alternatively, to make anything under WEB-INF accessible to the client, you would have to map it to a URL in web.xml:
<servlet>
<servlet-name>adminPage</servlet-name>
<jsp-file>/WEB-INF/results/admin/adminPage.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>adminPage</servlet-name>
<url-pattern>/adminPage/*</url-pattern>
</servlet-mapping>
Then use the url-pattern you mapped:
response.sendRedirect("./adminPage/");
Which is rather pointless. You could achieve basically the same thing with your JSP outside of WEB-INF and using a URL Rewrite Filter. In short, you probably have no real reason to put your JSPs under WEB-INF.
I have a problem with redirection - it simply does not work for valid paths.
Right now I use page forwarding in the Servlet, but I need redirection in a filter.
All the pages reside in the 'pages' folder and have a .jspx extension
I've tried the following (this path works with forwarding):
httpResponse.sendRedirect("/pages/login.jspx");
browser url is http://[localhost]/pages/login.jspx, and it shows Tomcat's 404 page, the context path (in my case it's '/hotel') is missing from the url, so, if I add it:
httpResponse.sendRedirect("/hotel/pages/login.jspx");
redirect does not happen, browser url does not change, and I'm shown the browser's 404 page (This program cannot display the webpage).
What am I doing wrong?
The filter which is used to test this has the following mapping:
#WebFilter(filterName = "SecurityFilter", urlPatterns = "/*")
The redirected URL is indeed relative to the initially requested URL. To dynamically prepend the context path it's recommended to use HttpServletRequest#getContextPath() instead of hardcoding it, because the context path value can be changed externally by server-specific configuration.
As to your concrete problem, I'm not sure if I understand "browser's 404 page" properly, perhaps you mean the browser-default error page which can occur when the server is unreachable or when the request has been redirected in an infinite loop (that should however have been made clear in the actual message of the browser default error page, at least Chrome and Firefox do that).
Given that your filter is mapped on /*, it's actually redirecting in an infinite loop because the request URL of the login page in turn also matches the URL pattern of the filter.
You'd need either to put the filter on a more specific URL pattern which does not cover the login page, e.g. on /secured/* where all restricted pages are been moved in there (or map it on /pages/* and put the login page outside there), or to fix your filter as follows:
String loginURL = request.getContextPath() + "/pages/login.jspx";
if (needsToRedirect && !request.getRequestURI().equals(loginURL)) {
response.sendRedirect(loginURL);
}
else {
chain.doFilter(request, response);
}
1 - Have you got logging or some other observable event in your servlet code that confirms it's definitely running?
2 - Redirects can fail if you write any actual response content prior to the redirect - have you anything doing that?
3 - Another option, set up a page in the root directory, even a "hello.html" static page, and see if you can redirect to that using either of "/hello.html" and "hello.html".
Just some ideas I would use in my own debug approach, hope something helps!
I am working on a cruise booking app using struts/tiles that uses multiple internal servlet/jsp forwards to reach the right jsp for display. But, once you reach the final jsp that is used to render the page, the ${pageContext.request.requestURL} call in that jsp returns the path of this jsp.
For example
Original request: /booking/getCruiseDetails
gets forwarded to: /booking/validateCruiseDeteails.jsp
gets forwarded to: /booking/validateUser.jsp
finally gets forwarded to: /booking/showCruiseDetails.jsp
So, in /booking/showCruiseDetails.jsp when I call ${pageContext.request.requestURL} I
get /booking/showCruiseDetails.jsp
How do you get the the original (client made) request url from a jsp that has been reached through multiple forwards. I did find the following posts on stackoverflow that hint at the solution here and here, but they don't address how you would go about finding the original request url after multiple forwards have occurred.
I found a better answer in this post [ How do you detect the URL in a Java Servlet when forwarding to JSP? ]
On the target JSP use:
request.getAttribute("javax.servlet.forward.request_uri")
To find out what the original URL was.
It doesn't require you to take any extra steps on the forwarding servlet
You can use a filter to putting origin address to request attribute and then read it from jsp
Filter mapped to /booking/* execute:
request.setAttribute("origin", request.getRequestURL());
Jsp:
${pageContext.request.attribute["origin"]}
This works because filter has set REQUEST dispatcher by default. It means filter executes only for direct client requests not for forwarding/including
${requestScope["javax.servlet.forward.request_uri"]}
or with single quotes
${requestScope['javax.servlet.forward.request_uri']}
Same as #Lenny Markus but using the provided constant in the Request Dispatcher class.
request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)
Consider using servlet filters instead to validate information. This means you can avoid your validation forwarding and just stay in a single JSP file.
You can show it without using a bean reference with the following:
<h:outputText value="#{requestScope['javax.servlet.forward.request_uri']}" />
Of course, you need to map the 404 page in your web.xml file though.
<error-page>
<error-code>404</error-code>
<location>/xhtml/pg/error/404.xhtml</location>
</error-page>
I'm making a simple, very lightweight front-controller. I need to match request paths to different handlers (actions) in order to choose the correct one.
On my local machine HttpServletRequest.getPathInfo() and HttpServletRequest.getRequestURI() return the same results. But I'm not sure what will they return in the production environment.
So, what's the difference between these method and what should I choose?
I will put a small comparison table here (just to have it somewhere):
Servlet is mapped as /test%3F/* and the application is deployed under /app.
http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=S%3F+ID?p+1=c+d&p+2=e+f#a
Method URL-Decoded Result
----------------------------------------------------
getContextPath() no /app
getLocalAddr() 127.0.0.1
getLocalName() 30thh.loc
getLocalPort() 8480
getMethod() GET
getPathInfo() yes /a?+b
getProtocol() HTTP/1.1
getQueryString() no p+1=c+d&p+2=e+f
getRequestedSessionId() no S%3F+ID
getRequestURI() no /app/test%3F/a%3F+b;jsessionid=S+ID
getRequestURL() no http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=S+ID
getScheme() http
getServerName() 30thh.loc
getServerPort() 8480
getServletPath() yes /test?
getParameterNames() yes [p 2, p 1]
getParameter("p 1") yes c d
In the example above the server is running on the localhost:8480 and the name 30thh.loc was put into OS hosts file.
Comments
"+" is handled as space only in the query string
Anchor "#a" is not transferred to the server. Only the browser can work with it.
If the url-pattern in the servlet mapping does not end with * (for example /test or *.jsp), getPathInfo() returns null.
If Spring MVC is used
Method getPathInfo() returns null.
Method getServletPath() returns the part between the context path and the session ID. In the example above the value would be /test?/a?+b
Be careful with URL encoded parts of #RequestMapping and #RequestParam in Spring. It is buggy (current version 3.2.4) and is usually not working as expected.
getPathInfo() gives the extra path information after the URI, used to access your Servlet, where as getRequestURI() gives the complete URI.
I would have thought they would be different, given a Servlet must be configured with its own URI pattern in the first place; I don't think I've ever served a Servlet from root (/).
For example if Servlet 'Foo' is mapped to URI '/foo' then I would have thought the URI:
/foo/path/to/resource
Would result in:
RequestURI = /foo/path/to/resource
and
PathInfo = /path/to/resource
Let's break down the full URL that a client would type into their address bar to reach your servlet:
http://www.example.com:80/awesome-application/path/to/servlet/path/info?a=1&b=2#boo
The parts are:
scheme: http
hostname: www.example.com
port: 80
context path: awesome-application
servlet path: path/to/servlet
path info: path/info
query: a=1&b=2
fragment: boo
The request URI (returned by getRequestURI) corresponds to parts 4, 5 and 6.
(incidentally, even though you're not asking for this, the method getRequestURL would give you parts 1, 2, 3, 4, 5 and 6).
Now:
part 4 (the context path) is used to select your particular application out of many other applications that may be running in the server
part 5 (the servlet path) is used to select a particular servlet out of many other servlets that may be bundled in your application's WAR
part 6 (the path info) is interpreted by your servlet's logic (e.g. it may point to some resource controlled by your servlet).
part 7 (the query) is also made available to your servlet using getQueryString
part 8 (the fragment) is not even sent to the server and is relevant and known only to the client
The following always holds (except for URL encoding differences):
requestURI = contextPath + servletPath + pathInfo
The following example from the Servlet 3.0 specification is very helpful:
Note: image follows, I don't have the time to recreate in HTML:
Consider the following servlet conf:
<servlet>
<servlet-name>NewServlet</servlet-name>
<servlet-class>NewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>NewServlet</servlet-name>
<url-pattern>/NewServlet/*</url-pattern>
</servlet-mapping>
Now, when I hit the URL http://localhost:8084/JSPTemp1/NewServlet/jhi, it will invoke NewServlet as it is mapped with the pattern described above.
Here:
getRequestURI() = /JSPTemp1/NewServlet/jhi
getPathInfo() = /jhi
We have those ones:
getPathInfo()
returns
a String, decoded by the web container, specifying extra path information that comes after the servlet path but before the query string in the request URL; or null if the URL does not have any extra path information
getRequestURI()
returns
a String containing the part of the URL from the protocol name up to the query string