熟悉的代码:
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
我的理解是/*
映射到http://host:port/context/*
。
/
怎么样?它肯定不会映射到http://host:port/context
root。实际上,它会接受http://host:port/context/hello
,但拒绝http://host:port/context/hello.jsp
。
任何人都可以解释http://host:port/context/hello
是如何映射的吗?
答案 0 :(得分:248)
<url-pattern>/*</url-pattern>
servlet上的/*
会覆盖所有其他servlet,包括servletcontainer提供的所有servlet,例如缺省servlet和JSP servlet。无论你发出什么样的请求,它都会在那个servlet中结束。因此,这对于servlet来说是一个糟糕的URL模式。通常,您只想在Filter
上使用/*
。通过调用FilterChain#doFilter()
,它可以让请求继续通过任何监听更具体的URL模式的servlet。
<url-pattern>/</url-pattern>
/
不会覆盖任何其他servlet。它仅替换所有与任何其他已注册servlet不匹配的请求的servletcontainer的内置缺省servlet。这通常仅在静态资源(CSS / JS /图像/等)和目录列表上调用。 servletcontainer的内置默认servlet还能够处理HTTP缓存请求,媒体(音频/视频)流和文件下载简历。通常,您不希望覆盖默认的servlet,因为否则必须处理其所有任务,这并非完全无关紧要(JSF实用程序库OmniFaces具有open source {{3} })。因此,这也是servlet的错误URL模式。至于为什么JSP页面没有命中这个servlet,这是因为servletcontainer的内置JSP servlet将被调用,默认情况下已经映射到更具体的URL模式*.jsp
。
<url-pattern></url-pattern>
然后还有空字符串URL模式。当请求上下文根时,将调用此方法。这与example方法的不同之处在于,在请求任何子文件夹时不会调用它。如果您想要“
<welcome-file>
”,这很可能是您实际需要的网址格式。我只需要承认,我直觉地期望空字符串URL模式和斜杠网址模式
/
完全相反地定义,所以我可以理解很多初学者都很困惑就此而言。但事实就是如此。
如果你实际上打算拥有一个前端控制器servlet,那么你最好将它映射到更具体的网址模式,如*.html
,*.do
,{{ 1}},/pages/*
等。您可以借助servlet过滤器隐藏前控制器URL模式并覆盖常见URL模式上的静态资源,如/app/*
,/resources/*
等。另见home page servlet。值得注意的是,Spring MVC有一个内置的静态资源servlet,因此,如果在Spring中为静态资源配置一个公共URL模式,那么就可以在/static/*
上映射其前端控制器。另请参阅How to prevent static resources from being handled by front controller servlet which is mapped on /*
答案 1 :(得分:42)
我想用映射规则和一个例子来补充BalusC的答案。
Servlet 2.5规范中的映射规则:
在我们的示例中,有三个servlet。 /是我们安装的默认servlet。 Tomcat安装两个servlet来为jsp和jspx提供服务。所以要映射http://host:port/context/hello
映射http://host:port/context/hello.jsp
答案 2 :(得分:22)
也许你需要知道网址是如何映射的,因为我在几个小时内遇到了404
。有两种处理请求的处理程序。 BeanNameUrlHandlerMapping
和SimpleUrlHandlerMapping
。当我们定义servlet-mapping
时,我们正在使用SimpleUrlHandlerMapping
。我们需要知道的一件事是这两个处理程序共享一个名为alwaysUseFullPath
的公共属性,默认为false
。
false
这意味着Spring不会使用完整路径来将urp mapp到控制器。这是什么意思?这意味着您定义servlet-mapping
:
<servlet-mapping>
<servlet-name>viewServlet</servlet-name>
<url-pattern>/perfix/*</url-pattern>
</servlet-mapping>
处理程序实际上将使用*
部分来查找控制器。例如,当您使用404
/perfix/api/feature/doSomething
错误
@Controller()
@RequestMapping("/perfix/api/feature")
public class MyController {
@RequestMapping(value = "/doSomething", method = RequestMethod.GET)
@ResponseBody
public String doSomething(HttpServletRequest request) {
....
}
}
这是一场完美的比赛,对吗?但为什么404
。如前所述,alwaysUseFullPath
的默认值为false,这意味着在您的请求中,只有/api/feature/doSomething
用于查找相应的Controller,但没有Controller关心该路径。您需要将自己的网址更改为/perfix/perfix/api/feature/doSomething
或从MyController基础perfix
移除@RequestingMapping
。
答案 3 :(得分:8)
我认为Candy的答案大多是正确的。我认为有一个小部分。
映射host:port / context / hello.jsp
我相信为什么&#34; / *&#34;与host:port / context / hello不匹配,因为它处理&#34; / hello&#34;作为路径而不是文件(因为它没有扩展名)。
答案 4 :(得分:2)
/*
和/
之间的本质区别在于,在具有扩展映射(如/*
)的任何servlet之前,将选择具有映射*.html
的servlet,而只有在考虑了扩展映射之后才会选择带有映射/
的servlet(并且将用于任何与其他任何内容不匹配的请求 - 它是“默认servlet”)。
特别是,在/*
映射之前始终会选择/
映射。要么阻止任何请求到达容器自己的默认servlet。
只有在完全匹配的servlet映射(如/foo/bar
)和路径映射长于/*
(如/foo/*
)之后才会选择。请注意,空字符串映射与上下文根(http://host:port/context/
)完全匹配。
请参阅版本3.1中http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html的Java Servlet规范的第12章。