1. 程式人生 > >【Head First Servlets and JSP】筆記7:如何創建一個全局的dog?

【Head First Servlets and JSP】筆記7:如何創建一個全局的dog?

函數 response servlet對象 用戶 技術 而是 ... first int

重定向與請求分派

“局部”參數——ServletConfig——servlet初始化參數

“全局”參數——ServletContext——上下文初始化參數

Web app的“構造器”——ServletContextListener

實戰:如何創建一個全局的dog?

1、重定向與請求分派。

        resp.sendRedirect("http://www.cnblogs.com/xkxf/");
        RequestDispatcher view = req.getRequestDispatcher("result.jsp"); // 為JSP實例化一個請求分派器

        view.forward(req, resp); // 使用請求分派器要求容器準備好JSP,並向JSP發送請求和響應
  • 重定向由客戶端完成,請求分派由服務器完成。
  • 重定向是讓客戶完成工作,而請求分派要求服務器上的某某來完成任務。

2、在頁面中顯示email。

很顯然,不可能通過硬編碼來完成。而是需要從數據庫拿數據,可以想象這個過程,當我們點開某個社交網站,然後點開“個人資料”,這個時候servlet中會調用一個getEmail的方法得到email,之後把它傳給視圖,最後展示給用戶。

那麽,有沒必要在部署描述文件(DD,deployment descriptor)中存儲email呢?假設你寫搭建一個個人博客、編輯一份網頁簡歷,這是有可能的,總要好過硬編碼在html中。

3、還是需要快速搭建一個測試環境,沿用上一節的代碼。

4、如何在DD中添加email呢?如下所示:

先修改web.xml,

<?xml version="1.0" encoding="ISO-8859-1" ?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <servlet> <servlet-name>MyTest</servlet-name> <servlet-class>com.example.web.MyTest</servlet-class> <init-param> <param-name>email</param-name> <param-value>[email protected]</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>MyTest</servlet-name> <url-pattern>/MyTest.do</url-pattern> </servlet-mapping> </web-app>

修改servlet,

package com.example.web;

        import javax.servlet.*;
        import javax.servlet.http.*;
        import java.io.*;

public class MyTest extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        resp.setContentType("text/html");

        PrintWriter out = resp.getWriter();
        out.println(getServletConfig().getInitParameter("email"));
        // 這裏相當於調用this.getServletConfig().ge...,this是誰呢?this是一個HttpServlet對象。
    }
}

重啟Tomcat,點擊submit,可以看到

技術分享

BTW:需要註意的是,不能在構造函數中調用getServletConfig(),原因是在這個時候ServletConfig根本不存在!

package javax.servlet;

import java.io.IOException;

public interface Servlet {
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}

回憶一下servlet的生命周期,servlet的生命周期由Web容器所掌控,Web容器首先調用Servlet的構造函數,在這之後才調用Servlet的init()函數。觀察上面的代碼,可以發現init()的參數正是ServletConfig。實際情況是這樣的:

  • 容器初始化一個servlet的時候,會為這個servlet建立一個唯一的ServletConfig。
  • 容器從DD(也就是web.xml)中“讀出”ServletConfig(也就是init-param)並把這些參數交給ServletConfig。然後把ServletConfig傳遞給servlet的init()方法。

5、有時候,需要一個更“全局”的參數,在Web的世界裏,它被叫做上下文初始化參數,與servlet初始化參數不同的是,它的有效範圍是整個Web App,而不僅僅是一個servlet。設置方法為:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <context-param>
        <param-name>email</param-name>
        <param-value>[email protected]</param-value>
    </context-param>

    <servlet>
        <servlet-name>MyTest</servlet-name>
        <servlet-class>com.example.web.MyTest</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>MyTest</servlet-name>
        <url-pattern>/MyTest.do</url-pattern>
    </servlet-mapping>

    <!--在這之後,還可以以有更多的servlet,而context-param是對所有servlet有效的!-->

</web-app>

調用的方式與servlet初始化參數類似:

package com.example.web;

        import javax.servlet.*;
        import javax.servlet.http.*;
        import java.io.*;

public class MyTest extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        resp.setContentType("text/html");

        PrintWriter out = resp.getWriter();
        // out.println(getServletConfig().getInitParameter("email"));
        out.println(getServletContext().getInitParameter("email"));
        // 只需要把Config改成Context就Ok了!
    }
}

重啟tomcat之後,點擊submit,仍舊會得到相同的輸出頁面,對用戶來說,不會體驗到任何差別!不過需要再次強調:每個servlet有一個ServletConfig,每個Web應用有一個ServletContext。

6、在一些場合下,我們希望有一些代碼在Web應用提供服務之前,首先被執行,類似於通過“靜態加載塊”來加載數據庫連接,也就是在程序正式工作前,完成一些初始化工作,例如,創建一個“全局”的數據庫連接,或是其它的全局對象,這就需要用到ServletContextListener

我們知道,完成一個事件響應,首先需要實現接口,然後註冊事件,最後寫響應方法。那麽,這個Listener應該由誰來註冊呢?如何使用這個監聽者呢?

技術分享

7、一個簡單的ServletContextListener:如何創建一個全局的dog?

package com.example;

public class Dog {
    private String breed;

    public Dog(String breed) {
        this.breed = breed;
    }

    public String getBreed() {
        return breed;
    }
}
<?xml version="1.0" encoding="ISO-8859-1" ?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <servlet>
        <servlet-name>ListenerTester</servlet-name>
        <servlet-class>com.example.ListenerTester</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>ListenerTester</servlet-name>
        <url-pattern>/ListenerTester.do</url-pattern>
    </servlet-mapping>


    <context-param>
        <param-name>breed</param-name>
        <param-value>Great Dane</param-value>
    </context-param>

    <listener>
        <listener-class>
            com.example.MyServletContextListener
            <!--在初始化任何servlet之前初始化應用-->
        </listener-class>
    </listener>

</web-app>
package com.example;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.getServletContext();
        String breed = servletContext.getInitParameter("breed");
        
        Dog dog = new Dog(breed);
        servletContext.setAttribute("dog", dog);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}
package com.example;

import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.*;

public class ListenerTester extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();

        out.println("test context attribute set by listener <br />");
        out.println("<br />");

        Dog dog = (Dog)getServletContext().getAttribute("dog");
        out.println("Dog‘s breed is: " + dog.getBreed());
    }
}

【Head First Servlets and JSP】筆記7:如何創建一個全局的dog?