web.xml的作用
web.xml,一個Tomcat工程中最重要的配置文件。web.xml沒有其實也可以----只要你確定你的項目里面不需要任何過濾器、監聽器、Servlet等等。我試了一下,沒有web.xml對那些已經編譯成Servlet的jsp頁面來說,是不影響正常顯示的,但是那些沒有編譯成Servlet的jsp頁面,訪問的時候就會報500的錯誤了。下面逐一看一下web.xml里常用標簽的作用。
welcome-file-list
這個標簽是用來配置首頁用的:
<welcome-file-list> <welcome-file>index1.jsp</welcome-file> <welcome-file>index2.jsp</welcome-file> <welcome-file>index3.jsp</welcome-file> <welcome-file>index4.jsp</welcome-file> <welcome-file>/target/redirectAndFoward.jsp</welcome-file> </welcome-file-list>
這么配置的意思,就是當用戶訪問http://ip:port/工程名的時候,會根據welcome-file-list配置的頁面列表,從項目的根目錄開始找頁面:
1、第一個配置的index1.jsp能找到,就展示index1.jsp
2、找不到index1.jsp,則去找第二個index2.jsp,index2.jsp能找到就展示index2.jsp,
3、找不到index3.jsp,則去找第三個index3.jsp,以此類推,如果所有的頁面都找不到則報HTTP Status 404即頁面找不到
注意一下,像配置的最后一個welcome-file這種寫法也是支持的,我試了一下最前面的那個"/"可加可不加
error-page
error-page表示當HTTP返回指定狀態碼的時候,容器將此次請求轉發到配置的指定頁面:
<error-page> <error-code>400</error-code> <location>/filter/error.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/filter/error.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/filter/error.jsp</location> </error-page>
這表示HTTP狀態碼為400、404、500的時候,此次請求都會被轉發到http://ip:port/工程名/filter/error.jsp這個頁面上去。注意一下這里是error-code,所以如果是200的話,是沒有效果的
filter
filter就不說了,兩種include方式及filter中的dispatcher解析一文已經講得很詳細了,filter的寫法也在上面。
另外注意一點,其實大家也都知道,提一下:filter執行的順序就是filter定義的順序。
servlet
servlet開發者比較熟悉,先匹配規則,匹配到路徑后走相應的Servlet類,就不說了。下面配一個相對不那么常用的,只是相對而已,這種servlet的寫法很常見:
<servlet> <servlet-name>startUpServlet</servlet-name> <servlet-class>com.xrq.servlet.StartUpServlet</servlet-class> <init-param> <param-name>Name</param-name> <param-value>123</param-value> </init-param> <init-param> <param-name>Age</param-name> <param-value>456</param-value> </init-param> <load-on-startup>8</load-on-startup> </servlet>
這是一個啟動servlet,表示容器啟動的時候servlet啟動,調用其init()方法,所以首先第一個標簽load-on-start,分幾點說:
1、load-on-startup元素標記容器是否在啟動的時候就加載這個servlet(實例化並調用其init方法)
2、它的值必須是一個整數,表示servlet應該被載入的順序
3、當值為0或者大於0時,表示容器在應用啟動時就加載並初始化這個servlet
4、當值小於0或者沒有指定時,表示這個容器在該servlet被選擇時才會去加載
5、正數值越小,該servlet的優先級就越高,應用啟動時就越先加載
6、當值相同時,容器自己選擇順序來加載
所以,load-on-startup中配置了一個大於等於0的正整數時,該servlet可以當作一個普通的servlet來用,無非是這個servlet啟動的時候會加載其init()方法罷了。
另外一個就是init-param了,表示一個鍵值對,只能在本servlet里面被使用,通過ServletConfig獲取,StartUpServlet的寫法是:
public class StartUpServlet extends HttpServlet { /** * 序列化 */ private static final long serialVersionUID = 1L; public void init() throws ServletException { System.out.println("StartUpServlet.init()"); System.out.println("Name:" + getServletConfig().getInitParameter("Name")); System.out.println("Age:" + getServletConfig().getInitParameter("Age")); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } public void destroy() { System.out.println("StartUpServlet.destory()"); } }
servlet只能取到配置在自己的<servlet>標簽內的<init-param>。
listener
listener即監聽器,是Servlet的監聽器,它可以監聽客戶端的請求、服務器端的操作等,在事情發生前后做一些必要的處理。通過監聽器,可以自動激發一些操作,比如監聽在線用戶數量,下面就寫一個監聽用戶數量的監聽器,首先web.xml配置很簡單:
<listener> <listener-class>com.xrq.listener.UserCounterListener</listener-class> </listener>
寫一個監聽器,監聽用戶數量一般都是以session創建和session失效為依據的,所以實現HttpSessionListener:
public class UserCounterListener implements HttpSessionListener { private AtomicInteger ai = new AtomicInteger(0); public void sessionCreated(HttpSessionEvent se) { ai.incrementAndGet(); } public void sessionDestroyed(HttpSessionEvent se) { ai.decrementAndGet(); } public int getUserCount() { return ai.get(); } }
除了監聽session的監聽器外,再介紹一些別的監聽器接口:
1、ServletContextListener
用於監聽WEB引用啟動和銷毀的事件,SevletContextListener是ServletContext的監聽者,如果ServletContext發生變化,如服務器啟動、服務器關閉,都會被ServletContextListener監聽到。監聽事件為ServletContextEvent
2、ServletContextAttributeListener
用於監聽WEB應用屬性改變的事件,包括添加屬性、刪除屬性、修改屬性。監聽時間為ServletContextAttributeEvent
3、HttpSessionBindingListener
HttpSessionBindingListener是唯一一個不需要在web.xml中配置的Listener,當我們的類實現了HttpSessionBindListener接口后,只要對象加入session或者從session中移除,容器會分別自動調用以下兩個方法:
(1)void valueBound(HttpSesssionBindEvent event)
(2)void valueUnbound(HttpSessionBindingEvent event)
注意,這個監聽器的觸發是針對於實現了該監聽器的類的,只有把實現了該監聽器的類set進session或從session中remove才會觸發這個監聽器
4、HttpSessionAttributeListener
用於監聽HttpSession中的屬性的操作,當session里面增加一個屬性時,觸發attributeAdded(HttpSessionBindEvent se)方法;當在session中刪除一個屬性時,觸發attributeRemoved(HttpSessionBindEvent se)方法;當session屬性被重新設置時,觸發attributeReplaced(HttpSessionBindingEvent se)方法。
注意,這個監聽器的觸發是針對所有的session的,只要session的屬性發生變化,都會觸發這個監聽器
5、HttpSessionListener
這個上面已經寫過了,監聽HttpSession。當創建一個session時,觸發sessionCreated(HttpSessionEvent se)方法;當銷毀一個session時,會觸發sessionDestoryed(HttpSessionEvent se)方法
6、HttpSessionActivationListener
這個用得不太多,主要監聽同一個session轉移至不同的JVM的情形
7、ServletRequestListener和ServletRequestAttributeListener
和ServletContextListener和ServletContextAttributeListener類似,前者監聽Request的創建和銷毀、后者監聽Request中屬性的增刪改
context-param
context-param里面配置的鍵值對是全局共享的,整個web項目都能取到這個上下文,比方說我在web.xml里面配置了一個HTTP端口和一個HTTPS端口:
<context-param> <param-name>NotSSLPort</param-name> <param-value>8080</param-value> </context-param> <context-param> <param-name>SSLPort</param-name> <param-value>8443</param-value> </context-param>
servlet可以這么取:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("NotSSLPort:" + getServletContext().getInitParameter("NotSSLPort")); System.out.println("SSLPort:" + getServletContext().getInitParameter("SSLPort")); }
filter可以這么取:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest)request; ServletContext sc = req.getSession().getServletContext(); System.out.println("NotSSLPort:" + sc.getInitParameter("NotSSLPort")); System.out.println("SSLPort:" + sc.getInitParameter("SSLPort")); chain.doFilter(request, response); }
listener可以這么取,以ServletContextListener為例:
public void contextInitialized(ServletContextEvent sce) { System.out.println("Enter SCListener.contextInitialized"); System.out.println("NotSSLPort:" + sce.getServletContext().getInitParameter("NotSSLPort")); System.out.println("SSLPort:" + sce.getServletContext().getInitParameter("SSLPort")); }
反正最終的目的就是取到一個ServletContext就對了。是不是感覺ServletContext很熟悉呢?沒錯,看一下jsp默認的內置對象,隨便打開一個轉換成Servlet的jsp頁面,里面都有內置對象的定義:
PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; JspWriter _jspx_out = null; PageContext _jspx_page_context = null;
ServletContext也就是我們常說的Application
<mime-mapping>
<mime-mapping>可能不太常見,這個標簽是用來指定對應的格式的瀏覽器處理方式的,添加mime-type的映射,就可以避免某些類型的文件直接在瀏覽器中打開了。
舉個例子:
<mime-mapping> <extension>doc</extension> <mime-type>application/msword</mime-type> </mime-mapping> <mime-mapping> <extension>pdf</extension> <mime-type>application/pdf</mime-type> </mime-mapping> <mime-mapping> <extension>rar</extension> <mime-type>application/x-rar-compressed</mime-type> </mime-mapping> <mime-mapping> <extension>txt</extension> <mime-type>text/plain</mime-type> </mime-mapping> <mime-mapping> <extension>xls</extension> <mime-type>application/vnd.ms-excel</mime-type> </mime-mapping>
這就指定了.doc、pdf、rar、txt、xls這五種類型的文件的打開方式了。常見的MIME類型有:
類 型 | 后 綴 | MIME類型 |
超文本標記語言文本 | .htm、.html | text/html |
普通文本 | .txt | text/plain |
RFT文本 | .rtf | application/rtf |
GIF圖形 | .gif | image/gif |
JPEG圖形 | .jpg、.jpeg | image/jpeg |
au聲音文件 | .au | audio/basic |
MIDI音樂文件 | .mid、.midi | audio/midi、audio/x-midi |
RealAudio音樂文件 | .ra、.ram | audio/x-pn-realaudio |
MPEG文件 | .mpg、.mpeg | video/mpeg |
AVI文件 | .avi | video/x-msvideo |
GZIP文件 | .gz | application/x-gzip |
TAR文件 | .tar | application/x-tar |
session-config
session-config是用來配置session失效時間的,因為session-config里面只有一個子標簽:
<session-config> <session-timeout>30</session-timeout> </session-config>
以分鍾為單位。當然,代碼里面也可以設置:
"request.getSession.setMaxInactiveInterval(30 * 60);"就可以了,單位為秒。
元素加載順序
首先可以肯定,加載順序與它們在web.xml文件中的先后順序無關,即不會因為filter寫在listener前面就先加載filter。最終得出的結論是listener->filter->servlet。
然后是context-param,用於向ServletContext提供鍵值對,即應用程序上下文信息,listener、filter、servlet都可能會用到這些上下文中的信息,那么context-param是否應該寫在listener、filter、servlet前面呢?未必,context-param可以寫在任何位置,因此真正的加載順序應該是:context-param->listener->filter->servlet。