在Struts中,擔任 MVC / Model 2 中Front Controller角色的是ActionServlet,所有的請求都必須先通過它,然而在Struts 1.1後,有關於請求的處理大部份已交由RequestProcessor,當ActionServlet收到GET或POST的請求,其doGet() 或doPost()會呼叫process()方法來處理請求:
protected void process(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
RequestUtils.selectApplication(request,
getServletContext());
getApplicationConfig(
request).getProcessor().process(request, response);
}
HttpServletResponse response)
throws IOException, ServletException {
RequestUtils.selectApplication(request,
getServletContext());
getApplicationConfig(
request).getProcessor().process(request, response);
}
RequestUtils是個工具類,ActionServlet呼叫其selectApplication()方法,藉由 request.getServletPath()來取得請求路徑以選擇應用程式模塊來處理請求,之後從ApplicationConfig物件取得 RequestProcessor物件,將使用者的請求委託它來進行處理。
通常是將ActionServlet當作黑盒子,您只要使用它,然而您也可以繼承ActionServlet來定義自己的控制器,但由於在Struts 1.1中大部份的請求已經委託RequestProcessor來處理,繼承ActionServlet來定義自己的控制器請求處理意義已經不大,通常的 目的是重新定義ActionServlet的init()方法,增加自己的初始化動作:
public class CustomActionServlet extends ActionServlet {
public void init() throws ServletException {
super.init();
// 增加自己的初始化動作
....
}
}
public void init() throws ServletException {
super.init();
// 增加自己的初始化動作
....
}
}
預設的RequestProcessor物件是org.apache.struts.action.RequestProcessor,您可以藉由觀看 process()方法的原始碼來瞭解它作了哪些事情:
public void process(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// 處理 contentType 為 multipart/form-data 的 POST 請求
request = processMultipart(request);
// 取得 URI 路徑
String path = processPath(request, response);
if(path == null)
return;
.....
// 確定客戶端的位置
// 是否要將一個Locale物件儲存在 session 中
// 配合 <controller> 的 locale 屬性使用
processLocale(request, response);
// 確定contentType,預設是 text/html
processContent(request, response);
// 判斷<controller>屬性nocache是否被設定
// 若是,在 response 中加入防止快取的header
processNoCache(request, response);
// 前置處理,預設返回 true
//子類可以重新定義它以決定要不要繼續處理
if(!processPreProcess(request, response)) {
return;
}
// 從URI路徑確定ActionMapping
ActionMapping mapping =
processMapping(request, response, path);
if(mapping == null) {
return;
}
....
// 處理ActionForm
// 如果沒有就新增一個,之後一直使用它
ActionForm form =
processActionForm(request, response, mapping);
// 將表單的欄位值填入ActionForm
processPopulate(request, response, form, mapping);
// 判斷是否執行ActionForm的validate()方法
if(!processValidate(request, response, form, mapping)) {
return;
}
// 判斷 <action> 標籤的 forward 或 include 標籤
// 是不是被設定,這兩個標籤在設定一個路徑
// 其與 type 屬性是互斥的,當設定其中一個屬性時
// 調用 RequestDispatcher 的 forward() 或 include()
// 其作用與設定ForwardAction或IncludeAction相同
// 直接繞送而不再使用Action物件進行接下來的處理
if(!processForward(request, response, mapping)) {
return;
}
if(processInclude(request, response, mapping)) {
return;
}
// 處理Action,如果沒有就生成一個,之後一直使用它
Action action =
processActionCreate(request, response, mapping);
if(action == null) {
return;
}
// 呼叫Action的execute()或perform()方法
// 並返回ActionForward
ActionForward forward =
processActionPerform(request,
response,
action,
for, mapping);
// 處理ActionForward
processActionForward(request, response, forward);
}
HttpServletResponse response)
throws IOException, ServletException {
// 處理 contentType 為 multipart/form-data 的 POST 請求
request = processMultipart(request);
// 取得 URI 路徑
String path = processPath(request, response);
if(path == null)
return;
.....
// 確定客戶端的位置
// 是否要將一個Locale物件儲存在 session 中
// 配合 <controller> 的 locale 屬性使用
processLocale(request, response);
// 確定contentType,預設是 text/html
processContent(request, response);
// 判斷<controller>屬性nocache是否被設定
// 若是,在 response 中加入防止快取的header
processNoCache(request, response);
// 前置處理,預設返回 true
//子類可以重新定義它以決定要不要繼續處理
if(!processPreProcess(request, response)) {
return;
}
// 從URI路徑確定ActionMapping
ActionMapping mapping =
processMapping(request, response, path);
if(mapping == null) {
return;
}
....
// 處理ActionForm
// 如果沒有就新增一個,之後一直使用它
ActionForm form =
processActionForm(request, response, mapping);
// 將表單的欄位值填入ActionForm
processPopulate(request, response, form, mapping);
// 判斷是否執行ActionForm的validate()方法
if(!processValidate(request, response, form, mapping)) {
return;
}
// 判斷 <action> 標籤的 forward 或 include 標籤
// 是不是被設定,這兩個標籤在設定一個路徑
// 其與 type 屬性是互斥的,當設定其中一個屬性時
// 調用 RequestDispatcher 的 forward() 或 include()
// 其作用與設定ForwardAction或IncludeAction相同
// 直接繞送而不再使用Action物件進行接下來的處理
if(!processForward(request, response, mapping)) {
return;
}
if(processInclude(request, response, mapping)) {
return;
}
// 處理Action,如果沒有就生成一個,之後一直使用它
Action action =
processActionCreate(request, response, mapping);
if(action == null) {
return;
}
// 呼叫Action的execute()或perform()方法
// 並返回ActionForward
ActionForward forward =
processActionPerform(request,
response,
action,
for, mapping);
// 處理ActionForward
processActionForward(request, response, forward);
}
您可以繼承RequestProcessor,並改寫其中的processXXXXX()方法來自定義請求的處理方式,如果您要使用自己的 RequestProcessor,要在struts-config.xml中使用<controller>標籤來定義,例如:
- struts-config.xml
...
<controller
contentType="text/html;charset=Big5"
locale="true"
nocache="true"
processorClass="caterpillar.CustomRequestProcessor"/>
...
在Struts 1.1後,新增了<controller>標籤,它可以用於指定ActionServlet的一些參數,在Struts 1.1之前,這些參數是在<init-params>中加以指定,使用<controller>標籤,應用程式中不同的模組也可 以指定各自的參數給ActionServlet。