servlet映射url模式中/和/ *之间的区别

时间:2010-11-10 01:28:39

标签: servlets web.xml url-pattern

熟悉的代码:

<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是如何映射的吗?

5 个答案:

答案 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规范中的映射规则:

  1. 映射确切的网址
  2. 映射通配符路径
  3. 地图附加信息
  4. 映射到默认servlet
  5. 在我们的示例中,有三个servlet。 /是我们安装的默认servlet。 Tomcat安装两个servlet来为jsp和jspx提供服务。所以要映射http://host:port/context/hello

    1. 下一步没有安装确切的URL servlet。
    2. 未安装通配符路径servlet,接下来。
    3. 下一个与任何扩展名都不匹配。
    4. 映射到默认servlet,返回。
    5. 映射http://host:port/context/hello.jsp

      1. 下一步没有安装确切的URL servlet。
      2. 未安装通配符路径servlet,接下来。
      3. 找到扩展servlet,返回。

答案 2 :(得分:22)

也许你需要知道网址是如何映射的,因为我在几个小时内遇到了404。有两种处理请求的处理程序。 BeanNameUrlHandlerMappingSimpleUrlHandlerMapping。当我们定义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

  1. 下一步没有安装确切的URL servlet。
  2. 找到通配符路径servlet ,返回。
  3. 我相信为什么&#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章。