如何在web.xml中使用Servlet url映射?

2022-09-01 20:13:52

我有一个包含以下内容的 web.xml 文件:

<servlet>
    <servlet-name>servlet1</servlet-name>
    <servlet-class>org.mycompany.test1</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet2</servlet-name>
    <servlet-class>org.mycompany.test2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet1</servlet-name>
    <url-pattern>/path/test</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet2</servlet-name>
    <url-pattern>/path/test/*</url-pattern>
</servlet-mapping>

我尝试了请求

.../path/test/abc 
.../path/test

这两个请求都由 Servlet2 处理。为什么?

更新

谢谢你们的帮助。我意识到行为取决于 servlet 映射声明的顺序。我试过这个网站.xml

<servlet>
    <servlet-name>servlet1</servlet-name>
    <servlet-class>org.mycompany.test1</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet2</servlet-name>
    <servlet-class>org.mycompany.test2</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet3</servlet-name>
    <servlet-class>org.mycompany.test3</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet4</servlet-name>
    <servlet-class>org.mycompany.test4</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>servlet1</servlet-name>
    <url-pattern>/path/test</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet2</servlet-name>
    <url-pattern>/path/test/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet3</servlet-name>
    <url-pattern>/path/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet4</servlet-name>
    <url-pattern>/path</url-pattern>
</servlet-mapping>

结果:

.../path/test/abc - servlet2
.../path/test/ - servlet2
.../path/test - servlet2

.../path/abc - servlet3
.../path/ - servlet4
.../path - servlet4

答案 1

从 Servlet 3.0 规范来看,这是 Web 容器在收到请求后必须如何定位 Servlet(强调我的):

用于映射到 servlet 的路径是来自请求对象的请求 URL 减去上下文路径和路径参数。下面的 URL 路径映射规则按顺序使用。使用第一个成功的匹配,但不尝试进一步的匹配

  1. 容器将尝试查找请求路径与 servlet 路径的完全匹配。成功的匹配将选择 servlet。
  2. 容器将以递归方式尝试匹配最长的路径前缀。这是通过一次在路径树中单步执行一个目录,使用“/”字符作为路径分隔符来完成的。最长的匹配项决定了所选的 servlet。
  3. 如果 URL 路径中的最后一个段包含扩展(例如.jsp),则 servlet 容器将尝试匹配处理扩展请求的 servlet。扩展被定义为最后一个“.”字符之后的最后一个段的一部分。
  4. 如果前三个规则都没有导致 servlet 匹配,容器将尝试提供适合所请求资源的内容。如果为应用程序定义了“默认”servlet,则将使用它。许多容器提供用于提供内容的隐式默认 servlet。

容器必须使用区分大小写的字符串比较进行匹配。

您还应该查看映射的规范(如下所示):

在 Web 应用程序部署描述符中,以下语法用于定义映射:

  • 以字符开头并以后缀结尾的字符串用于路径映射。‘/’‘/*’

  • 以前缀开头的字符串用作扩展映射。‘*.’

  • 空字符串是一种特殊的 URL 模式,它完全映射到应用程序的上下文根,即格式为 的请求。在本例中,路径信息为,servlet 路径和上下文路径为空字符串。("")http://host:port/<contextroot>/’/’(““)

  • 仅包含该字符的字符串指示应用程序的“默认”servlet。在这种情况下,servlet 路径是请求 URI 减去上下文路径,路径信息为 null。’/’

  • 所有其他字符串仅用于完全匹配

现在让我们看一些例子。请考虑以下一组映射:

Path Pattern            Servlet
/foo/bar/*              servlet1
/baz/*                  servlet2
/catalog                servlet3
*.bop                   servlet4

将会导致以下行为:

Incoming Path           Servlet Handling Request
/foo/bar/index.html     servlet1
/foo/bar/index.bop      servlet1
/baz                    servlet2
/baz/index.html         servlet2
/catalog                servlet3
/catalog/index.html     “default” servlet
/catalog/racecar.bop    servlet4
/index.bop              servlet4

请注意,在 和 的情况下,不使用映射到的 servlet,因为匹配项不精确。/catalog/index.html/catalog/racecar.bop“/catalog”

现在来看看你的问题:)

/path/test属于映射规范的第 5 点。这意味着只有 以 结尾的路径才会以 为目标。/path/testservlet1

但是,符合同一规范的第一点。这意味着:/path/test/*

.../path/test将由 和 处理servlet1

.../path/test/abc将由servlet2

这是我在测试应用程序中验证的。


答案 2

您的路径冲突。

你的两条路径的意思相同,“/*”没有任何区别。显然,当您尝试路径时,将执行最后一个匹配项(servlet2)。

您通常输入带有Servlet名称的路径,例如:

/path/test/servlet1
/path/test/servlet2

推荐