有的时候会困惑,web.xml到底是什么?为什么JavaEE要从web.xml开始呢?嗯,当把这个那个框架抛开,有些基础的问题是非常有趣的。
web.xml不是必须的。你不用它一样可以写出web程序。
web.xml文件是用来配置:welcome、listener、servlet、filter等的。当你的web工程没用到这些,你可以不写web.xml文件。
进入正题。
Spring 提供 ServletContextListener 的一个实现类 ContextLoaderListener,该类可以作为 listener 使用,它会在创建时自动查找 WEB-INF/下的applicationContext.xrnl 文件。
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
如果有多个Spring配置文件需要载入,则考虑使用context-param。
由于ContextLoaderListener加载时,会查找名为contextConfigLocation的参数,配置context-param时参数名字应该是contextConfigLocation。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
Spring MVC 的Servlet,它将加载WEB-INF/123web-servlet.xml 的配置文件,以启动Spring MVC模块。
<servlet>
<servlet-name>123web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>123web</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
session-timeout元素用来指定默认的会话超时时间间隔,以分钟为单位。该元素值必须为整数。如果session-timeout元素的值为零或负数,则表示会话将永远不会超时。
<session-config>
<session-timeout>30</session-timeout>
</session-config>
404及welcome页面:
<welcome-file-list>
<welcome-file>index.do</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
其中关于web.xml的一些有意思的细节问题:
@加载顺序
加载顺序与它们在 web.xml 文件中的先后顺序无关。即不会因为 filter 写在 listener 的前面而会先加载 filter。最终得出的结论是:listener -> filter -> servlet,同时还存在着这样一种配置节:context-param,它用于向 ServletContext 提供键值对,即应用程序上下文信息。我们的 listener, filter 等在初始化时会用到这些上下文中的信息,那么 context-param 配置节是不是应该写在 listener 配置节前呢?实际上 context-param 配置节可写在任意位置,因此真 正的加载顺序为:context-param -> listener -> filter -> servlet
@Mapping规则
当一个请求发送到servlet容器的时候,容器先会将请求的url减去当前应用上下文的路径作为servlet的映射url,比如我访问的是http://localhost/test/aaa.html,我的应用上下文是test,容器会将http://localhost/test去掉,剩下的/aaa.html部分拿来做servlet的映射匹配。这个映射匹配过程是有顺序的,而且当有一个servlet匹配成功以后,就不会去理会剩下的servlet了(filter不同,后文会提到)。其匹配规则和顺序如下:
1. 精确路径匹配。例子:比如servletA 的url-pattern为 /test,servletB的url-pattern为 /* ,这个时候,如果我访问的url为http://localhost/test ,这个时候容器就会先 进行精确路径匹配,发现/test正好被servletA精确匹配,那么就去调用servletA,也不会去理会其他的servlet了。
2. 最长路径匹配。例子:servletA的url-pattern为/test/*,而servletB的url-pattern为/test/a/*,此时访问http://localhost/test/a时,容器会选择路径最长的servlet来匹配,也就是这里的servletB。
3. 扩展匹配,如果url最后一段包含扩展,容器将会根据扩展选择合适的servlet。例子:servletA的url-pattern:*.action
@不同的映射
以”/’开头和以”/*”结尾的是用来做路径映射的。
以前缀”*.”开头的是用来做扩展映射的。
所以,为什么定义”/*.action”这样一个看起来很正常的匹配会错?因为这个匹配即属于路径映射,也属于扩展映射,导致容器无法判断。