我们在一般在配置 SSM 项目时会将 DispatcherServlet
的 url-pattern
配置为 *.do
、 *.action
、 /*
或 /
, 今天就来分析一下它们的区别。以及 Tomcat 中内置的两个 Servlet: DefaultServlet
和 JspServlet
。
我们来列举一下在 web.xml 中 url-pattern 的几种情况:
匹配规则 | url-pattern | 举例 |
---|---|---|
精确匹配 | /login | /login, 不能匹配 /login/ |
前缀匹配 | /user/* | /user、/user/、/user/home、user/index |
后缀匹配 | *.do | /getUser.do、/addUser.do |
缺省匹配 | / | 所有没有被映射的路径都将由该匹配规则处理, 如 default servlet |
/*
认为是一种特殊的前缀匹配。/*
的优先级介于前缀匹配和后缀匹配之间。我们先来看一下 default servlet 是什么。
tomcat/web.xml at 9.0.x · apache/tomcat - GitHub
这是 Tomcat 中的 basic web.xml
, 它将对容器内的所有 webapp 生效 (除非里面的内容被覆盖)。
通过 basic web.xml 我们可以看出, 在 Tomcat 中内置了两个 Servlet: DefaultServlet 和 JspServlet, 且它们的 url-pattern 如下
<!-- The mapping for the default servlet --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- The mappings for the JSP servlet --> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> </servlet-mapping>
也就是说我们在 Tomcat 中的所有 webapp 都内置了两个 servlet, 其中 JspServlet
用于处理所有以 *.jsp
为后缀的请求, 而 DefaultServlet
用于处理那些没有被映射的请求, 比如: css
、js
、jpg
...
你可以在 tomcat/DefaultServlet.java at main · apache/tomcat - GitHub 阅读 DefaultServlet
的源代码。
同理, 你应该也可以在 GitHub 上找到 JspServlet 的源代码, 这里不再赘述。
通过上面的分析, 可以了解到 Tomcat 是如何加载 jsp 文件和静态资源的, 接下来看一下我们该如何配置 DispatcherServlet
的 url-pattern
。
在 SpringMVC 的配置文件中有一个 <mvc:default-servlet-handler/>
标签, 它的作用就是向 IOC 容器中注册一个 org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler
的对象用于处理那些 SpringMVC 未映射的请求 (如: css、js、jpg 等静态资源或其他错误的访问路径), 其本质还是将这些请求交给了 Tomcat 中内置的 DefaultServlet 来处理。
因此我个人认为 DispatcherServlet 映射路径的最佳实践如下:
<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-webmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
根据以上的分析可知: 在 web.xml 中这样配置 DispatcherServlet 的 url-pattern 后 DefaultServlet 将不会生效 (因为 DefaultServlet 的 url-pattern 被覆盖了), 但是 JspServlet 将不受影响, 因此只需要在 SpringMVC 的配置文件中添加 <mvc:default-servlet-handler/>
标签再将静态资源的请求交给 DefaultServlet 处理即可。
但是如果把 DispatcherServlet 的 url-pattern 配置为 /*
那么根据 url-pattern 的优先级, JspServlet 也将不会生效, 因此此时再去访问 jsp 页面将出现 404 错误
(因为 DefaultServlet 也无法处理 jsp 页面的请求, 它只可以处理静态资源的请求)。