armnotstrong
armnotstrong

Reputation: 9065

spring servlet url-pattern map not working with star sign

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? enter image description here

So, the question became :

Upvotes: 1

Views: 2916

Answers (1)

Serge Ballesta
Serge Ballesta

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 :

  • when servlet is mapped to /view/admin servlet path is /view/admin and path info is null
  • when servlet is mapped to /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

Related Questions