Mapping cases in web.xml - java

In web.xml, is it possible to have a main mapping and a second mapping used with mappings that are different from the first one as shown below?
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/?</url-pattern>
</servlet-mapping>

You can have multiple servlet-mappings in a deployment descriptor. The rules for selecting a mapping are described in the Java Servlet Specification Chapter 12. Mapping Requests to Servlets:
12.1 Use of URL Paths
...
The path used for mapping to a servlet is the request URL from the request object minus the context path and the path parameters. The URL path mapping rules below are used in order. The first successful match is used with no further matches attempted:
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. Many containers provide an implicit default servlet for serving content.
So this means, if you have an exact match like <url-pattern>/tar</url-pattern>, this mapping will be selected. Otherwise the second, less specific mapping, (e.g. <url-pattern>/*</url-pattern>) will be used.
But you cannot create a mapping with <url-pattern>/tar*</url-pattern>, because an asterisk is only allowed at the end /* or at the beginning *. of a pattern (note the slash / before and the period . after the asterisk). See section 12.2 Specification of Mappings for the full details.

Related

How to make a servlet handle all URLs except JSPs [duplicate]

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.

Tomcat - How exactly context path matching works?

Suppose I have two Spring webapps deployed to the same Tomcat server instance:
A:
ROOT.war, context = /
#Controller
class TestController {
#RequestMapping("/api/someMethod")
public String someMethod() {
//..
}
#RequestMapping("/api/v1/someMethod")
public String someMethod() {
//..
}
}
B:
api#v1.war, context = /api/v1/
#Controller
class TestController {
#RequestMapping("/someMethod")
public String someMethod() {
//..
}
}
Which web application will be used to process the following HTTP requests?
GET http://<hostname>/api/someMethod
GET http://<hostname>/api/v1/someMethod
GET http://<hostname>/api/v1/nonexistentMethod
As you can see the second HTTP request matches both apps. I have tried to find answer in Tomcat docs, but found none. Where is specified how context path matching works?
According to Servlet 3.0 Specification
10.1 Web Applications Within Web Servers
A Web application is rooted at a specific path within a Web server.
For example, a catalog application could be located at
http://www.mycorp.com/catalog. All requests that start with this
prefix will be routed to the ServletContext which represents the
catalog application.
A servlet container can establish rules for
automatic generation of Web applications. For example a ~user/
mapping could be used to map to a Web application based at
/home/user/public_html/
12.1 Use of URL Paths
Upon receipt of a client request, the Web container determines the
Web application to which to forward it. The Web application selected
must have the longest context path that matches the start of the
request URL. The matched part of the URL is the context path when
mapping to servlets. The Web container next must locate the servlet
to process the request using the path mapping procedure described
below. The path used for mapping to a servlet is the request URL from
the request object minus the context path and the path parameters.
The URL path mapping rules below are used in order. The first
successful match is used with no further matches attempted:
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 ma tch the longest path-pre fix. 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.
Versions of this specification prior to 2.5 made use of these mapping techniques as a suggestion rather than a requirement,
allowing servlet containers to each have their different schemes for
mapping client requests to servlets.
If neither of the previous three rules re sult 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. Many containers provide an implicit
default servlet for serving content.
Also Tomcat Request Process Flow might be useful

Spring MVC web.xml mappings

I was looking at a tutorial on Spring MVC, and noticed that the dispatcher servlet is mapped to the urlpattern /and it was explained that this means that all requests will be handled by the servlet defined to handle that urlpattern.
That makes sense, but I thought that /* was the notation used to specify all requests, not just /. What is the difference between a url pattern of / and one of /*? I would think that / would map to the context path of the application. so for example, if 'myapp' was the context root of the app:
myipaddress/myapp would be handled by a urlpattern of /
myipaddress/myapp/foo would be handled by a urlpattern of /*
Can someone help me understand where I'm going wrong
The 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.
http://download.oracle.com/otndocs/jcp/servlet-3.0-fr-eval-oth-JSpec/

Why should url-pattern in servlet mapping start with forward slash(/)

I was reading Head First JSP and Servlets book. I was going through the mapping of servlet. And my doubt here is
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>com.avinash.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/ServletBeer.do</url-pattern>
</servlet-mapping>
Why should the url-pattern start with forward slash(/)?
What does the forward slash(/) represent? Does it represent our webapp name?
What happens if the url-pattern do not start with forward slash(/)?
Is it a specification to start with forward slash(/)?
And in the book it is clearly mentioned:
Don't forget the forward slash(/) in the url-pattern.
Can you explain?
The / in the url-pattern means the root of the web application that uses this web.xml. So when you give /ServletBeer.do. That means http://<yourhost>:<port>/<your context Root>/ServletBeer.do. When ever you hit this url, the servlet you which have mapped with this i.e com.avinash.TestServlet will be invoked.
Its not mandatory that you have to use / in all your url mapping - that purely depends on how you want to configure it. / is just a regular expression. You can also use *.jsp in your url-pattern - which will actually invoke this servlet everytime you request any jsp in your web- application.
Consider the section 12.2 Specification of Mappings ** from **JSR-000315 Java Servlet 3.0 Final Release
12.2 Specification of 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
On the above questions i could find answer for one of the questions.
What happens if the url-pattern do not start with forward slash(/). I have checked it but i don't remember
When i started tomcat by removing the / in the url-pattern i got the following error
Caused by: java.lang.IllegalArgumentException: Invalid <url-pattern> ServletBeer.do in servlet mapping
at org.apache.catalina.core.StandardContext.addServletMapping(StandardContext.java:3267)
at org.apache.catalina.core.StandardContext.addServletMapping(StandardContext.java:3242)
at org.apache.catalina.deploy.WebXml.configureContext(WebXml.java:1324)
at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1348)
at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:880)
at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:378)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5343)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
This indicates that if we are not using extension mapping compulsory the url-pattern should start with /

Trouble with web.xml url pattern

In my web.xml I have URL pattern for servlet like this:
<url-pattern>/*/myservice</url-pattern>
So I want to call it using blablabla/myservice also as anyWord/myservice.
But it doesn't work. It work only if I call it using this URL: /*/myservice (with asterisk in URL).
You can't do that.
According to the Servlet 2.5 Specification (and things aren't that different in other levels of the specification), chapter SRV.11.2:
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.
Your case falls under the 4th bullet, so exact mapping is used.
To circumvent that, use a mapping of / (third case). Map all requests to go to a particular servlet, and have that servlet re-route requests to handlers of some sort (either other servlets, or some custom classes).
For example:
<url-pattern>/</url-pattern>
<servlet-name>MyServlet</servlet-name>
And then, within MyServlet's code, inspect the URL that you received in the request (using request.getPathInfo()) and use the value to forward the request to other handlers.
You could use a filter while your url pattern is /* and inside the filter decide which redirection you required.
<filter>
<display-name>MyFilter</display-name>
<filter-name>MyFilter</filter-name>
<filter-class>com.MyfilterClass</filter-class>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</filter>
What about two ULR-mapping sections?
<servlet-mapping>
<servlet-name>ModifyMemberSVL</servlet-name>
<url-pattern>/ModifyMember</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ModifyMemberSVL</servlet-name>
<url-pattern>/Administration/Add_Member/ModifyMember</url-pattern>
</servlet-mapping>

Categories