I have a servlet called User.java. It is mapped to the url pattern
<servlet-mapping>
<servlet-name>User</servlet-name>
<url-pattern>/user/*</url-pattern>
</servlet-mapping>
Inside the Servlet, the path following the slash in user/ is analyzed, data about that user is retrieved from the database, set in attributes, and then the page user_home.jsp is to be displayed.
The code to make this happen is:
User user = UserManager.getUserInfoById(userPath);
request.getSession().setAttribute("user", user);
request.getRequestDispatcher("resources/jsp/user_home.jsp").forward(request, response);
The problem is, that rather than opening this user_home.jsp, the request is mapped once again to the same servlet User.java. It does nothing.
I've put output statements at the beginning of the doGet method, so I can see that the URL is
http://localhost:8080/myproj/user/resources/jsp/user_home.jsp
so it seems the obvious problem is that it's mapping right back to the user/* pattern.
How do I get the Servlet to display this page without going through URL mapping, and properly display the jsp I need it to?
If the path passed to request.getRequestDispatcher() does not begin with a "/", it is interpreted as relative to the current path. Since your servlet's path is /user/<something>, it tries to forward the request to /user/resources/jsp/user_home.jsp, which matches your servlet mapping and therefore forwards to the same servlet recursively.
On the other hand, if the path passed to request.getRequestDispatcher() begins with a "/", it is interpreted as relative to the current context root. So assuming that the resources directory is located at the root of your webapp, try adding a "/" at the beginning of the path, e.g.:
request.getRequestDispatcher("/resources/jsp/user_home.jsp").forward(request, response);
you don't want to use the * in your servlet mapping. simply because everytime that you have /user/ in your URL it will redirect back to the servlet.
the asterisk accepts every URL that has /user/ and redirect it based on servlet mappiing, so you might want to make it
<servlet-mapping>
<servlet-name>User</servlet-name>
<url-pattern>/user/User</url-pattern>
</servlet-mapping>
and use it in your action as action = user/User
Related
I'm working on a requirement where I need to write the servlet to the context path of the application, according to servlet specification document empty string i.e. "" mapping should work for application root context. I have tried different combinations like
<servlet>
<servlet-name>Redirect</servlet-name>
<servlet-class>RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Redirect</servlet-name>
<url-pattern></url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Redirect</servlet-name>
<servlet-class>RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Redirect</servlet-name>
<url-pattern>""</url-pattern>
</servlet-mapping>
these are not working. Is there any other way to write the servlet for the context path
for path "/" there is a servlet already. Requirement is to write the servlet for context path
Empty string is for application root context.
It's a legacy / backwards compat feature.
The recommended declaration for root context is still /, and the returned string for application root context will always be "" (empty string).
That being said, this little bit of trivia about application root context isn't relevant to your issue at hand.
You are dealing with url-pattern, a different concept.
The url-pattern rules are applied after the request has matched an application root context.
A url-pattern that has quotes is invalid.
A url-pattern that is empty is pointless, as it will never match an incoming request and you'll never have a dispatched request sent to it.
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/test/*</url-pattern>
</servlet-mapping>
If I hit /test/page the above will work. However, hitting /test or /test/ will not work. I'm using Spring MVC, and my request mapping is as follows:
#RequestMapping(value = {"","/"})
EDIT:
I'm in the process of verifying with an independent project, but this appears to be a bug with Spring's UrlPathHelper. The following method returns an incorrect path when there is both a context and a servlet path, and you hit the servlet without a trailing slash.
public String getPathWithinApplication(HttpServletRequest request) {
String contextPath = getContextPath(request);
String requestUri = getRequestUri(request);
if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
// Normal case: URI contains context path.
String path = requestUri.substring(contextPath.length());
return (StringUtils.hasText(path) ? path : "/");
}
else {
// Special case: rather unusual.
return requestUri;
}
}
Just as an example let's say I have a context of "admin" and the following servlet-mapping:
<servlet-mapping>
<servlet-name>usersServlet</servlet-name>
<url-pattern>/users/*</url-pattern>
</servlet-mapping>
Now I have a request mapping in one of my controllers like this:
#RequestMapping(value = {"","/"})
If I hit /admin/users it will not work. However, if I hit /admin/users/ it will work. Now if I change my request mapping to the following then they will both work:
#RequestMapping(value = {"/users","/"})
However, now the URL /admin/users/users will also work (which is not what I would want).
Yevgeniy is correct, but if your DispatcherServlet is taking over for the default servlet, you have to add this to your web.xml:
<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>
my setup usually looks like this:
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
controller, where i assume you want to handle /test and /test/ equally:
#Controller
public class MyController {
#RequestMapping("/test")
public String test() {
return "redirect:/welcome";
}
#RequestMapping("/test/")
public String test() {
return "redirect:/welcome";
}
#RequestMapping("/welcome")
public void test(ModelMap model) {
// do your stuff
}
}
setup like this would cause DispatcherServlet to handle requests for *.css and *.js files, which is not desired in most cases. i think this is the problem Bhavik describes. For those resources you can you the ResourceController like this:
<mvc:resources mapping="/css/**" location="/resources/css/" />
<mvc:resources mapping="/js/**" location="/resources/js/" />
files from /resources/css and /resources/js will be served without forcing you to write a extra controller.
First of all, the difference between mapping dispatcher servlet to "/" and to "/*".
There is a difference!
When mapping to "/*", all URL requests (including something like this "/WEB-INF/jsp/.../index.jsp") are mapped to dispatcher servlet.
Secondly, when using Spring + Tiles, and returning some JSP in your tiles definition, it is treated as an internal forward request, and handled by the same servlet as the original request.
In my example, I invoke root URL "/", which is properly caught by home() method, and then forwarded to "index.jsp" by Tiles, which is again being handled by Dispatcher Servlet.
Obviously, dispatcher servlet cannot handle "index.jsp", because there is no controller for it.
Yeah, it is ugly, but looks like this is the way it works.
So, the only solution I've found so far: to change "/*" back to "/" in web.xml. This way JSPs are rendered properly by Tomcat's jsp servlet, I guess, and not dispatcher servlet.
Unfortunately, this fix will break the ROOT URL dispatching by Spring, so you need to leave the idea of using ROOT URL + Tiles for now.
Please note that adding explicit servlet mapping ".jsp -> Tomcat jsp in web.xml doesn't help, when using "/*", and it sucks.
Still the problem is not resolved.
Also this is the problem in Spring MVC 3.0
A way without touch the web.xml file is by set the map to the default welcome file path.
#RequestMapping("/index.html")
In my case, every url was working except of the root "/" url.
The problem was that i didn't deleted the index.htm file inside of my projects' webapp root folder.
I would like to run a search whenever a 404 is encountered. For example, a user would like to view restaurants with Italian cuisine, they would go to www.mywebsite.com/italian so instead of showing a custom 404 error page, I would like add a filter which first checks if a 404 would have been thrown, if so, attempt to search against a list of search items, if a match exists, forward request to that page rather than throw 404 error.
Example:
www.mywebsite.com/italian --> www.mywebsite.com/search.do?cuisine=italian
www.mywebsite.com/london --> www.mywebsite.com/search.do?city=london
www.mywebsite.com/rest --> www.mywebsite.com/show.do?rest_id=XXX
The question I guess is how would I determine if there doesn't exists a servlet with url-mapping "/italian" or "/italian/*" within my server config?
Using (in Filter.doFilter) request.getRequestDispatcher(request.getRequestURI()) always returns a non-null value which I cannot use to determine whether the request is valid or not. I can use a 404 error statement but the result would have a response status of 404 rather than 200.
You can just map the 404 error page on a servlet URL pattern.
<servlet>
<servlet-name>errorServlet</servlet-name>
<servlet-class>com.example.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>errorServlet</servlet-name>
<url-pattern>/error</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/error</location>
</error-page>
This allows for doing fine grained business and HTTP request/response controlling job in the servlet before displaying the desired JSP.
I can think of at least two ways to implement this:
<error-page>
In your web.xml add:
<error-page>
<error-code>404</error-code>
<location>/notfound</location>
</error-page>
/notfound should be an existing servlet/controller that can access the original URL (the one that was not found, e.g. /italian) with:
request.getAttribute("javax.servlet.error.request_uri")
In this controller you can send redirect to /search.do.
HTTP proxy
If you put HTTP proxy in front of servlet container (like Apache HTTP server) you can catch 404's sent from the server and return redirects (30x codes).
Servlet post-filter
If you insist on servlet filter, this is doable as well. Create a filter that wraps the original response and forwards the request further. After receiving the response back from the chain check the HTTP status. If it is 404, redirect to search servlet.
Untested: ServletContext.getResourcePaths() seems to list resources mapped on a given path.
I'm a Ruby on Rails developer programming a web application in Java. I am trying to achieve something similar to what is achieved in Rails. In Rails it is possible to call a link using localhost:8000\Users\1 when Users is a Model and 1 is the id of a specific user. I would like to get the same kind of thing in Java.
I am working in an MVC type design where my JSP pages are the view and my Servlets are the controllers. I created a servlet called Users which renders the users.jsp page now i can get to that page using the URL localhost:8000\projectName\Users, i would like to route localhost:8000\projectName\Users\1 to the page user.jsp while the appropriate Servlet will handle sending into the page the correct user (with id=1).
Any idea how I can achieve this?
I'm doing this in a University project and am not allowed to use any frameworks. I also would rather something i could code rather than install.
now i can get to that page using the URL localhost:8000\projectName\Users, i would like to route localhost:8000\projectName\Users\1 to the page user.jsp while the appropriate Servlet will handle sending into the page the correct user (with id=1).
Simple. Map the servlet on an URL pattern of /Users/* instead of /Users. You can then grab the path info (the part after /Users in the URL, which is thus /1 in your example) as follows:
String pathInfo = request.getPathInfo();
// ...
You can just forward to users.jsp the usual way.
Long id = Long.valueOf(pathInfo.substring(1));
User user = userService.find(id);
request.setAttribute("user", user);
request.getRequestDispatcher("/WEB-INF/users.jsp").forward(request, response);
I would try this via a servlet and servlet mappings like that in web.xml
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.example.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/Users</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/Users/*</url-pattern>
</servlet-mapping>
Than in your UserServlet try to get the full URL and parse it to your needs. Example:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String url = reg.getRequestURL();
//... get last part after slash and parse it to your id
}
See http://download.oracle.com/javaee/1.3/api/javax/servlet/http/HttpServletRequest.html for further documentation on the request and how its parameters can be retrieved
UrlRewriteFilter is like mod_rewrite but for Tomcat. You can use it to make your URLs SEO-friendly. You can also use Apache+mod_rewrite+Tomcat.
I want that when user hits following URL:
http://host:8080/AppName/ServletName/Param1/Param2
It should go to a servlet named ServletName and Param1 and Param2 become request parameters. I have seen these kind of urls in ruby projects. Is it possible in Java?
If you are using Spring MVC you can map a #Controller and access the params as #PathVariable in a #RequestMapping.
#Controller
public class MyController {
#RequestMapping("/{param1}/{param2})
public Response get(#PathVariable("param1") String param1, #PathVariable("param2") String param2) {
//method body
}
}
Yes, you can do something like that with a servlet. You need to set the servlet mapping in web.xml like this:
<servlet-mapping>
<servlet-name>ServletName</servlet-name>
<url-pattern>/ServletName/*</url-pattern>
</servlet-mapping>
to get all requests and in the servlet you need to parse the result of HttpServletRequest.getPathInfo().
HttpServletRequest.getContextpath() seems interesting, even though i have never used it myself.
Sure you can, it's called REST, and you can get an intro here: http://download.oracle.com/javaee/6/tutorial/doc/giepu.html
You can also map servlets to wildcarded paths, so you could just map your servlet to /ServletName/* and get the /Param1/Param2 part from request.getPathInfo().
You can also achieve this with URL rewriting. There is also a servlet container equivalent available that works with a ServletFilter called UrlRewriteFilter.
I personally use Tapestry5 which natively encodes parameters this way.
I haven't done this,even haven't seen but try this
first map the url in the web.xml like this
<servlet>
<servlet-name>ServletName</servlet-name>
<servlet-class>ServletName</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletName</servlet-name>
<url-pattern>/ServletName/Param1/Param2</url-pattern>
</servlet-mapping>
and then get the url to a string using
String url=request.getRequestURI();
then you can split and get param1 and param2.