servlet映射url模式中的/和/ *之间的区别
熟悉的代码:
<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
映射?
<url-pattern>/*</url-pattern>
servlet上的/*
覆盖所有其他的servlet,包括servlet容器提供的所有servlet,比如默认的servlet和JSP servlet。 不pipe你发起什么请求,它都会在这个servlet中结束。 这是servlet的一个错误的URL模式。 通常,您只想在Filter
上使用/*
。 通过调用FilterChain#doFilter()
它可以让请求继续到监听更具体的URL模式的任何servlet。
<url-pattern>/</url-pattern>
/
不会覆盖任何其他的servlet。 它只replaceservletcontainer的内置默认servlet,用于所有不匹配任何其他注册servlet的请求。 这通常只在静态资源(CSS / JS / image / etc)和目录列表上被调用。 servlet容器的内置默认servlet也能够处理HTTPcaching请求,媒体(audio/video)stream和文件下载恢复。 通常,您不希望覆盖默认的servlet,否则您将不得不处理所有的任务,这并不是很重要(JSF实用程序库OmniFaces有一个开源 示例 )。 这也是servlet的一个错误的URL模式。 至于为什么JSP页面没有命中这个servlet,这是因为servlet容器内置的JSP servlet将被调用,这已经默认映射到更具体的URL模式*.jsp
。
<url-pattern></url-pattern>
然后还有空string的URL模式 。 这将在请求上下文根时被调用。 这与
<welcome-file>
方法不同,它在请求任何子文件夹时不会被调用。 如果您想要“ 主页servlet ”,这很可能是您实际寻找的URL模式。 我只需要承认,我会直观地期望空string的URL模式 和斜杠URL模式
/
正好相反,所以我可以理解,很多初学者对此感到困惑。 但它是这样的。
前部控制器
如果你真的打算有一个前端控制器的servlet,那么你最好把它映射到一个更具体的URL模式,如*.html
, *.do
, /pages/*
, /app/*
等。你可以隐藏前端控制器的URL模式,并在servletfilter的帮助下,覆盖像/resources/*
, /static/*
等通用URL模式的静态资源。 另请参见如何防止静态资源被映射在/ *上的前端控制器servlet处理 。 值得注意的是,Spring MVC有一个内置的静态资源servlet,所以这就是为什么你可以将它的前端控制器映射到/
如果你在Spring中为静态资源configuration了一个通用的URL模式。 另请参见如何处理Spring MVC中的静态内容?
我想用映射规则和示例来补充BalusC的答案。
从Servlet 2.5规范映射规则:
- 地图确切的url
- 映射通配符path
- 地图扩展
- 映射到默认的servlet
在我们的例子中,有三个servlet。 /是我们安装的默认servlet。 Tomcat安装两个servlet来提供jsp和jspx。 所以要映射http://host:port/context/hello
- 没有安装确切的URL servlet,接下来。
- 接下来没有安装通配符path的servlet。
- 不匹配任何扩展名,接下来。
- 映射到默认的servlet,返回。
映射http://host:port/context/hello.jsp
- 没有安装确切的URL servlet,接下来。
- 接下来没有安装通配符path的servlet。
- find扩展servlet,返回。
也许你需要知道如何映射url,因为我已经404
几个小时了。 有两种处理请求的处理程序。 BeanNameUrlHandlerMapping
和SimpleUrlHandlerMapping
。 当我们定义一个servlet-mapping
,我们使用SimpleUrlHandlerMapping
。 我们需要知道的一件事是这两个处理程序共享一个名为alwaysUseFullPath
的公共属性,默认为false
。
这里的false
意味着Spring不会使用完整的path来将URL映射到控制器。 这是什么意思? 这意味着当你定义一个servlet-mapping
:
<servlet-mapping> <servlet-name>viewServlet</servlet-name> <url-pattern>/perfix/*</url-pattern> </servlet-mapping>
处理程序将实际使用*
部分来查找控制器。 例如,当您使用/perfix/api/feature/doSomething
请求时,以下控制器将面临404
错误
@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没有关心该path。 你需要改变你的url/perfix/perfix/api/feature/doSomething
或从MyController base @RequestingMapping
删除perfix
。
我认为糖果的答案大多是正确的。 有一小部分,我认为不然。
要映射主机:端口/上下文/ hello.jsp
- 没有安装确切的URL servlet,接下来。
- find通配符path的servlets ,返回。
我相信为什么“/ *”不匹配host:port / context / hello,因为它将“/ hello”视为path而不是文件(因为它没有扩展名)。
/*
和/
之间的本质区别是,在任何带有扩展映射的servlet(比如*.html
)之前,将会select一个映射为/*
servlet,而只有在考虑到扩展映射之后才会select映射为/
的servlet将被用于任何不匹配其他任何请求—它是“默认的servlet”)。
特别是, /*
映射将始终在映射之前被选中。 防止任何请求到达容器自己的默认servlet。
只有在完全匹配的servlet映射(如/foo/bar
)和path映射比/*
(如/foo/*
)更长的映射之后才会被选中。 请注意,空string映射与上下文根( http://host:port/context/
)完全匹配。
请参阅http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html上的; 3.1版Java Servlet规范的第12章。