如何使用web.xml中的Servlet URL映射?

我有一个包含内容的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处理 . 为什么?

UPDATE

谢谢你们的帮助 . 我意识到行为取决于servlet映射声明的顺序 . 我试过这个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>
    <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

回答(2)

2 years ago

从Servlet 3.0 specification,这是Web容器在收到请求后必须找到servlet的方式(强调我的):

用于映射到servlet的路径是请求对象中的请求URL减去上下文路径和路径参数 . 下面的URL路径映射规则按顺序使用 . 第一次成功匹配使用,未尝试进一步匹配:容器将尝试查找请求路径与servlet路径的完全匹配 . 成功匹配选择servlet . 容器将递归地尝试匹配最长的路径前缀 . 这是通过使用'/'字符作为路径分隔符一次单击目录的路径树来完成的 . 最长匹配确定所选的servlet . 如果URL路径中的最后一个段包含扩展名(例如.jsp),则servlet容器将尝试匹配处理扩展请求的servlet . 扩展名被定义为最后一个“ . ”字符后的最后一个段的一部分 . 如果前三个规则都不会导致servlet匹配,则容器将尝试提供适合所请求资源的内容 . 如果为应用程序定义了“默认”servlet,则将使用它 . 许多容器提供用于提供内容的隐式默认servlet . 容器必须使用区分大小写的字符串比较进行匹配 .

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

在Web应用程序部署描述符中,使用以下语法定义映射:以“/”字符开头并以“/ ”后缀结尾的字符串用于路径映射 . 以“ . ”前缀开头的字符串用作扩展名映射 . 空字符串(“”)是一个特殊的URL模式,它精确映射到应用程序的上下文根,即http:// host:port / <contextroot> /形式的请求 . 在这种情况下,路径信息是'/',servlet路径和上下文路径是空字符串(“”) . 仅包含'/'字符的字符串表示应用程序的“默认”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

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

现在来解决你的问题:)

/path/test 属于映射规范的第5点 . 这意味着只有以 /path/test 结尾的路径才会定位 servlet1 .

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

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

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

我在测试应用程序中验证了这一点 .

2 years ago

你的路径冲突 .

你的两条路径都是一样的,'/ *'没有任何区别 . 显然,当您尝试路径时,将执行最后一个匹配(servlet2) .

您通常会使用Servlet名称放入路径,例如:

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