servlet 映射
上周,我通过对学生的作业进行评分,讲述了一个可以使用过滤器的创意用途 。 关于,还有一个经常出现的问题,值得关注的博客文章:servlet映射。 尽管从表面上看servlet映射似乎很容易,但有时它们可能是造成巨大麻烦的原因。
问题
在上述作业中,学生必须创建一个模拟的电子商务商店应用程序。 主页显示标题,简介短语以及醒目的图像。 问题是未显示图像。
此时,学生可以发挥创造力-毕竟这是一项作业。 他们要么放弃显示图像的要求,要么使用在线托管的图像-热链接。 后者效果惊人!
同样,找不到JavaScript和CSS文件。 为了使它们起作用,它们会内联。
让我们看看是什么原因。
分析
JavaEE Web应用程序提供了两种路径映射方法:
- servlet映射一个,可以在
web.xml
Web部署描述符中配置,也可以通过类上的@WebServlet
注释配置。@WebServlet("/foo") publicclassFooServletextendsHttpServlet{...}
现在可以在
/foo
路径下访问该servlet。 - 资源一:可以直接访问
WEB-INF
文件夹中没有的任何内容。sample.war |__ image | |__ a.jpg | |__ b.jpg |__ script | |__ a.js |__ style | |__ a.css |___ WEB-INF |__ web.xml
根据上述结构,将公开以下路径:
-
/image/a.jpg
-
/image/a.jpg
-
/script/a.js
-
/style/a.css
-
最终用户不知道路径是由servlet还是由静态资源提供的。 Servlet可以映射到/foo.html
。 同样,可以实现一个提供动态图像的servlet并将其映射到*.jpg
。
现在很重要。 当请求路径时,服务器首先寻找匹配的servlet映射。 如果未找到,则尝试按路径查找相关的静态资源。 因此,如果两个servlet映射都匹配同一路径,则它会覆盖静态资源 。
在以上问题中,罪魁祸首确实是一个servlet,更确切地说是一个映射到/
映射的servlet。
@WebServlet("/")
publicclassHomePageServletextendsHttpServlet{...}
通过在调试模式下运行JVM,并在所述servlet的service()
方法内设置一个断点,可以很容易地证明这一点。 很明显,它遮盖了每个静态资源。
这个怎么运作
Servlet规范的一部分专门介绍映射和路径匹配。 摘录如下:
- 容器将尝试查找请求路径与Servlet路径的精确匹配。 成功匹配将选择servlet。
- 容器将递归地尝试匹配最长的路径前缀。 这是通过使用
/
字符作为路径分隔符,一次将路径树下移到一个目录来完成的。 最长的匹配决定了所选的servlet。- 如果URL路径中的最后一段包含扩展名( 例如
.jsp
),则Servlet容器将尝试匹配处理该扩展名请求的servlet。 扩展定义为last段之后的last段的一部分.
字符。- 如果前三个规则均未导致servlet匹配,则容器将尝试提供适合于所请求资源的内容。 如果为应用程序定义了“默认” servlet,则将使用它。 许多容器提供了一个隐式默认servlet来提供内容。
请注意提到默认服务 。 该默认servlet是映射到/
默认servlet,它的确会匹配其他servlet未匹配的每个路径,因为最长的路径匹配规则。
解
该解决方案还可以在规范中找到:
空字符串(“”)是一种特殊的URL模式,它精确地映射到应用程序的上下文根, 即 ,形式为
http://host:port/<context-root>/
请求。 在这种情况下,路径信息为/
,而servlet路径和上下文路径为空字符串(“”)。
解决方法是仅删除映射到主页的servlet中的/
:
@WebServlet("")
publicclassHomePageServletextendsHttpServlet{...}
结论
细节决定成败。 一个额外的角色可能破坏一个人的应用程序,并使开发人员陷入疯狂的不良解决方法中。 大多数时候,阅读文档(或规格)可以找到正确的解决方案。
servlet 映射