How to make more specific urlPattern override broader pattern with annotations - java

I currently have a main controller servlet with the following annotation:
#WebServlet(name="ControllerServlet", urlPatterns={"/", "/home"})
I have .js and .css files under the /resources dir in my project that my .jsp files reference and the links are getting sent to my main controller which I don't want. I made a second servlet to handle the .js .css files with nn annotation of:
#WevServlet(name="ResourceServlet", urlPatterns={"/resources"})
hoping that it would pick up the requests coming from my .jsp files but ControllerServlet is still picking them up. How can I make /resources urls get directed to my ResourceServlet?

The url pattern / matches anything that isn't matched by the other mappings. If you have
#WebServlet(name="ResourceServlet", urlPatterns={"/resources"})
then a request to, eg. localhost:8080/context/resources will be handled by your ResourceServlet, but a request to localhost:8080/context/resources/somescript.js won't because it doesn't match ResourceServlet's url pattern. Therefore, ControllerServlet will handle it.
You need to change your ResourceServlet mapping to
#WebServlet(name="ResourceServlet", urlPatterns={"/resources/*"})

Related

Conflict with #MountPath at Apache Wicket

I'm using Apache Wicket annotations with #MountPath the following page path "/#{id}/#{action}" and in /webapp I have the following structure:
css/style.css
img/logo.png
When I try access page got an error because Wicket try to resolve style.css and logo.png as the page and not as static file.
I must do a bypass at resource folder /css and /img, how can I do that?
The problem you face is that you mount a page on the root/index, i.e. "/", with two optional parameters. Wicket will use that page to handle requests to "/", /"one", "/one/two". The static resources you have will be matched because they have two segments, i.e. they will match on both optional parameters.
You can solve/workaround this problem by listing "/css" and "/img" in ignorePaths parameter for WicketFilter in web.xml.

Servlet crashes jsp layout [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.

How to prepend front controller servlet mapping to urls in jsp

I have a simple java web application running in Tomcat.
In it, FrontController.java servlet has mapping #WebServlet("/controller/*"). So, in order to fire the servlet, I need my every url to start with /controller/. I need to be able to display images on pages images are stored outside container, so that I write them to OutputStream). But if I write my src urls like ${pageContext.request.contextPath}images/picture.jpg then the resulting url will be obviously localhost:8080/rootFolder/images/picture.jpg and not the localhost:8080/rootFolder/controller/images/picture.jpg.
To load these files I can either manually prepend controller/ after every ${pageContext.request.contextPath} which is bad or I can follow the advice found here append dispathcer servlet mapping to url and add line request.setAttribute("frontControllerMapping", "controller/"); to every method which processes request and then code urls like this ${pageContext.request.contextPath}${frontControllerMapping}images/picture.jpg which is better.
My questions are how to prepend the controller mapping to every url which must be processed by servlet and how to do it right? Is the second option the correct way to do so?
Instead of adding the complete URL for each resource you can use relative URLs. If that is not an option, than you could simply map all requests to your servlet like this:
#WebServlet("/*")
Then you don't need to worry about adding the controller path to all URLs.

Filter servlet causing image, css and JS not displaying on client while URL Pattern of Filter Servelet is /* and Servlet URL Pattern is / [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.

Make all requests to mysite.com/user/specified/path run the same JSP

I want to allow users to create groups in my application and access them via URL. For example, if you made a group called "sweethatclub," you could access it at http://mysite.com/sweethatclub. Of course, the same code will run for /sweethatclub and /drillteam and even /students/yearbook
I'm running in a Java servlet environment, and can't quite get the paths to align for this. I can write a filter that intercepts all requests and adds information to the request by parsing the URL, but then I want to run the code of an index.jsp. I don't want to map index.jsp to all URLs, because, for example, /images/smiley.jpg still needs to respond the with appropriate file instead of index.jsp.
Is there a way to send all requests to a servlet, unless the request is matched by a plain-old file? Or, is there some other way to accomplish what I want here?
Please let me know if I need to supply more information. I'm new to this environment.
The URL patterns in the web.xml are not supposed to be smart enough to figure out target URL's nature. If you can tolerate it, the easiest way would be to place all the user specified paths under a a well known root... someplace separate from the static files. So you end up with user specified paths like http://mysite.com/sites/sweethatclub.
Alternatively, you can move all your static content under http://mysite.com/static/, and set up the servlet mappings or filters to treat anything starting with 'static' different from the dynamic URL space.
If you are in a Unix invironment, you could just create all the "group sites" as virtual directories that just point to your default one.
Map the servlet on a specific URL pattern
<url-pattern>/groups/*</url-pattern>
Put all static content in a common folder, e.g. /static and fix all URLs in the pages to point to that URL instead.
Create a filter which is mapped on
<url-pattern>/*</url-pattern>
and does the following job in doFilter() method
String uri = ((HttpServletRequest) request).getRequestURI();
if (uri.startsWith("/static/")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/groups" + uri).forward(request, response);
}
No, this does not end up with /groups in browser address bar URL. It's fully transparent. You can if necessary make "/static" and/or "/groups" an <init-param> of the filter so that it's externally configureable.

Categories

Resources