Reputation: 9065
In the web.xml
if I specified the servlet map with a full path like this:
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/view/admin</url-pattern>
</servlet-mapping>
It works fine, but if I using a star sign(*) according to the specification (chapter 12.2):
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//. 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.
Like this:
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/view/*</url-pattern>
</servlet-mapping>
The map rule just not work, and glassfish gives a log like:
[glassfish 4.0] [WARNING] [] [org.springframework.web.servlet.PageNotFound] [tid: _ThreadID=19 _ThreadName=http-listener-1(2)] [timeMillis: 1422503740955] [levelValue: 900] [[No mapping found for HTTP request with URI [/view/admin] in DispatcherServlet with name 'spring']]
What should be wrong?(I have found what cause this, please read on)
Additional info on Spring MVC configure and the Controller Class
Following is some more additional information that required by comments.
The full web.xml
is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/view/*</url-pattern>
</servlet-mapping>
</web-app>
And here is the spring-servlet.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd ">
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="com.ksider.service.searchserver.controller"></context:component-scan>
<bean id="freemarkerSettings" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/view/" />
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">0</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="locale">zh_CN</prop>
<prop key="url_escaping_charset">UTF-8</prop>
<prop key="whitespace_stripping">true</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="number_format">0.##</prop>
<prop key="classic_compatible">true</prop>
</props>
</property>
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape" />
</map>
</property>
</bean>
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
<!-- <property name="viewNames" value="*.ftl"/> -->
<property name="contentType" value="text/html; charset=utf-8"/>
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
<property name="order" value="1"/>
<property name="exposeSpringMacroHelpers" value="true"/>
<property name="requestContextAttribute" value="rc"/>
</bean>
</beans>
And this is the controller:
package com.ksider.service.searchserver.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class AdminController {
@RequestMapping(value = "/view/admin", method = RequestMethod.GET)
public String getAdminPage(ModelMap modelMap){
modelMap.put("Msg","hello");
return "admin/index";
}
}
Progress update:
I have fond what cause this, if I use
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/view/*</url-pattern>
</servlet-mapping>
instead of
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/view/admin</url-pattern>
</servlet-mapping>
Some how I should add a prefix /view
to every request, like
if I want to query http://localhost:8080/view/admin
I should query http://localhost:8080/view/view/admin
instead.
I think this is a very confusing issue :-(
I just check the servlet mapping reference and can't get a clue why this happened. Maybe some trick Spring mvc to blame?
So, the question became :
Upvotes: 1
Views: 2916
Reputation: 149155
There are 2 different problems.
First is how the servlet container maps to a servlet. You have correctly interpreted that : if servlet is mapped to /view/admin
or /view/*
it will equally receive the request.
Next is how the request is decoded and processed by spring DispatcherServlet
. Servlet specification 3.0 (3.5 Request Path Elements) says :
/view/admin
servlet path is /view/admin
and path info is null/view/*
servlet path is /view
and path info id /admin
When DispatcherServlet
finds a null path info, it looks for the servlet path in its mappings (and finds your controller), but if path info is not null, it assumes that servlet path is a prefix that is not in the mappings.
That's the reason why you find your controller under /view/view/admin
: first /view
is eaten by servlet path and path info /view/admin
is the mapping for the controller.
When you map the DispatcherServlet
to /view/*
, the controller mappings must not contain the servlet path => you controller mapping should be /admin
Upvotes: 2