Tomcat serving static resources on Spring MVC app - spring

I'm building a Spring MVC application, and the frontController servlet is mapped in "/" intercepting all requests, I'd to be able to serve the static contents (.js,.css,.png...) from tomcat and not by Spring.
My app structure is
-webapp/
styles/
images/
WEB-INF/
views/
By default, because the frontController is mapped on the context root of my app its handles all requests but don't serve any static resource.
The mvc configurarion for static resources is follow.
<mvc:resources mapping="/resources/**" location="/"/>
And the page's code is:
<img src="resources/images/logo.png" />
I need to configure Tomcat to serve the static resources with no spring interaction.
Any suggestion?

You can remap tomcats default servlet (which handles static content), e.g.
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/images/*</url-pattern>
</servlet-mapping>

Have a look at this mailing list thread and see if that does what you're looking for.

Another potential solution - Just add the following to your Spring DispatcherServlet.xml (Spring Docs)
<mvc:default-servlet-handler/>
This tag allows for mapping the DispatcherServlet to "/" (thus overriding the mapping of the container's default Servlet), while still allowing static resource requests to be handled by the container's default Servlet. It configures a DefaultServletHttpRequestHandler with a URL mapping (given a lowest precedence order) of "/**". This handler will forward all requests to the default Servlet.
Pros (as compared to #nos's solution)
The URL remapping solution behaves differently depending upon your container. Jetty/Tomcat 6 take that to mean 'map URL/images/* to WEBAPP/images/'. Tomcat < 6 (and maybe others) take that to mean 'map URL/images/ to WEBAPP/*', which is a BIG security breach.
If you want to serve a favicon.ico, robots.txt etc. from your site, then you'll have
to create additional url-mappings for them.
Cons
Spring is in the loop, which is definitely something that is unnecessary.
Additionally, irrespective of the solution that one prefers, I'd suggest adding the following to your web.xml to prevent directory listings (on, say URL/images)
<servlet>
<servlet-name>default</servlet-name>
<init-param>
<param-name>dirAllowed</param-name>
<param-value>false</param-value>
</init-param>
</servlet>

Related

Spring MVC DispatcherServlet 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>
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

Servlet mapping issue with SpringMVC

i'm developing a J2EE App using Spring (mvc, security, etc...) and i have a problem with the mappings. I would like to redirect people who type "..../myapp" to a welcome jsp, specifically to "/myapp/welcome.html"
Previously my servlet-mapping had this config:
<servlet-mapping>
<servlet-name>MyApp</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
But i changed it, in order to catch the "/myapp" request. The newone that i wrote is the following:
<servlet-mapping>
<servlet-name>ThreddsAdminPanel</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
It works as expected but when i try to access to a page which needs an css, this error appears:
"No mapping found for HTTP request with URI"
I think that if My url-pattern is /*, the servlet is catching something that doesn't belong to it although i don't know how to do it. Does anybody know a good way to do this?
Thank you
See this: Pretty URL Mapping with Spring 3.0
Basically, change your servlet-mapping from /* to / and then you can worry about performing the redirect.
For the redirect, you should be able to do something like this (assuming use of the mvc namespace in XML config):
<mvc:view-controller path="/myapp" view-name="redirect:/myapp/welcome.html"/>

spring servlet-context in sts

Using STS in eclipse to create an mvc project I notice that the servlet-context.xml seems to be written to be used in both the root context and the dispatcherservlet Context. I say this because I notice that the context:component-scan is in it, which is often loaded into the root context, but it is loaded into the dispatcherservlet context. I also noticed a sample spring mvc/jpa project - http://duckranger.com/2012/04/spring-mvc-3-x-with-sts-tutorial-part-iii-add-some-jpa/ - that specifically loads the servlet-context.xml into both contexts. I thought the idea was to keep a clean separation between the contexts. Can someone explain this to me?
The following configuration is plain wrong
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:META-INF\root-context.xml
classpath:META-INF\servlet-context.xml
classpath:META-INF\datasource.xml
</param-value>
</context-param>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF\servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Your root and servlet context should NEVER import the same files, as the beans from the root context will already be available in the servlet context because of the context hierarchy in Spring. There is no point to create copies of them in the different contexts(especially because the beans in the root context will be shadowed by the ones in the servlet context, for example if you declare <tx:annotation-driven> only in the root context it will not affect the behavior of the servlet context beans, which will force you to tangle configuration even more) .
It's very illogical to put <jpa:repositories> into the servlet context, because it's VERY likely that you will use the repositories from the service layer.
Typically you should not put anything but the MVC configuration to the servlet context. It's the root web app context where the services should live. Servlet context provides separation of the controllers from the services, so when you test your services with Spring Test Context framework you don't have to create the controllers(if you want to test the mappings you should use Spring MVC Test framework) and test the application services directly.
To be clear, if we examine the figure from the Hexagonal Architecture article
the the servlet context should contain only user-side API related things but not the application. It is arguable whether you should divide the configuration of the root web app context and put data-side-api into separate configuration file but the question was about servlet/root contexts.
Just to be less abstract here's some informal diagram of what I typically keep in mind(in terms of Spring contexts and bean configuration files) when configure a Spring application(of course it's all subjective, it's not a super solution and actually is a bit over complicated - it's unlikely that I will need so many servlets and configuration files)

Static resources in Spring MVC app

In my Spring mvc application I want to serve static resources using mvc:resources.
My web.xml mapping looks that:
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Where main is dispatcher servlet to serve all the content
In my servlet.xml file I added:
<mvc:resources mapping="/static/**" location="/static/"/>
and it works properly when my application context is empty (like localhost:8080/), but when I deploy application in another context it doesn't work, I got 404.
I tried many combinations:
"static/**"
"*/static/**"
Nothing works.
I'm sure it's server context problem, but I have not idea (I couldn't find the solution in Google too) how to solve this. Please, help.
I was able to succesfully map my static resources using the following convention:
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
The easiest way for we that worked, was adding in the servlet-config.xml (the file that is configured in web.xml as the contextConfigLocation) the following:
<mvc:default-servlet-handler/>

Can someone explain the Spring web.xml file?

I'm new to Java Enterprise and to Spring but I have a strong grasp of standard Java. I am looking through an existing web application project. The project uses Tomcat/Spring/Hibernate which I understand is fairly common. It also uses DWR for remote method invocations. I'm finding it somewhat difficult to separate responsibilities: what Tomcat is responsible for, what Spring is responsible for, how a request gets from one to the other, and how the major pieces of Spring fit together. I've read a great deal of documentation on Spring, particularly about beans and bean factory and am still in process of reading more. Any advice you guys have would be welcome, but I'll provide some specific questions.
Question 1: Where does the web.xml fit into things (when is it used/called, and where is it called from)?
Code sample 1:
<servlet>
<servlet-name>qrst</servlet-name>
<display-name>qrst Servlet</display-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
What does the above snippet do (or, what does it cause to happen)? At some point in my web app qrst.jsp gets used; is it the DispatcherServlet that calls qrst.jsp using the servlet name? Else what is the significance of the servlet name? What is load on startup?
Code sample 2:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/someLocation/some-servlet.xml
</param-value>
</context-param>
Links or explanation of what the above does? I can see from looking at the XML file that it contains bean definitions and I do understand what beans are and how they are used, but I don't know any other details about this and would like to.
Code sample 3:
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR</display-name>
<servlet-class>
org.directwebremoting.servlet.DwrServlet
</servlet-class>
<init-param>
<param-name>classes</param-name>
<param-value>
somepackage.someclass
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
From what I read about beans, I believe those init-param elements are just parameters that get set in the servlet's java class. What's the significance of the servlet name, and what about the load on startup? The web app somehow "knows" when an AJAX (dwr) call is happening versus when the web app is being loaded for the first time (when its loading for the first time it should use qrst.jsp). How does it know this? How does it decide to route the request to DWR instead of to qrst.jsp? Where does it do this?
Thanks.
Servlets are JavaEE's idiom for answering HTTP requests. You program the behavior of your application in a Servlet which will respond to a request.
Tomcat is a Servlet container, which means you deploy your application in Tomcat and it will manage all the communication infrastructure for you: it accepts connections, manages database connections(*) and will call upon your servlets to handle incoming requests.
web.xml is part of any JavaEE application, not Spring. Your code sample 1 declares that your app will use an instance of class org.springframework.web.servlet.DispatcherServlet to handle incoming requests.
Although servlets are the basic foundations for JavaEE development, it is not advised to create your own; instead, with Spring, you create MVC controllers. Then the DispatcherServlet will call upon these controllers to handle the requests. It's just another indirection (but a very powerful one!)
is it the DispatcherServlet that calls qrst.jsp using the servlet name?
Not directly. It's just a coincidence that your servlet and the JSP file have the same name.
What is loaded on startup?
Your code sample 2 instructs the DispatcherServlet to load the beans from file /someLocation/some-servlet.xml. If there are controller beans in this file and according to how you configured the url mapping, beans from this file will answer the incoming requests. See the reference.
I believe those init-param elements are just parameters that get set in the servlet's java class
The init-param elements in web.xml are for the servlet class.
The web app somehow "knows" when an AJAX (dwr) call is happening versus when the web app is being loaded for the first time (when its loading for the first time it should use qrst.jsp). How does it know this?
Missing from the question are either the <servlet-mapping> element (found in web.xml), or the url mappings (found in the spring files). These are responsible for deciding whether an URL should be handled by the dispatcher servlet or the dwr servlet.
For instance, with an servlet mapping like below:
<servlet-mapping>
<servlet-name>qsrt</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dwr</servlet-name>
<url-pattern>*.dwr</url-pattern>
</servlet-mapping>
Then all URLs ending in .do will be answered by the dispatcher servlet, and those ending with .dwr will be handled by the dwr servlet. Here's where the names of the servlets are important.
JSP files are a different story. The container will simply use them to handle a URL ending in *.jsp. Do not create your onw servlet mapping for URLs ending in *.jsp. This will only cause headaches. This is probably unspecified behavior.
Edit:
However, the URL in the browser's address bar always looks the same: it would always invoke the qrst servlet
Then it is possible that your servlet-mapping is so broad (something like: <url-pattern>/*</url-pattern>) that it will handle anything you throw at the server and never give a chance for the other servlets to handle it.
Last but not least, when working with DWR or any Ajax technology, install the HttpFox extension for Firefox so you can monitor the Ajax calls of your application.

Resources