该拦截器处于defaultStack第十一的位置,看这个拦截器的名称应该就是对checkbox进行处理的。要理解这个拦截器的作用有一点必须知道:当一个form表单中存在一个checkbox的时候,假设这个checkbox的name属性值为married,当我们选上这个checkbox的时候请求参数命令里有一个married=true参数,而当我们没有选上这个checkbox的时候,请求参数里面根本就没有这个married参数,就相当于form表单中根本就没有这个checkbox,而大多数情况下我们想要的结果是,当没有选上这个checkbox的时候请求参数集合里有这个married参数,只不过它的值为"false"。问题引出来了,而该拦截器就可以用来解决这个问题。下面是该拦截器的intercept方法源码:
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(); }
<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>
既然一个参数名可以接收多个参数值,那为什么上面例子当__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)方法:
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; }
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[]返回 }