有人能解释一下servlet映射吗?

51

我正在尝试使用SpringMVC编写Web应用程序。通常,我会将一些自定义的文件扩展名映射到Spring的前端控制器上,并且可以顺利地运行,但这次我想要REST-like URL,没有文件名扩展名。

将我的上下文路径下的所有内容都映射到前端控制器(我们称之为“app”)意味着我还需要处理静态文件,这是我不想做的事情(为什么要重复造轮子?),因此与Tomcat的默认servlet(我们称之为“tomcat”)结合使用似乎是可行的方法。

我通过以下方式使它正常工作:

<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>*.ext</url-pattern>
</servlet-mapping>

并且对于我的静态内容的每个文件扩展名重复执行后者。我只是想知道为什么以下设置(对我来说与上述设置等效)不起作用。

<!-- failed attempt #1 -->
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>*.ext</url-pattern>
</servlet-mapping>

<!-- failed attempt #2 -->
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>/some-static-content-folder/*</url-pattern>
</servlet-mapping>

有人可以解释一下吗?


http://static.springsource.org/spring-webflow/docs/2.0.x/reference/html/ch12s03.html - user330178
相关链接: https://dev59.com/uWYq5IYBdhLWcg3wwDNA#14225540 - informatik01
3个回答

43

我想我可能知道发生了什么。

在你的工作 web.xml 文件中,你已将 servlet 设置为默认 servlet(/ 本身是默认 servlet,如果没有其他匹配项,它将响应任何请求),它将回答任何不匹配其他映射的请求。

在 Failed 1 中,你的 /* 映射似乎是一个有效的路径映射。 在 web.xml 中,/* 映射会回答除了其他路径映射之外的所有请求。根据规范,扩展名映射是被显式映射覆盖的隐式映射。这就是为什么扩展名映射失败的原因。一切都被明确地映射到了 app。

在 Failed 2 中,app 负责所有事情,除了与静态内容映射相匹配的内容。为了展示快速测试中发生了什么,这里有一个例子。/some-static-content-folder/ 包含 test.png

尝试访问 test.png,我尝试了:

/some-static-content-folder/test.png

文件未找到。但是正在尝试。

/some-static-content-folder/some-static-content-folder/test.png

似乎出了一些问题。因此,在Tomcat默认servlet(至少是6.0.16)中,它会丢弃servlet映射并尝试通过剩余路径查找文件。根据这篇文章Servlet for serving static content,Jetty的行为更符合您和我的预期。

你不能像映射一个根目录来处理rest调用吗?例如将"app"映射到"/rest_root/*",然后你就需要对"rest_root"文件夹里的任何内容负责,但除此之外的其他地方都应该由Tomcat来处理,除非你进行另一个显式的映射。我建议将rest servlet设置为path mapping,因为它可以更好地表明意图。使用"/"或"/*"似乎不适当,因为你必须映射出例外情况。以SO作为例子,我的rest mappings应该如下:

用户servlet的路径映射为"/users/*"

帖子servlet的路径映射为"/posts/*"

映射顺序

  1. 显式(Path mappings)
  2. 隐式(Extension mappings)
  3. 默认(/)

请纠正我搞错的任何内容。


“Failed attempt #1”的解释非常准确。但是我仍然无法弄清另一个问题。 - agnul
如果/*已经映射到“app” servlet,那么将“/”映射到什么会有什么好处? - matt b
如果你使用 /,那么映射不会有任何收益,因为它永远不会被调用。使用 / 的缺点是你需要处理所有的东西,而使用 / 你仍然可以设置扩展映射。 - Philip Tinney
2
有点疯狂,意识到Servlet不支持像'/myAppModules//Services/'这样的通配符。我可以想到许多其他服务器可以处理这个问题,但Servlet却不能。有趣的是,业余爱好者级别的WAMP可以做到,但“企业级”Servlet却不能。 - Joseph Lust
我还没有深入研究过,但是Jersey(http://jersey.java.net/)应该能够更轻松地构建REST映射。似乎找不到任何类似于Rails Routes的Java分发器。 - Philip Tinney
显示剩余2条评论

3

参考一下,在Tomcat版本>=6.0.29中,“失败的尝试#2”是完全正确的。

这是Tomcat bug的结果,已在版本6.0.29中得到修复:

https://issues.apache.org/bugzilla/show_bug.cgi?id=50026

<!-- Correct for Tomcat >= 6.0.29 or other Servlet containers -->
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>default</servlet-name>
  <url-pattern>/some-static-content-folder/*</url-pattern>
</servlet-mapping>

2

我从未尝试过像这样映射servlet,但我会认为/*在技术上既以/开头又以/*结尾,即使相同的字符用于两个匹配。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接