ActionMappingParametersInteceptor ActionMappingParametersInteceptor攔截器處於defaultStack第十四的位置,該攔截器繼承自ParametersInterceptor,也是用於把參數設置到ValueStack中,只不過該攔截器的參數是來源於ActionMapping中,而不是來自請求參數。往ValueStack中設置值的邏輯與ParametersInterceptor一模一樣,正是這個原因才把ParametersInterceptor攔截器放在了該攔截器之前講解。大家可以發現該攔截器只是覆蓋了ParametersInterceptor的兩個方法: [java] view plaincopy @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方法: [java] public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { //省略... ActionMapping mapping = prepare.findActionMapping(request, response, true);//調用prepare對象的findActionMapping //省略... } 下面是findActionMapping方法: [java] 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方法: [java] 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的。 到此該攔截器就講到這裡了,准備下一個攔截器......