186

熟悉的代码:

<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只映射到根目录。事实上,它会接受http://host:port/context/hello,但会拒绝http://host:port/context/hello.jsp

谁能解释一下是如何http://host:port/context/hello映射的?

4

5 回答 5

285

<url-pattern>/*</url-pattern>

on a servlet 覆盖所有其他 servlet,包括 servletcontainer 提供的/*所有 servlet,例如默认 servlet 和 JSP servlet。无论您发出什么请求,它都会在那个 servlet 中结束。因此,这对于 servlet 来说是一个糟糕的 URL 模式。通常,您只想/*在 a 上使用Filter。它能够让请求继续通过调用FilterChain#doFilter().

<url-pattern>/</url-pattern>

/不会覆盖任何其他 servlet 。它只替换 servletcontainer 的内置默认 servlet,用于所有与任何其他已注册 servlet 不匹配的请求。这通常只在静态资源(CSS/JS/image/etc)和目录列表上调用。servletcontainer 内置的默认 servlet 还能够处理 HTTP 缓存请求、媒体(音频/视频)流和文件下载恢复。通常,您不希望覆盖默认 servlet,否则您将不得不处理它的所有任务,这并非微不足道(JSF 实用程序库OmniFaces有一个开源 示例)。因此,这对于 servlet 来说也是一个糟糕的 URL 模式。至于为什么 JSP 页面没有命中这个 servlet,是因为 servletcontainer 内置的 JSP servlet 会被调用,默认情况下它已经映射到更具体的 URL 模式上*.jsp

<url-pattern></url-pattern>

然后还有空字符串 URL 模式 。这将在请求上下文根时调用。<welcome-file>这与请求任何子文件夹时不调用它的方法不同。如果您想要一个“主页 servlet ” ,这很可能是您实际寻找的 URL 模式。我只需要承认,我直观地期望空字符串 URL 模式 和斜杠 URL 模式/完全相反地定义,所以我可以理解很多初学者对此感到困惑。但是它就是这样啊。

前控制器

如果您确实打算拥有一个前端控制器 servlet,那么您最好将其映射到更具体的 URL 模式上,例如*.html, *.do, /pages/*,/app/*等。您可以隐藏前端控制器 URL 模式并在通用 URL 模式上覆盖静态资源在 servlet 过滤器的帮助下,如/resources/*,等。/static/*另请参阅如何防止静态资源被映射到 /* 的前端控制器 servlet 处理。应该注意的是 Spring MVC 有一个内置的静态资源 servlet,所以/如果你在 Spring 中为静态资源配置一个通用的 URL 模式,你可以映射它的前端控制器。另请参阅如何处理 Spring MVC 中的静态内容?

于 2010-11-10T02:13:46.577 回答
47

我想用映射规则和一个例子来补充 BalusC 的答案。

Servlet 2.5 规范中的映射规则:

  1. 映射确切的 URL
  2. 映射通配符路径
  3. 地图扩展
  4. 映射到默认 servlet

在我们的示例中,有三个 servlet。/ 是我们安装的默认servlet。Tomcat 安装了两个 servlet 来为 jsp 和 jspx 提供服务。所以要映射http://host:port/context/hello

  1. 接下来,没有安装确切的 URL servlet。
  2. 接下来,没有安装通配符路径 servlet。
  3. 不匹配任何扩展名,下一个。
  4. 映射到默认 servlet,返回。

映射http://host:port/context/hello.jsp

  1. 接下来,没有安装确切的 URL servlet。
  2. 接下来,没有安装通配符路径 servlet。
  3. 找到扩展 servlet,返回。
于 2010-11-10T17:00:00.267 回答
26

也许您也需要知道 url 是如何映射的,因为我已经忍受404了几个小时。有两种处理请求的处理程序。BeanNameUrlHandlerMappingSimpleUrlHandlerMapping。当我们定义 aservlet-mapping时,我们正在使用SimpleUrlHandlerMapping. 我们需要知道的一件事是这两个处理程序共享一个名为的公共属性alwaysUseFullPath,默认为false.

false这意味着 Spring 不会使用完整路径将 url 映射到控制器。这是什么意思?这意味着当您定义 a 时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。如前所述,默认值为alwaysUseFullPathfalse,即在你的请求中,仅/api/feature/doSomething用于查找对应的Controller,而没有Controller关心该路径。您需要将您的 url 更改为/perfix/perfix/api/feature/doSomethingperfix从 MyController base中删除@RequestingMapping

于 2015-09-15T07:01:48.833 回答
9

我认为 Candy 的回答大部分是正确的。有一小部分我不这么认为。

映射主机:端口/上下文/hello.jsp

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

我相信为什么 "/*" 不匹配 host:port/context/hello 因为它将 "/hello" 视为路径而不是文件(因为它没有扩展名)。

于 2014-11-14T09:41:43.613 回答
2

/*和之间的本质区别在于/,一个带有映射的 servlet将在/*任何带有扩展映射(如t 匹配其他任何东西——它是“默认 servlet”)。*.html/

特别是,/*映射总是在/映射之前被选择。有任何一个都可以防止任何请求到达容器自己的默认 servlet。

/foo/bar仅在完全匹配的 servlet 映射(如)和路径映射长于/*(如)的 servlet 映射之后才会选择其中一个/foo/*http://host:port/context/请注意,空字符串映射与上下文根 ( )完全匹配。

请参阅 Java Servlet 规范的第 12 章,可在http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html 获得3.1 版。

于 2017-07-27T20:49:00.500 回答