前面的章节讲述了Servlet和Filter,不说一下web.xml总感觉少点什么。
好多人都知道web项目要配置web.xml,没有web.xml,web工程就起不来,为什么呢?我跟大部分一样都从未静下心来去细细品味一下。、
web.xml,中文名为部署描述文件,该文件由servlet定义,是web应用的配置文件。
部署描述符文件和其他的XML文件一样,都要由一个XML头开始。
这个头需要声明使用的XML版本,以及该xml使用的字符编码。
DOCYTPE声明可以有,也可以没有,本人使用的maven创建的web工程中,web.xml中没有该部分。
而创建的html文件中则有该部分的声明,例如:<!doctype html>,只是声明该文档是个html。
在这个声明之后,需要指定管理此文件其余部分内容的语法的DTD(Document Type Definition,文档类型定义),该语法会识别你的web.xml填写的是否正确。
在web.xml中其顶层元素为web-app,web.XML元素不像HTML,他们大小写敏感。
下面用maven创建web工程的web.xml代码(web.xml中的成员暂不填写):
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
</web-app>
当一个web程序启动时,web容器(tomcat等)就会去读取web.xml文件。
有人会问为什么叫web.xml,不叫其它的,这个我是没办法解释的,例如猫为什么叫猫....谁知道呢?
至于web容器(tomcat之类)怎么去读取的web.xml,这个我还是能大概说一下。
当tomcat启动的时候,tomcat会获取Catalina等其他类的一些数据,并设置一些参数,这些参数供tomcat使用。
当我们将我们的web应用部署在tomcat上时,tomcat就会读取我们web.xml,读取web.xml的代码如下(截取一部分):
protected void webConfig() {
......
WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
context.getXmlValidation(), context.getXmlBlockExternal());
Set<WebXml> defaults = new HashSet<>();
defaults.add(getDefaultWebXmlFragment(webXmlParser));
WebXml webXml = createWebXml();
// Parse context level web.xml
InputSource contextWebXml = getContextWebXmlSource(); // 读取/WEB-INF/web.xml
if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) { // /WEB-INF/web.xml文件的内容解析到webXml里面
ok = false;
}
ServletContext sContext = context.getServletContext();
Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser); // 解析的是webFragment
......
// Step 3. Look for ServletContainerInitializer implementations
if (ok) {
processServletContainerInitializers(); // 这个是解析继承ServletContainerInitializer类的配置,
}
......
}
上面的代码设定了去哪个路径下读取web.xml并解析,以及获取servletContext等。
由此可知web.xml为什么在web-INF目录下,tomcat是怎么读取web.xml的都进行了简单描述。
我不想讲太多,在这里我想说的是,你不需要深入了解这一块,但是要知道红色线标记的这一块。
如果你想学习更多的,请深入学习一下tomcat,当然也可以参考下面这个大神的博客。
大概说了web容器加载web.xml的过程,接下要说一下web.xml中常用到的成员。
1.schema
web.xml的模式文件是由Sun公司定义的,每个web.xml文件的根元素<web-app>中,都必须标明这个 web.xml使用的是哪个模式文件。
其它的元素都放在<web-app></web-app>之中。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
</web-app>
2.<display-name>,Web应用的名称,用来标记这个特定的Web应用的一个名称
<display-name>Tomcat Example</display-name>
3.<context-param>,web应用上下文参数,声明应用范围内的初始化参数。
它用于向 ServletContext提供键值对,即应用程序上下文信息。我们的listener, filter等在初始化时会用到这些上下文中的信息。
在servlet里面可以通过getServletContext().getInitParameter("context/param")得到。
<context-param>
<param-name>ContextParameter</para-name>
<param-value>test</param-value>
</context-param>
4.<filter>过滤器,将自写的Filter过滤类,添加到web应用中,这个过滤类需要实现javaxs.servlet.Filter接口(具体可以看我前面的章节)
<filter>
<filter-name>setCharacterEncoding</filter-name>
<filter-class>com.abc.FilterA</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>setCharacterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5.<listener>监听器
<listener>
<listerner-class>com.listener.SessionListener</listener-class>
</listener>
6.<servlet>, 用来声明一个servlet的数据
<servlet-name></servlet-name> 指定servlet的名称
<servlet-class></servlet-class> 指定servlet的类名称
<jsp-file></jsp-file> 指定web站台中的某个JSP网页的完整路径
<init-param></init-param> 用来定义参数,可有多个init-param。在servlet类中通过getInitParamenter(String name)方法访问初始化参数
<load-on-startup></load-on-startup>指定当Web应用启动时,装载Servlet的次序。
当值为正数或零时:Servlet容器先加载数值小的servlet,再依次加载其他数值大的servlet。
当值为负或未定义:Servlet容器将在Web客户首次访问这个servlet时加载它。
<servlet-mapping></servlet-mapping> 用来定义servlet所对应的URL,包含两个子元素
<servlet-name></servlet-name> 指定servlet的名称
<url-pattern></url-pattern> 指定servlet所对应的URL
一般都用的是基本配置,高级配置可以忽略
<!-- 基本配置 -->
<servlet>
<servlet-name>snoop</servlet-name>
<servlet-class>SnoopServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>snoop</servlet-name>
<url-pattern>/snoop</url-pattern>
</servlet-mapping>
<!-- 高级配置 -->
<servlet>
<servlet-name>snoop</servlet-name>
<servlet-class>SnoopServlet</servlet-class>
<init-param>
<param-name>foo</param-name>
<param-value>bar</param-value>
</init-param>
<run-as>
<description>Security role for anonymous access</description>
<role-name>tomcat</role-name>
</run-as>
</servlet>
<servlet-mapping>
<servlet-name>snoop</servlet-name>
<url-pattern>/snoop</url-pattern>
</servlet-mapping>
7.<session-config>会话超时配置,单位为分钟
<session-config>
<session-timeout>120</session-timeout>
</session-config>
8.<welcome-file-list>欢迎文件页
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>
9.<error-page>错误页面
<!-- 1、通过错误码来配置error-page。当系统发生×××错误时,跳转到错误处理页面。 -->
<error-page>
<error-code>404</error-code>
<location>/NotFound.jsp</location>
</error-page>
<!-- 2、通过异常的类型配置error-page。当系统发生java.lang.NullException(即空指针异常)时,跳转到错误处理页面。 -->
<error-page>
<exception-type>java.lang.NullException</exception-type>
<location>/error.jsp</location>
</error-page>
web.xml中的常用的基本成员都在上面了。
虽然大多数人已经学习了SSH,不看这一些东西,但是这些东西是真正的基础,搞不懂这些,SSH也就难以更上一层楼。
叙述过了Filter和Listener,也说过了Servlet,那就说一下web容器加载web.xml中成员的顺序:
web容器加载web项目时,会去读取web.xml。在web.xml中,他会读取listener,Filter,Context-param。
读取顺序:首先会读取context-param,再读取listener,读取完这两个,就会去创建ServletContext。
(在listener中,我曾说过,实现指定接口后的监听类可以监听application,即ServletContext。如果不读取Listener,那就没办法创建监听,即接下来对application的相关操作无从得知)
监听读取过了,被监听对象的参数也有了。现在创建被监听对象ServletContext。(被监听对象由web容器创建),然后容器将被监听对象的参数传给监听对象(Context-param传给ServletContext),接下来创建监听对象(listener),在实现的监听对象中,我们可以通过监听对象获得已经创建的ServletContext,以及Context-param参数。
因为ServletContext是当前web项目共享的,所以它比所有的servlet创建的都要早,既然ServletContext比Servlet的创建早,那么对Context-param做相关操作也必然比servlet的创建要早。
由此得知:web.xml中会先读取Context-param,然后是listener,再读取Filter。
Filter因为可以过滤用户对某个Servlet的请求,所以,应该在创建Servlet前被创建。
由此,我们得知:context-param -> listener -> filter -> servlet
另外,web.xml中的成员顺序不影响web容器对其的读取顺序,毕竟取值的时候按key-value读取的。