The familiar code:
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
My understanding is that /* maps to http://host:port/context/*.
How about /? It sure doesn't map to http://host:port/context root only. In fact, it will accept http://host:port/context/hello, but reject http://host:port/context/hello.jsp.
Can anyone explain how is http://host:port/context/hello mapped?
<url-pattern>/*</url-pattern>
The /* on a servlet overrides all other servlets, including all servlets provided by the servletcontainer such as the default servlet and the JSP servlet. Whatever request you fire, it will end up in that servlet. This is thus a bad URL pattern for servlets. Usually, you'd like to use /* on a Filter only. It is able to let the request continue to any of the servlets listening on a more specific URL pattern by calling FilterChain#doFilter().
<url-pattern>/</url-pattern>
The / doesn't override any other servlet. It only replaces the servletcontainer's built in default servlet for all requests which doesn't match any other registered servlet. This is normally only invoked on static resources (CSS/JS/image/etc) and directory listings. The servletcontainer's built in default servlet is also capable of dealing with HTTP cache requests, media (audio/video) streaming and file download resumes. Usually, you don't want to override the default servlet as you would otherwise have to take care of all its tasks, which is not exactly trivial (JSF utility library OmniFaces has an open source example). This is thus also a bad URL pattern for servlets. As to why JSP pages doesn't hit this servlet, it's because the servletcontainer's built in JSP servlet will be invoked, which is already by default mapped on the more specific URL pattern *.jsp.
<url-pattern></url-pattern>
Then there's also the empty string URL pattern . This will be invoked when the context root is requested. This is different from the <welcome-file> approach that it isn't invoked when any subfolder is requested. This is most likely the URL pattern you're actually looking for in case you want a "home page servlet". I only have to admit that I'd intuitively expect the empty string URL pattern and the slash URL pattern / be defined exactly the other way round, so I can understand that a lot of starters got confused on this. But it is what it is.
Front Controller
In case you actually intend to have a front controller servlet, then you'd best map it on a more specific URL pattern like *.html, *.do, /pages/*, /app/*, etc. You can hide away the front controller URL pattern and cover static resources on a common URL pattern like /resources/*, /static/*, etc with help of a servlet filter. See also How to prevent static resources from being handled by front controller servlet which is mapped on /*. Noted should be that Spring MVC has a built in static resource servlet, so that's why you could map its front controller on / if you configure a common URL pattern for static resources in Spring. See also How to handle static content in Spring MVC?
I'd like to supplement BalusC's answer with the mapping rules and an example.
Mapping rules from Servlet 2.5 specification:
Map exact URL
Map wildcard paths
Map extensions
Map to the default servlet
In our example, there're three servlets. / is the default servlet installed by us. Tomcat installs two servlets to serve jsp and jspx. So to map http://host:port/context/hello
No exact URL servlets installed, next.
No wildcard paths servlets installed, next.
Doesn't match any extensions, next.
Map to the default servlet, return.
To map http://host:port/context/hello.jsp
No exact URL servlets installed, next.
No wildcard paths servlets installed, next.
Found extension servlet, return.
Perhaps you need to know how urls are mapped too, since I suffered 404 for hours. There are two kinds of handlers handling requests. BeanNameUrlHandlerMapping and SimpleUrlHandlerMapping. When we defined a servlet-mapping, we are using SimpleUrlHandlerMapping. One thing we need to know is these two handlers share a common property called alwaysUseFullPath which defaults to false.
false here means Spring will not use the full path to mapp a url to a controller. What does it mean? It means when you define a servlet-mapping:
<servlet-mapping>
<servlet-name>viewServlet</servlet-name>
<url-pattern>/perfix/*</url-pattern>
</servlet-mapping>
the handler will actually use the * part to find the controller. For example, the following controller will face a 404 error when you request it using /perfix/api/feature/doSomething
#Controller()
#RequestMapping("/perfix/api/feature")
public class MyController {
#RequestMapping(value = "/doSomething", method = RequestMethod.GET)
#ResponseBody
public String doSomething(HttpServletRequest request) {
....
}
}
It is a perfect match, right? But why 404. As mentioned before, default value of alwaysUseFullPath is false, which means in your request, only /api/feature/doSomething is used to find a corresponding Controller, but there is no Controller cares about that path. You need to either change your url to /perfix/perfix/api/feature/doSomething or remove perfix from MyController base #RequestingMapping.
I think Candy's answer is mostly correct. There is one small part I think otherwise.
To map host:port/context/hello.jsp
No exact URL servlets installed, next.
Found wildcard paths servlets, return.
I believe that why "/*" does not match host:port/context/hello because it treats "/hello" as a path instead of a file (since it does not have an extension).
The essential difference between /* and / is that a servlet with mapping /* will be selected before any servlet with an extension mapping (like *.html), while a servlet with mapping / will be selected only after extension mappings are considered (and will be used for any request which doesn't match anything else---it is the "default servlet").
In particular, a /* mapping will always be selected before a / mapping. Having either prevents any requests from reaching the container's own default servlet.
Either will be selected only after servlet mappings which are exact matches (like /foo/bar) and those which are path mappings longer than /* (like /foo/*). Note that the empty string mapping is an exact match for the context root (http://host:port/context/).
See Chapter 12 of the Java Servlet Specification, available in version 3.1 at http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html.
Related
I have manually configured web.xml for my application. Now, I'm facing issues while running my application. I'm trying to access my servlet from my jsp page. But, it is throwing error as page not found.
The servlets are placed under below folder location
<application folder>/WEB-INF/classes/<package>
So, what should be the entries for servlets in url-pattern and servlet-mapping. So that, servlet can be accessible through URL.
url-pattern is used in web.xml to map your servlet to specific URL. Please see below xml code, similar code you may find in your web.xml configuration file.
<servlet>
<servlet-name>AddPhotoServlet</servlet-name> //servlet name
<servlet-class>upload.AddPhotoServlet</servlet-class> //servlet class
</servlet>
<servlet-mapping>
<servlet-name>AddPhotoServlet</servlet-name> //servlet name
<url-pattern>/AddPhotoServlet</url-pattern> //how it should appear
</servlet-mapping>
If you change url-pattern of AddPhotoServlet from /AddPhotoServlet to /MyUrl. Then, AddPhotoServlet servlet can be accessible by using /MyUrl. Good for the security reason, where you want to hide your actual page URL.
Java Servlet url-pattern Specification:
A string beginning with a '/' character and ending with a '/*'
suffix is used for path mapping.
A string beginning with a '*.'
prefix is used as an extension mapping.
A string containing only the '/' character indicates the "default" servlet of the application. In this case the servlet path
is the request URI minus the context path and the path info is
null.
All other strings are used for exact matches only.
Reference : Java Servlet Specification
You may also read this Basics of Java Servlet
Servlet-mapping has two child tags, url-pattern and servlet-name. url-pattern specifies the type of urls for which, the servlet given in servlet-name should be called. Be aware that, the container will use case-sensitive for string comparisons for servlet matching.
First specification of url-pattern a web.xml file for the server context on the servlet container at server .com matches the pattern in <url-pattern>/status/*</url-pattern> as follows:
http://server.com/server/status/synopsis = Matches
http://server.com/server/status/complete?date=today = Matches
http://server.com/server/status = Matches
http://server.com/server/server1/status = Does not match
Second specification of url-pattern A context located at the path /examples on the Agent at example.com matches the pattern in <url-pattern>*.map</url-pattern> as follows:
http://server.com/server/US/Oregon/Portland.map = Matches
http://server.com/server/US/server/Seattle.map = Matches
http://server.com/server/Paris.France.map = Matches
http://server.com/server/US/Oregon/Portland.MAP = Does not match, the extension is uppercase
http://example.com/examples/interface/description/mail.mapi =Does not match, the extension is mapi rather than map`
Third specification of url-mapping,A mapping that contains the pattern <url-pattern>/</url-pattern> matches a request if no other pattern matches. This is the default mapping. The servlet mapped to this pattern is called the default servlet.
The default mapping is often directed to the first page of an application. Explicitly providing a default mapping also ensures that malformed URL requests into the application return are handled by the application rather than returning an error.
The servlet-mapping element below maps the server servlet instance to the default mapping.
<servlet-mapping>
<servlet-name>server</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
For the context that contains this element, any request that is not handled by another mapping is forwarded to the server servlet.
And Most importantly we should Know about Rule for URL path mapping
The container will try to find an exact match of the path of the request to the path of the servlet. A successful match selects the servlet.
The container will recursively try to match the longest path-prefix. This is done by stepping down the path tree a directory at a time, using the ’/’ character as a path separator. The longest match determines the servlet selected.
If the last segment in the URL path contains an extension (e.g. .jsp), the servlet container will try to match a servlet that handles requests for the extension. An extension is defined as the part of the last segment after the last ’.’ character.
If neither of the previous three rules result in a servlet match, the container will attempt to serve content appropriate for the resource requested. If a “default” servlet is defined for the application, it will be used.
Reference URL Pattern
I have seen some url-pattern in my xml e.g, in filter-mapping, intercept-url, mvc:resources, etc. Are these patterns always the same ? What's the difference among these URL patterns /, /*, /** ?
It depends in which context you ask this question:
Servlet/Filter mappings
Spring Security mappings
Servlet/Filter mappings
In the Web application deployment descriptor, the following syntax is used to define mappings:
A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for
path mapping.
A string beginning with a ‘*.’ prefix is used as an extension mapping.
The empty string ("") is a special URL pattern that exactly maps to the
application's context root, i.e., requests of the form http://host:port/<contextroot>/. In this case the path info is ’/’ and the servlet path and context path is
empty string (““).
A string containing only the ’/’ character indicates the "default" servlet of the
application. In this case the servlet path is the request URI minus the context path
and the path info is null.
All other strings are used for exact matches only
This comes from the Servlet Specification (JSR 315) (section 12.2).
In a Servlet/Filter mapping scenario / means the "default" servlet, normally this is where the DefaultServlet (in Tomcat that is) is mapped to. Basically it handles all incoming requests and doesn't pass them on further down the chain for processing (basically this is the last-catch-all mapping).
/* in the servlet mapping scenario means all incoming URLs (when it cannot be processed it will be handed of the the last-catch-all-mapping).
Spring Security mappings
Now when talking about Spring, /, /* and /** have a different meaning. They refer to so called Ant-style path expressions.
Where / means only / (the root of your application), where /* means the root including one level deep and where /** means everything.
So /foo/* will match a URL with /foo/bar but will not match /foo/bar/baz. Whereas /** or /foo/** would match all of them.
In struts2 why is a Filter is used as a controller instead of ActionServlet?
What is the advantage of using a Filter over ActionServlet?
As per Struts2 Budi Karnival struts2 book, There is one distinct advantage of using a filter over a servlet as a controller. With a filter you can conveniently choose to serve all the resources in your application, including static ones.
With a servlet, your controller only handles access to the dynamic part of the application. Note that the url-pattern element in the web.xml file in the previous application is
<servlet>
<servlet-name>Controller</servlet-name>
<servlet-class>...</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Controller</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
With such a setting, requests for static resources are not handled by the servlet controller, but by the container. You wouldn't want to handle static resources in your servlet controller because that would mean extra work.
A filter is different. A filter can opt to let through requests for static contents. To pass on a request, call the filterChain.doFilter method in the filter's doFilter method.
Consequently, employing a filter as the controller allows you to block all requests to the application, including request for static contents. You will then have the following setting in your deployment descriptor:
<filter>
<filter-name>filterDispatcher</filter-name>
<filter-class>...</filter-class>
</filter>
<filter-mapping>
<filter-name>filterDispatcher</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Advantage of this filter : One thing for sure, you can easily protect your static files from curious eyes.
The following code will send an error message if a user tries to view a JavaScript file:
public void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String uri = req.getRequestURI();
if (uri.indexOf("/css/") != -1 && req.getHeader("referer") == null) {
res.sendError(HttpServletResponse.SC_FORBIDDEN);
} else {
// handle this request
}
}
It will not protect your code from the most determined people, but users can no longer type in the URL of your static file to view it. By the same token, you can protect your images so that no one can link to them at your expense.
Another advantage :
The introduction of Interceptors in Struts2 framework.It not just reduce our coding effort,but helps us write any code which we would have used filters for coding and necessary change in the web.xml as opposed to Struts1.So now any code that fits better in Filter can now moved to interceptors( which is more controllable than filters), all configuration can be controlled in struts.xml file, no need to touch the web.xml file
We generally Use a Filter when we want to filter and/or modify requests based on specific conditions.
For S2 to work it needs to perform certain reprocessing and modification work in order for a successful execution of your request while on other hands we use Servlet when we want to control, preprocess and/or post-process requests.
For controlling request S2 use Servlet under the hood but being hidden away to make the overall application structure more clean and easy to use.
This is what we have for Filters in The Java EE 6 Tutorial.
A filter is an object that can transform the header and content (or both) of a request or response. Filters differ from web components in that filters usually do not themselves create a response. Instead, a filter provides functionality that can be “attached” to any kind of web resource. Consequently, a filter should not have any dependencies on a web resource for which it is acting as a filter; this way, it can be composed with more than one type of web resource.
Inside a servlet Filter, is there a way to figure out which Servlet a particular request would eventually hit? I need to do Role based security checks based upon Servlets (not URL patterns) , in a filter (due to legacy reasons).
thanks
This information is not available by HttpServletRequest.
If you're already on Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, etc), then you can get information of all servlet registrations and mappings by ServletContext#getServletRegistrations():
for (Entry<String, ? extends ServletRegistration> entry = servletContext.getServletRegistrations().entrySet()) {
String servletClassName = entry.getKey();
Collection<String> urlPatterns = entry.getValue().getMappings();
// ...
}
You could do the URL matching yourself based on the servlet mappings and the information as obtained by among others HttpServletRequest#getServletPath()
If you're not already on Servlet 3.0, then you need to parse the web.xml and collect all servlets and their URL patterns yourself, or to have a copy of it elsewhere. For manually parsing web.xml, the JAXB may come handy.
The HttpServletRequest.getServletPath() returns the part of the request URI that resulted in the servlet being invoked.
I have two web applications.But only one among them includes Java servlet class.I want to access that servlet class from within the web.xml file of other application.Is it possible?.If yes,How will be it possible?.
You can't do that in the web.xml. You can however create a new servlet which in turn redirects/forwards the request to the servlet of the other webapplication. Redirecting is easy, just let the URL point to the particular servlet.
response.sendRedirect("/otherwebapp/theservlet");
Forwarding requires a bit more work. This is by default not possible due to security restrictions. First you need to configure the servletcontainer to enable cross context access between the webapplications in question. It's unclear which one you're using, so here's just a Tomcat targeted example so that you understand in what direction you should look for your own servletcontainer: for the both webapps, you need to set the crossContext attribute of the <Context> element to true:
<Context crossContext="true">
This way you can obtain the other context by ServletContext#getContext() inside a servlet:
ServletContext othercontext = getServletContext().getContext("/otherwebapp");
Finally you can forward the request through it as follows:
othercontext.getRequestDispatcher("/theservlet").forward(request, response);