CheckboxInterceptor 該攔截器處於defaultStack第十一的位置,看這個攔截器的名稱應該就是對checkbox進行處理的。要理解這個攔截器的作用有一點必須知道:當一個form表單中存在一個checkbox的時候,假設這個checkbox的name屬性值為married,當我們選上這個checkbox的時候請求參數命令裡有一個married=true參數,而當我們沒有選上這個checkbox的時候,請求參數裡面根本就沒有這個married參數,就相當於form表單中根本就沒有這個checkbox,而大多數情況下我們想要的結果是,當沒有選上這個checkbox的時候請求參數集合裡有這個married參數,只不過它的值為"false"。問題引出來了,而該攔截器就可以用來解決這個問題。下面是該攔截器的intercept方法源碼: [java] public String intercept(ActionInvocation ai) throws Exception { Map parameters = ai.getInvocationContext().getParameters();//獲取請求參數Map Map<String, String[]> newParams = new HashMap<String, String[]>();//創建一個新參數Map Set<Map.Entry> entries = parameters.entrySet(); for (Iterator<Map.Entry> iterator = entries.iterator(); iterator.hasNext();) {//迭代請求參數Map Map.Entry entry = iterator.next(); String key = (String)entry.getKey();//獲取當前迭代的請求參數的key,即form表單字段的name屬性值 if (key.startsWith("__checkbox_")) {//判斷key是否以__checkbox_開關 String name = key.substring("__checkbox_".length());//獲取當前key __checkbox_後面部分字符串 //獲取當前entry的值 Object values = entry.getValue(); iterator.remove();//從請求參數Map中移除當前entry if (values != null && values instanceof String[] && ((String[])values).length > 1) { //如果進入該if語句,則說明同一個checkbox設置了兩次,則直接進入下一個entry LOG.debug("Bypassing automatic checkbox detection due to multiple checkboxes of the same name: #1", name); continue; } // 判斷名為 name變量值 的checkbox是否被選中,沒有選中則不會有相應的參數 if (!parameters.containsKey(name)) { // 沒有選中則向新參數Map中添加一個key為 name變量值 的長度為1的字符串數組 newParams.put(name, new String[]{uncheckedValue}); } } } //把新的參數Map加入到請求參數Map中 parameters.putAll(newParams); //調用下一個攔截器 return ai.invoke(); } 為了更好的理解該攔截器的功能,下面列舉一個表單: [html] <form action="xtayfjpk.do" method="post"> <input type="checkbox" name="married" value="3"/>已婚<br/> <input type="hidden" name="__checkbox_married"/><br/> <input type="submit" value="提交"/> </form> 當進入到該攔截器之後,判斷當前迭代的name屬性值是否以__checkbox_開頭,如果不是以__checkbox_開關則沒有任何操作,如果以__checkbox_開頭則把__checkbox_後面的部分截取出來,這裡即得到married,然後獲取_checkbox_married參數值,再將該參數從請求參數Map中移除(因為這個參數只是一個標記而已),然後獲取__checkbox_married的值,正常情況應該是為null的,但如果有值則說明相同意義的checkbox被設置了兩次這樣就會打印一個debug信息不再執行下面的操作。正常情況為null則去判斷married checkbox有無被選中,選中了married參數就會在request參數Map中,如果沒有選中則不會,但通過newParams.put(name, new String[]{uncheckedValue});這句代碼給married賦值了一個長度為1的字符串數組其值為uncheckedValue,該值是可以設置的,默認值為"false",最後把newParams中的數據全部添加到request請求參數Map中,完成邏輯,再調用下一個攔截器。 不知道大家有沒有發現獲取的請求參數值返回的是String[],而不是一個字符串,就拿checkbox舉個例子,如果用多個checkbox讓用戶選愛好,這樣就可能出現多個愛好,所以要用一個String[]去接收,為了統一參數接收,即是一個值的返回的也是一個String[],只不過數組長度為1。 既然一個參數名可以接收多個參數值,那為什麼上面例子當__checkbox_married有值的時候卻不再執行下面的代碼了呢?這是因為__checkbox_married這個參數只是用來標識當married checkbox沒有選中的時候該攔截器要不要對其進行處理,而正常情況下是不應該有值的。要使該攔截器有效則必須在form表單中添加一個名為"__checkbox_"+要處理的checkbox的name屬性值的字段。 這裡呢再講一下關於request對象取參數值方法的一點細節: 當調用request.getParameter(key)返回的是一個字符串,調用request.getParameterMap.get(key)返回的是一個字符串數組,一開始覺得有點迷惑,覺得返回值應該是相同的,這裡卻出現了不一樣的結果(key相同),後來去翻了Tomcat的源碼才弄明白。 request.getParameter(key),實際調用的是org.apache.tomcat.util.http.Parameters類中的getParameter(String name)方法: [java] public String getParameter(String name) { handleQueryParameters(); ArrayList values = (ArrayList)this.paramHashValues.get(name); if (values != null) { if (values.size() == 0) return ""; return ((String)values.get(0));//返回index為0的元素 } return null; } request.getParameterMap.get(key),實際調用的是org.apache.tomcat.util.http.Parameters類中的getParameterMap方法: [java] public Map getParameterMap() { if (parameterMap.isLocked()) return parameterMap; Enumeration enumeration = getParameterNames(); while (enumeration.hasMoreElements()) { String name = enumeration.nextElement().toString(); String[] values = getParameterValues(name);//獲取值數組 parameterMap.put(name, values);//放入了parameterMap中 } parameterMap.setLocked(true); return parameterMap; } public String[] getParameterValues(String name) {//該方法獲取值數組 handleQueryParameters(); ArrayList values = (ArrayList)this.paramHashValues.get(name); if (values == null) return null; return ((String[])values.toArray(new String[values.size()]));//將values ArrayList轉成了String[]返回 }