在 Web 容器啟動後,會讀取標註(Annotation)或 web.xml 的設定,根據當中的每個 Servlet 的設定,將 Servlet 類別載入並實例化,並為每個 Servlet 的設定產生一個 ServletConfig
物件,而後呼叫 Servlet
介面的 init()
方法,並將產生的 ServletConfig
物件當作引數傳入。
ServletConfig
即 Servlet 中的標註或 web.xml 中每個 <servlet>
設定的代表物件,容器會為每個 Servlet 設定產生一個 Servlet
及 ServletConfig
實例。GenericServlet
同時實作了 Servlet
及 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
在實作 Servlet
的 init()
方法時,也呼叫了另一個無參數的 init()
方法,基本上在撰寫 Servlet 時,如果有一些初始時所要執行的動作,可以重新定義這個無參數的 init()
方法,而不是直接重新定義有 ServletConfig
參數的 init()
方法。
注意!當你有一些物件實例化後所要執行的動作,必須定義建構式。在撰寫 Servlet 時,若想要執行與Web應用程式資源相關的初始化動作時,則要重新定義 init()
方法。
舉例來說,若你想要使用 ServletConfig
來作一些事情,則不能在建構式中定義,因為實例化 Servlet 時,因為容器還沒有呼叫 init()
方法傳入 ServletConfig
,所以不會有 ServletConfig
實例。
GenericServlet
也包括了 Servlet
與 ServletConfig
定義方法的簡單實作,實作內容主要是透過 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);
}
}
}