刨根問底-struts-http請求的預處理

FilterDispatcher是struts2的核心控制器,每一個請求都會進入FilterDispatcher對象的doFilter()方法。而後再struts.xml文件中根據action的name屬性進行匹配,找到要執行的action類和方法,執行完方法返回結果。 java

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        ServletContext servletContext = getServletContext();

        String timerKey = "FilterDispatcher_doFilter: ";
        try {

            // FIXME: this should be refactored better to not duplicate work with the action invocation
            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
            ActionContext ctx = new ActionContext(stack.getContext());
            ActionContext.setContext(ctx);

            UtilTimerStack.push(timerKey);
            request = prepareDispatcherAndWrapRequest(request, response);
            ActionMapping mapping;
            try {//根據url取得對應的Action的配置信息      //看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存儲在 ActionMapping對象中                                            mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
            } catch (Exception ex) {
                log.error("error getting ActionMapping", ex);
                dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
                return;
            } //若是找不到對應的action配置,則直接返回。好比你輸入***.jsp等 if (mapping == null) {
                // there is no action in this request, should we look for a static resource?
                String resourcePath = RequestUtils.getServletPath(request);

                if ("".equals(resourcePath) && null != request.getPathInfo()) {
                    resourcePath = request.getPathInfo();
                }

                if (staticResourceLoader.canHandle(resourcePath)) {
                    staticResourceLoader.findStaticResource(resourcePath, request, response);
                } else {
                    // this is a normal request, let it pass through
                    chain.doFilter(request, response);
                }
                // The framework did its job here
                return;
            } //正式開始Action的方法           後面詳細解釋                                                 dispatcher.serviceAction(request, response, servletContext, mapping);

        } finally {
            dispatcher.cleanUpRequest(request);
            try {
                ActionContextCleanUp.cleanUp(req);
            } finally {
                UtilTimerStack.pop(timerKey);
            }
            devModeOverride.remove();
        }
    }

因爲這個doFilter()是重點,主要是3個功能: web

(1)encoding和Local是web頁面上的重要屬性,也是web程序進行國際化il8n處理的核心參數。prepareDispatcherAndWrapRequest()設置encoding和Local參數。並對httpServletRequest進行必定的封裝 apache

(2)ActionContext的建立老是伴隨着valueStack的建立。valueStackFactory負責建立valueStack,併爲valueStack設置上下文環境;緊接着valueStack建立的就是ActionContext,而且ActionContext的建立以valueStack的上下文環境做爲參數。 session

valueStack的上下文環境與ActionContext的數據存儲空間是等同的。代碼證實:  ctx = new ActionContext(stack.getContext()); app

(3)解析請求url,而且把值賦值給ActionMapping對象 jsp

(4)serviceAction執行action ide

如今咱們就重點分析解析url,serviceAction執行action後面再詳細分析 測試

二、getMapping()方法:ActionMapper接口的實現類 DefaultActionMapper的getMapping() this

/*
     * (non-Javadoc)
     *
     * @see org.apache.struts2.dispatcher.mapper.ActionMapper#getMapping(javax.servlet.http.HttpServletRequest)
     */

    public ActionMapping getMapping(HttpServletRequest request,
                                    ConfigurationManager configManager) {
        ActionMapping mapping = new ActionMapping();//建立一個ActionMapping
        String uri = getUri(request);//獲得請求路徑的URI,如:login.action                         int indexOfSemicolon = uri.indexOf(";");//修正url的帶;jsessionid                          uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;

        uri = dropExtension(uri, mapping);//刪除擴展名,默認擴展名爲action                         if (uri == null) {
            return null;
        }

        parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace     handleSpecialParameters(request, mapping);//去掉特殊參數                                      //若是Action的name沒有解析出來,直接返回                                                     if (mapping.getName() == null) {
            return null;
        }

        parseActionName(mapping);//主要是處理name!add 格式的解析

        return mapping;
    }

    protected ActionMapping parseActionName(ActionMapping mapping) {
        if (mapping.getName() == null) {
            return mapping;
        }
        if (allowDynamicMethodCalls) {
            // handle "name!method" convention.
            String name = mapping.getName();
            int exclamation = name.lastIndexOf("!");
            if (exclamation != -1) {
                mapping.setName(name.substring(0, exclamation));//提取左邊爲name  mapping.setMethod(name.substring(exclamation + 1));//提取右邊的method }
        }
        return mapping;
    }

註釋:getMapping()方法返回ActionMapping類型的對象,該對象包含三個參數:Action的name、namespace和要調用的方法method url

2.1查看ActionMapping對象:裏面有name等等屬性

public class ActionMapping {

    private String name;
    private String namespace;
    private String method;
    private String extension;
    private Map<String, Object> params;
    private Result result;

}
2.2getUri(request)獲取請求路徑:


/**
     * Gets the uri from the request
     *
     * @param request The request
     * @return The uri
     */
    protected String getUri(HttpServletRequest request) {
        // handle http dispatcher includes.
        String uri = (String) request
                .getAttribute("javax.servlet.include.servlet_path");
        if (uri != null) {
            return uri;
        }

        uri = RequestUtils.getServletPath(request);
        if (uri != null && !"".equals(uri)) {
            return uri;
        }

        uri = request.getRequestURI();
        return uri.substring(request.getContextPath().length());
    }
註釋:request.getContextPath() 其做用是獲取當前的系統路徑


我作了一個測試,先看看打印結果:

uRequestUtils.getServletPath(request) = /skip.action
request.getRequestURI()  = /gaokao/skip.action
request.getContextPath() = /gaokao

不難看出getUri(request)是爲了得到請求路徑 /skip.action

2.三、dropExtension(uri, mapping)刪除擴展名

  protected List<String> extensions = new ArrayList<String>() {{
        add("action");
        add("");
    }};
protected String dropExtension(String name, ActionMapping mapping) {
        if (extensions == null) {
            return name;
        }
        for (String ext : extensions) {
            if ("".equals(ext)) {  int index = name.lastIndexOf('.');
                if (index == -1 || name.indexOf('/', index) >= 0) {
                    return name;
                }
            } else {//刪除擴展名.action
                String extension = "." + ext;
                if (name.endsWith(extension)) {
                    name = name.substring(0, name.length() - extension.length());
                    mapping.setExtension(ext);
                    return name;
                }
            }
        }
        return null;
    }

extensions中默認的保存了action,其餘事怎麼加入的呢?

@Inject(StrutsConstants.STRUTS_ACTION_EXTENSION)
    public void setExtensions(String extensions) {
        if (extensions != null && !"".equals(extensions)) {
            List<String> list = new ArrayList<String>();
            String[] tokens = extensions.split(",");
            for (String token : tokens) {
                list.add(token);
            }
            if (extensions.endsWith(",")) {
                list.add("");
            }
            this.extensions = Collections.unmodifiableList(list);
        } else {
            this.extensions = null;
        }
    }
原來是預處理, 經過註解在初始化的時候賦值,STRUTS_ACTION_EXTENSION = "struts.action.extension"

想一想之前在struts.properties文件中設置struts.action.extension=action,原來是這的道理啊,哈哈。

2.4 parseNameAndNamespace(uri, mapping, configManager)從uri中解析出來name和namespace,而且把name和names賦值給mapping。

2.5 handleSpecialParameters(request, mapping)去除特殊參數:

public void handleSpecialParameters(HttpServletRequest request,
                                        ActionMapping mapping) {
        // handle special parameter prefixes.
        Set<String> uniqueParameters = new HashSet<String>();
        Map parameterMap = request.getParameterMap();
        for (Iterator iterator = parameterMap.keySet().iterator(); iterator
                .hasNext();) {
            String key = (String) iterator.next();

            // Strip off the image button location info, if found
            if (key.endsWith(".x") || key.endsWith(".y")) {
                key = key.substring(0, key.length() - 2);
            }

            // Ensure a parameter doesn't get processed twice
            if (!uniqueParameters.contains(key)) {
                ParameterAction parameterAction = (ParameterAction) prefixTrie
                        .get(key);
                if (parameterAction != null) {
                    parameterAction.execute(key, mapping);
                    uniqueParameters.add(key);
                    break;
                }
            }
        }
    }
註釋;主要是去除鼠標參數,橫豎座標。
相關文章
相關標籤/搜索