Spring <mvc:resources ... /> request routing - spring-mvc

TL;DR: I'm writing a simple Tomcat/Spring/Freemarker webapp and seem to be having a lot of trouble getting Spring's DispatcherServlet to honor <mvc:resources...> configuration.
PLEASE NOTE: AFAICT this is not a duplicate of other questions since I've tried the solutions given in other answers. If someone finds an existing question and that question provides a solution I missed, I'll gladly VTC as a dup (or delete this question if desired).
I have a very simple webapp based on Freemarker. That part is working fine. I have a single request-handler method to handle all requests (#RequestMapping("/**")) but wish to serve static resources /${contextPath}/static/... using the <mvc:resources.../> facility. The resources are located in subdirectories of the top-level webapp directory.
Based on reading other questions on SO I added
<mvc:resources mapping="/static/**" location="/" />
to my Spring configuration.
No matter what I do, requests that I expect to be resolved as a static resource file are being sent to the request handler method of my controller instead. The only thing I can think of is that the #RequestMapping annotation has precedence over mvc:resources, but that doesn't make a lot of sense.
I have verified that the resource URLs are being generated correctly, i.e. the template line
<link rel="stylesheet" href="${contextPath}/static/css/gallery.css">
generates
<link rel="stylesheet" href="/gallery/static/css/gallery.css">
and the request is being received by the Tomcat server, just routed to the wrong place.
I've read most of the questions on SO about this subject and I believe I'm doing it right (see for example Trying to get mvc resources to serve my static resources), but clearly I'm missing something obvious.
Environment
Eclipse Luna
Java 8
Tomcat 8
Freemarker 2.3.23
Spring 4.2.0
Windows 7 SP1
Deployed Layout
Standard Java EE Tomcat directory structure
webapps
|- gallery
|- css
|- images
|- js
|- META-INF
|- WEB-INF
|- classes
|- lib
|- views
Tomcat Context Definition
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="D:\dev\tools\apache-tomcat-8.0.24\wtpwebapps\gallery"
path="/gallery" reloadable="true"
source="org.eclipse.jst.j2ee.server:gallery"/>
Spring Servlet Config
WEB-INF/main-servlet.xml
...
<mvc:resources mapping="/static/**" location="/" />
<mvc:annotation-driven/>
<context:component-scan base-package="com.mysite.gallery"/>
...
I've tried all possible orderings of these statements but that seems to have no effect. I also tried adding
<mvc:default-servlet-handler/>
with no effect.
WEB-INF/web.xml
Standard Spring MVC DispatcherServlet config
...
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>main</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
...
RequestMapping method
...
#RequestMapping("/**")
public String gallery(ModelMap modelMap, HttpServletRequest req, HttpServletResponse resp)
{
etc...
Freemarker Template
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="${contextPath}/static/css/photoswipe.css">
<link rel="stylesheet" href="${contextPath}/static/css/default-skin/default-skin.css">
<link rel="stylesheet" href="${contextPath}/static/css/gallery.css">
<script src="${contextPath}/static/js/photoswipe.min.js"></script>
<script src="${contextPath}/static/js/photoswipe-ui-default.min.js"></script>
</head>
<body>
<div>
...

You gave the answer in your question: The only thing I can think of is that the #RequestMapping annotation has precedence over mvc:resources, but that doesn't make a lot of sense.
You may think it does not make sense, but is is how Spring fellow decided it should be, at least by default...
But you have different ways for static ressources to have precedences on the #RequestMapping annotated controller.
The simplest way is to add an "order=0" attribute to the <mvc:resources.../> tag :
<mvc:resources mapping="/static/**" location="/" order="0"/>
and to write it in WEB-INF/main-servlet.xml before <mvc:annotation-driven/>
I tested in with Spring 3.2.4 and it works like you want. But it looks like driving spring framework where it was not designed for, so I cannot guarantee that it will work on other versions.
You could also map the dispatcher servlet to / instead of /*. That way all static resources (and also JSP) that can be served directly by the servlet container will be. The main caveat with that mapping, is that root will no longer be served by Spring dispatcher servlet. One possible workaround it to use a /home URL for the root controller, and put a welcome file in web xml :
<servlet>
<servlet-name>main</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/home</welcome-file>
</welcome-file-list>
That way, you to not even need to use /mappings/images/img.gif, just use /images/img.gif/.
But there is another caveat, that I have always accepted (because I could not find any workaround): if /url is served by one controller, /url.jsp or /url.jpeg will give a 404 error. As the container default servlet knows about .jpeg or .jsp files it will catch the request and fail.

Related

Spring MVC 4 File Upload Failing Silently

I'm using Spring MVC (Version 4.1) on Tomcat 8, and am desperately trying to make the file upload functionality work. Currently, I have a controller configured like this:
#RequestMapping(value={"/TestCase/Upload"}, method=RequestMethod.POST)
#ResponseBody
public ResponseEntity<String> uploadFile(HttpServletRequest request,
#RequestParam("file") MultipartFile file) {
System.out.println("Hit this location.");
return new ResponseEntity("Success");
}
My web.xml has the appropriate server configuration:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
<!-- Configuration for file upload (configuring Multipart file) -->
<multipart-config>
<location>/tmp</location>
<max-file-size>500000</max-file-size>
<max-request-size>505000</max-request-size>
<file-size-threshold>10485</file-size-threshold>
</multipart-config>
</servlet>
And finally, my Spring xml configuration file has the necessary resolver specified:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="500000" />
</bean>
The Apache commons-fileupload JAR is on the classpath.
I have used this approach successfully in the past on non-Tomcat servers, but now the application isn't working - but it's failing quietly. The response has a status code of 200, but nothing inside of the file upload controller method is executed. There are no exceptions thrown in the server logs, and the only way I can get the controller method to print anything out is if I remove the "Multipart" parameter entirely. At first I thought that the controller method wasn't being hit at all, but if I change the URL mapping, then the calling code throws a 404 - so it is definitely hitting the correct mapping/method - it's just that nothing inside of the method is executing (with no exceptions thrown!)
What am I doing wrong?
It turns out Spring MVC will hide noClassDef's from the console when booting itself up. The issue was that apache-commons-io.jar was missing on the classpath. Including that JAR caused everything to work properly.
So in the future if Spring is quietly misbehaving - check to ensure all necessary libraries are explicitly included, because it certainly won't tell you!

Set servlet as default home page in web.xml [duplicate]

This question already has answers here:
Change default homepage in root path to servlet with doGet
(2 answers)
Closed 7 years ago.
I've a servlet registered in web.xml as below.
<servlet>
<servlet-name>Manager</servlet-name>
<servlet-class>Manager</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/RequestManager</url-pattern>
</servlet-mapping>
Basically I want to call this servlet as my default home page when I open http://localhost:8080/appname. So, I tried registering it as welcome file in same web.xml as below:
<welcome-file-list>
<welcome-file>Manager</welcome-file>
</welcome-file-list>
But, when I run the project, I get an error saying "requested resource not available". However, if I write in the url with my servlet URL pattern, it works fine.
Specify an empty string as servlet's URL pattern.
<servlet>
<servlet-name>Manager</servlet-name>
<servlet-class>Manager</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern></url-pattern>
</servlet-mapping>
See also:
Difference between / and /* in servlet mapping url pattern
Unrelated to the concrete problem, the <welcome-file> should represent an URL path, not a servlet name. It'd have worked if you specifed <welcome-file>RequestManager</welcome-file>. But this affects all subfolders. Actually, the <welcome-file> has an entirely different meaning than "home page file" you've had in mind. It represents the default resource which should be served when a folder is been requested.
You can use index.jsp to forward to your servlet.
<jsp:forward page="servlet_context">
and add index.jsp as welcome file in web.xml
inside servlet class you can forward Control Using :
request.getRequestDispatcher("forward page URL").forward(req,res);
or else if you are using JSP then use
<% RequestDispatcher rd = servletContext.getRequestDispatcher("/pathToResource");
rd.forward(request, response); %>
or
<jsp:forward page="relative URL" />

Spring servlet in web.xml with missing contextConfigLocation param-value

I have a web.xml file with (among other things) a servlet that defines an init-param to specify the contextConfigLocation, but the param-value is BLANK?
Why is the developer doing this. I can't for the life of me find anything in the documentations for Spring 3.X that tells me what effect this has.
<servlet>
<servlet-name>restservices</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
By default the DispatcherServlet will load a xml file named [servlet-name]-servlet.xml.
This is when no init-param named contextConfigLocation is defined.
However in your case there is an init-param named contextConfigLocation defined, which tells the DispatcherServlet to load nothing but only delegate to the parent context (the one loaded by the ContextLoaderListener).
So in short there is a difference between no init-param defined or an empty init-param.
See also https://jira.springsource.org/browse/SPR-4746.
it just because the developer had nothing to declare in the servlet configuration.
he had maybe defined all what he needs in the root context.
Ah. Generally, the dispatcher servlet would follow the convention of searching for servlet-name - servlet.xml to load the WebAppContext.
It might be (and this is just guess work because i dont know your config) that there already is a file restservices-servlet.xml which is
loaded using the ContextLoaderListener
Or imported in your applicationContext.xml ( or its equivalent)
Or isnt needed, because all the beans for the Controller/ViewResolver
are configured in your applicationContext.xml
Typically, the DispatcherServlet config (WebappContext) should contain the Controller/ViewResolver bean definitions.

Servlet mapping url mapping issue with spring and BIRT

In my application I'm using spring MVC(3.0.5) architecture along with BIRT reporting framework.
I'm trying to serve all requests including the static resources like css, js, html and image files using the spring DispatcherServlet.
For this purpose I added the following entries to my web.xml
<servlet>
<servlet-name>springapp</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
...............
...............
<servlet-mapping>
<servlet-name>springapp</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
This will direct all request to the DispatcherServlet and in my context file I added
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/docs/**" location="/docs/" />
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/js/**" location="/js/" />
<mvc:resources mapping="/themes/**" location="/themes/" />
so that these resources will be loaded from the file system.
These configurations are working fine. But I'm facing issues with my BIRT reporting engine now.
The BIRT reporting engine uses some jsp files located in a folder called webcontent which is located at the root of the application. Since we are directing all request to DispatcherServlet even the request for these jsp pages are going to the spring servlet. As I understand from some posts the jsp files are normally handled by org.apache.jasper.servlet.JspServlet which is registered in the Apache Tomcat's web.xml file and it has a servlet mapping as follows
<!-- The mapping for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
What are the changes that I should make in my servlet mapping to work in this environment? I need the jsp files to be handled by the default jsp servlet not by the spring servlet. How can I achieve this?
For this post I understood that the second priority in servlet matching is for the url prefix, so my url pattern / for spring servelt is overriding the default jsp servlet mapping, Is this assumption correct? If it is correct then how to overcome this?
Thank you.
The typical mapping of DispatcherServlet is <url-pattern>/</url-pattern>. In this case it still handles all requests except for requests handled by other servlets (in particular, requests to *.jsp), so that it should solve the problem.

Setup a Filter that will set the Response Header to only Image File(s)

I am having a caching problem based on the discussion that I have in this link
But I am not sure how to go about with the suggestion on setting the response headers on my Spring MVC.
Does anybody know how to setup a some sort of a filter that will add add a response header only on image files?
I currently am not an expert on J2EE web development with SPring MVC.
Any idea?
Spring comes with a Resources Servlet.
<!-- Serves static resource content from .jar files such as blartoch.jar -->
<servlet>
<servlet-name>Resources Servlet</servlet-name>
<servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
<load-on-startup>50</load-on-startup>
</servlet>
<!-- Map all /resources requests to the Resource Servlet for handling -->
<servlet-mapping>
<servlet-name>Resources Servlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
We are using an ear file and all of my resources are in a jar in the ear. If you are only deploying a WAR file (perhaps to tomcat), then try putting your resources in a jar and putting the jar in your WAR file's /WEB-INF/lib directory.
If you store your resources (inside the jar) in the following directory:
/META-INF/common/images
requests for your resources will look something like this:
<img src="<c:url value="/resources/common/images/cuteKitten.jpg"/>"/>

Resources