ServletConfig


在 Web 容器啟動後,會讀取標註(Annotation)或 web.xml 的設定,根據當中的每個 Servlet 的設定,將 Servlet 類別載入並實例化,並為每個 Servlet 的設定產生一個 ServletConfig 物件,而後呼叫 Servlet 介面的 init() 方法,並將產生的 ServletConfig 物件當作引數傳入。

ServletConfig 即 Servlet 中的標註或 web.xml 中每個 <servlet> 設定的代表物件,容器會為每個 Servlet 設定產生一個 ServletServletConfig 實例。GenericServlet 同時實作了 ServletServletConfig

ServletConfig

GenericServlet 主要的目的之一,就是將初始 Servlet 呼叫 init() 方法所傳入的 ServletConfig 封裝起來:

private transient ServletConfig config;
public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
}
public void init() throws ServletException {
}

GenericServlet 在實作 Servletinit() 方法時,也呼叫了另一個無參數的 init() 方法,基本上在撰寫 Servlet 時,如果有一些初始時所要執行的動作,可以重新定義這個無參數的 init() 方法,而不是直接重新定義有 ServletConfig 參數的 init() 方法。

注意!當你有一些物件實例化後所要執行的動作,必須定義建構式。在撰寫 Servlet 時,若想要執行與Web應用程式資源相關的初始化動作時,則要重新定義 init() 方法。

舉例來說,若你想要使用 ServletConfig 來作一些事情,則不能在建構式中定義,因為實例化 Servlet 時,因為容器還沒有呼叫 init() 方法傳入 ServletConfig,所以不會有 ServletConfig 實例。

GenericServlet 也包括了 ServletServletConfig 定義方法的簡單實作,實作內容主要是透過 ServletConfig 來取得一些相關資訊,例如:

public ServletConfig getServletConfig() {
    return config;
}
public String getInitParameter(String name) {
    return getServletConfig().getInitParameter(name);
}
public Enumeration getInitParameterNames() {
    return getServletConfig().getInitParameterNames();
}   
public ServletContext getServletContext() {
    return getServletConfig().getServletContext();
}

所以在繼承 HttpServlet 實作 Servlet 時,就可以透過這些方法來取得所要的相關資訊,而不用直接意識到 ServletConfig 的存在。

若要使用標註設定個別 Servlet 的初始參數,可以在 @WebServlet 中使用 @WebInitParam 設定 initParams。例如:

...
@WebServlet(
    urlPatterns={"/conf"},
    initParams={
        @WebInitParam(name = "PARAM1", value = "VALUE1"),
        @WebInitParam(name = "PARAM2", value = "VALUE2")
    }
)
public class ServletConfigDemo extends HttpServlet {
    private String PARAM1;
    private String PARAM2;

    public void init() throws ServletException {
        super.init();
        PARAM1 = getInitParameter("PARAM1");
        PARAM2 = getInitParameter("PARAM2");
    }
    ....
}

若要在 web.xml 中設定個別 Servlet 的初始參數,可以在 <servlet> 標籤之中,使用 <init-param> 進行設定。例如:

...
<servlet>
    <servlet-name>ServletConfigDemo</servlet-name>
    <servlet-class>cc.openhome.ServletConfigDemo</servlet-class>
    <init-param>
        <param-name>PARAM1</param-name>
        <param-value>VALUE1</param-value>
    </init-param>
    <init-param>
        <param-name>PARAM2</param-name>
        <param-value>VALUE2</param-value>
    </init-param>
</servlet>
...

由於 ServletConfig 必須在 Web 容器將 Servlet 實例化後,呼叫有參數的 init() 方法再將之傳入,是與 Web 應用程式資源相關的物件,所以在繼承 HttpServlet 後,通常會重新定義無參數的 init() 方法以進行 Servlet 初始參數的取得。

下面這個範例簡單地示範如何設定、使用 Servlet 初始參數,其中登入成功與失敗的網頁,可以由初始參數設定來決定:

package cc.openhome;

import java.io.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;

@WebServlet(
    urlPatterns = {"/login"},
    initParams = {
        @WebInitParam(name = "SUCCESS", value = "user"),
        @WebInitParam(name = "ERROR", value = "login.html")
    }
)
public class Login extends HttpServlet {
    private String SUCCESS_VIEW;
    private String ERROR_VIEW;

    @Override
    public void init() throws ServletException {
        super.init();
        SUCCESS_VIEW = this.getInitParameter("SUCCESS");
        ERROR_VIEW = this.getInitParameter("ERROR");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
        String name = request.getParameter("name");
        String passwd = request.getParameter("passwd");
        if("caterpillar".equals(name) && "123456".equals(passwd)) {
            request.changeSessionId();
            request.getSession().setAttribute("login", name);
            response.sendRedirect(SUCCESS_VIEW);
        }
        else {
            response.sendRedirect(ERROR_VIEW);
        }
    }
}