struts2 18拦截器详解(十二) --- CheckboxInterceptor

CheckboxInterceptor

   该拦截器处于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>

   当进入到该拦截器之后,判断当前迭代的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)方法:


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方法:

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[]返回
}

   看到上面的源码大家应该知道为什么为出现结果不一致的原因了。到此该拦截器就讲解完毕了,准备下一个拦截器啦......


你可能感兴趣的:(struts2,Interceptor)