struts2 18拦截器详解(十六) --- ActionMappingParametersInteceptor

ActionMappingParametersInteceptor

   ActionMappingParametersInteceptor拦截器处于defaultStack第十四的位置,该拦截器继承自ParametersInterceptor,也是用于把参数设置到ValueStack中,只不过该拦截器的参数是来源于ActionMapping中,而不是来自请求参数。往ValueStack中设置值的逻辑与ParametersInterceptor一模一样,正是这个原因才把ParametersInterceptor拦截器放在了该拦截器之前讲解。大家可以发现该拦截器只是覆盖了ParametersInterceptor的两个方法:

@Override
protected Map<String, Object> retrieveParameters(ActionContext ac) {
	//获取AcitonMapping对象
    ActionMapping mapping = (ActionMapping) ac.get(ServletActionContext.ACTION_MAPPING);
    if (mapping != null) {
        return mapping.getParams();//获取AcitonMapping参数
    } else {
        return Collections.emptyMap();
    }
}

@Override//将参数设置到ActionContext的parameters Map中
protected void addParametersToContext(ActionContext ac, Map newParams) {
	//获取请求参数
    Map previousParams = ac.getParameters();
    Map combinedParams = null;
    if (previousParams != null) {
        combinedParams = new TreeMap(previousParams);
    } else {
        combinedParams = new TreeMap();
    }
    //newParams为ActionMapping中的经过了合法性检查后的合法参数
    combinedParams.putAll(newParams);
	//将请求参数与合法参数一起设置到ActionContext的parameters Map中
    ac.setParameters(combinedParams);
}

   因为现在执行的是ActionMappingParametersInteceptor拦截器所以在ParametersInterceptor的doIntercept方法中调用的retrieveParameters方法是ActionMappingParametersInteceptor拦截器中的retrieveParameters,这是java多态的表现,所以该拦截器通过覆盖父类的retrieveParameters方法达到了改变参数来源的目的。
   在ParametersInterceptor拦截器的setParameters方法中最后一句调用了addParametersToContext方法,而在ActionMappingParametersInteceptor子类中覆盖了addParametersToContext方法,所以执行的也是ActionMappingParametersInteceptor拦截器定义的addParametersToContext方法,将将请求参数与合法参数一起设置到ActionContext的parameters Map中。

   但有一点需要大家注意,就是ActionMapping的参数永远为null,所以执行该拦截器时为ValueStack设置值的操作根本就不会发生,下面通过源代码进行证明。在证明之前ActionConfig,ActionMapping,ActionMapper之间的关系需要明白,ActionConfig对象保存的是Action的配置信息,ActionMapping对象保存的是Action的映射信息,ActionMapper是根据你访问的URL去ActionConfig中进行匹配再映射成ActionMapping对象。例如,一个Action的配置中可以有多个方法,可以有多个Result,但是在执行的时候只能执行Action中的一个方法,返回的时候只能有一个Result而ActionMapper的功能就是根据URL与AcitonConfig映射成ActionMapping对象。

StrutsPrepareAndExecuteFilter的doFilter方法:


public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
	//省略...
	ActionMapping mapping = prepare.findActionMapping(request, response, true);//调用prepare对象的findActionMapping
	//省略...
}

下面是findActionMapping方法:
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
    ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
    if (mapping == null || forceLookup) {
        try {
        	//去容器中找ActionMapper对象,并调用ActionMapper对象的getMapping方法返回ActionMapping对象
            mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
            if (mapping != null) {
                request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
            }
        } catch (Exception ex) {
            dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
        }
    }
    return mapping;
}

   ActionMapper是一个接口,在struts2中其默认实现类是org.apache.struts2.dispatcher.mapper.DefaultActionMapper,下面是该类的getMapping方法:

public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) {
    ActionMapping mapping = new ActionMapping();//新建一个ActionMapping对象
    String uri = getUri(request);//获取URI

    int indexOfSemicolon = uri.indexOf(";");
    uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;//处理 URI

    uri = dropExtension(uri, mapping);//去掉URI后缀
    if (uri == null) {
        return null;
    }
	//解析Action的namespace与name
    parseNameAndNamespace(uri, mapping, configManager);
	//处理特殊参数
    handleSpecialParameters(request, mapping);

    if (mapping.getName() == null) {
        return null;
    }
	//解析ActionName,因为struts2可以支持动态方法调用,如:xxxAction!login
    parseActionName(mapping);

    return mapping;
}

   一开始以为会在handleSpecialParameters设置ActionMapping参数,但进去看了以后发现也没有为ActionMapping设置参数的操作,所以对于用DefaultActionMapper作为ActionMapper的的实现类的话,ActionMapping中的参数是为null的。

   到此该拦截器就讲到这里了,准备下一个拦截器......


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