Spring MVC DispatcherServlet mapping / vs /* - spring

<servlet>
<servlet-name>springmvcdemo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvcdemo</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
vs
<servlet>
<servlet-name>springmvcdemo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvcdemo</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I know there are duplicated questions but i'm still confused. My understanding is that when using /* , every request will go through this servlet (It means all .jsp, .html,etc will end up in this ). / will make this servlet the default servlet ( if there are exact URL installed..., return ) But it seem to me that when using / every request all still go through The DispatcherServlet no matter what. I can't open any .jsp file directly. Can someone explain to me more about this?

As per the Servlet specification, mapping for "/" means default servlet meaning if there is no explicit servlet matching the request, then this default servlet would be serving the request. For e.g., there is a servlet named "default" defined in Tomcat server common configuration web.xml which is inherited by all applications. This servlet serves the static contents like css,images etc which are typically not mapped in applications web.xml. Similarly there is a special Servlet which handles requests for jsp files ( all request ending with *.jsp as naturally these will be needed to be compiled to Servlets which would then process the request). So if you override the default servlet to be any other servlet in the application web.xml, then all requests not handled by any other servlet goes to this servlet and if this Servlet is not capable to serving request, it will not work.
If you declare Spring dispatcher servlet as the default Servlet, then you will not be able to serve static contents from container provided Servlet. Instead there is a special handler provided which can load static resources from configurable path pattern from directory / classpath. You need to use <mvc:resources/> tag for this feature. However if you still want to use container provided Servlet for serving resource you would need to use
<mvc:default-servlet-handler/> in the spring configuration. You can read more about this approach and its prons/cons here - section 15.12.4

Related

Dispatcher Servlet Mapping - Spring Framework

I am new to Spring Framework and I was wondering why every time we create a new Spring project and we set the dispatcher mapping as / instead of the default *.htm.
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Thanks!
1.<url-pattern>*.html</url-pattern>:
we are specifying the servlet class DispatcherServlet that acts as the front controller in Spring Web MVC. All the incoming request for the .html file will be forwarded to the DispatcherServlet.
2.<url-pattern>/</url-pattern> :
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.
Thanks..

Is the load-on-startup tag in web.xml mandatory?

Is the load-on-startup tag a mandatory tag in web.xml to load dispatcher servlet in spring? Will our dispatcher servlet get initialized if it doesn't mention this tag?
yes it's required, if you expect to dispatch or render anything using spring.
No, it is not mandatory. If you do not specify "load-on-startup" tag, your project will still work fine, except for the fact that the servlet will take slightly more time to load for the first request. This tag is helpful if you have multiple servlets and you want to control the loading flow. If you have multiple servlets, then the servlet which has the least "load-on-startup" value will be loaded first.
In the below example, servlet1 will be loaded first, then servlet2 will be loaded, and so on.
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>X</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>Y</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

java.lang.IllegalStateException: Cannot forward after response has been committed while including HTML files using jsp:include

When <jsp:include> is used for including HTML file DispatcherServlet is throwing
java.lang.IllegalStateException: Cannot forward after response has been committed
I have one servlet:
<servlet-mapping>
<servlet-name>web</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
In it, I have enabled Spring MVC annotations and have handler mapping and adapter for JSP files without controllers (converting old webapp to Spring). And I have enabled DefaultServletHttpRequestHandler in this Servlet.
Any idea how to avoid that IllegalStateException when including html files?
So if you let spring handle all html files, it will always fail on jsp:include because spring cannot handle html includes.
Best way around this for me was to leave html files on default servlet.
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
and leave rest on DispatcherServlet.
<servlet>
<servlet-name>web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>web</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
This is definitely not a best solution, but until I convert all jsps (around 1000 of them) to mvc and something like tiles this is the only way I can see it working.
It is illegal to call forward() after some response is written to the output stream. The response may have been already sent to the client.
This article Causes of Response already committed explains why response is already committed.
I tried the proposed solution which declares the default servlet mapping for *.html url patterns and it worked fine. The only problem was that it introduced some side effects in my case (an hybrid webapp, spring and non-spring managed): html files that should have been managed by Spring's front controller now were managed by Tomcat's default controller.Fortunately, I found a couple of solutions with zero impact on the rest of the webapp.
Use .jsp file extension instead of .html. Spring won't complain if
it finds <jsp:include page="file.jsp" /> instead of <jsp:include page="file.html" />
Include the .html file in a scriptlet <%=file.html %> and avoid using the jsp "include" tag

Spring: How to redirect non-dispatcher requests to dispatcher?

I have standard servlet-mapping for Dispatcher Servlet - /app/*. I have controller that handle /notify requests. I need to expose this controller as servlet on http://[SERVER]/notify. How to simple redirect all requests from http://[SERVER]/notify to http://[SERVER]/app/notify (but without other tools, like urlrewrite) ? I know i can write simple servlet instead of, and set servlet-mapping in web.xml, but want to have controller, not servlet ;)
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
Controller:
#Controller
public class PaymentNotificationController {
#RequestMapping("/notify")
void notify() { ... }
}
You can put another Dispatcher Servlet in
<servlet-mapping>
<servlet-name>Notification Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/notify/*</url-pattern>
</servlet-mapping>
and configure it with the same XML file as your main dispatcher servlet.
Don't discount urlrewrite - it only takes nanoseconds to execute, and years have gone into making it as fast as possible.
If you do throw up another Spring MVC servlet, you'll wind up with a second application context, which may not be desirable. DispatcherServlet is a front controller, of which there is supposed to be one - so yes - you can put as many as you want in, but they're almost like little mini-apps inside your WAR.

Loading spring context in web application after some servlet

We need to load the spring application context in our web application after one of our servlets is initialized, so I wonder what is the best way to do it?
I know that it's recommended to use the listener in web.xml, but it's obviously not good for us because in this case the context will be loaded before the first servlet. I saw that there was this class - ContextLoaderServet - in Spring 2.5, but it's absent in Spring 3.0. So I guess we should write some dummy servlet ourselves with the sole purpose of loading the context? Is there any better way?
Thanks.
OK, so if you have this legacy servlet that sets stuff up, then you will need to persuade the Spring servlet to load after it.
This is straightforward - use Spring's DispatcherServlet to load the Spring context, and use the standard <load-on-startup> in web.xml to dictate the startup order, e.g.
<servlet>
<servlet-name>LegacyServlet</servlet-name>
<servlet-class>com.xy.LegacyServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>SpringServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

Resources