Struts2中URL处理

来源:互联网 发布:流程梳理,优化建议书 编辑:程序博客网 时间:2024/06/13 07:40

在Struts中,碰到一个奇怪的现象对于一下两个URL可以访问到同一个Action,

链接:
http://localhost:8081/operation/operator/quotetask/operator/quotetask/queryByTaskId.do?quoteTaskId=
http://localhost:8081/operation/operator/quotetask/queryByTaskId.do?quoteTaskId=

在好奇心的驱使下,查看了Struts对于URL的处理源码,在Struts中,主要是需要通过URL找到对应的ActionMapping设置,也就是在Struts.xml中配置的action,其寻找过程如下:
1. 在web.xml中,配置了.do结尾的请求,都会被struts的org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter过滤器过滤。
2. 在StrutsPrepareAndExecuteFilter中的doFilter中,执行寻找ActionMapping,并执行对应的action方法逻辑

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {        HttpServletRequest request = (HttpServletRequest) req;        HttpServletResponse response = (HttpServletResponse) res;        try {            if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {                chain.doFilter(request, response);            } else {                prepare.setEncodingAndLocale(request, response);                // 创建Struts值栈ValueStack                prepare.createActionContext(request, response);                // 设置当前分发工具类Dispatcher到当前线程中                prepare.assignDispatcherToThread();                request = prepare.wrapRequest(request);                // 寻找相应的ActionMapping                ActionMapping mapping = prepare.findActionMapping(request, response, true);                if (mapping == null) {                    boolean handled = execute.executeStaticResourceRequest(request, response);                    if (!handled) {                        chain.doFilter(request, response);                    }                } else {                    execute.executeAction(request, response, mapping);                }            }        } finally {            prepare.cleanupRequest(request);        }    }
  1. 在PrepareOperations.findActionMapping中的逻辑
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {        ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);        if (mapping == null || forceLookup) {            try {                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, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);            }        }        return mapping;    }
  1. 最后处理URL的地方在DefaultActionMapper.parseNameAndNamespace中
protected void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) {        String namespace, name;        int lastSlash = uri.lastIndexOf("/");        if (lastSlash == -1) {            namespace = "";            name = uri;        } else if (lastSlash == 0) {            // ww-1046, assume it is the root namespace, it will fallback to            // default            // namespace anyway if not found in root namespace.            namespace = "/";            name = uri.substring(lastSlash + 1);        } else if (alwaysSelectFullNamespace) {            // Simply select the namespace as everything before the last slash            namespace = uri.substring(0, lastSlash);            name = uri.substring(lastSlash + 1);        } else {            // Try to find the namespace in those defined, defaulting to ""            Configuration config = configManager.getConfiguration();            String prefix = uri.substring(0, lastSlash);            namespace = "";            boolean rootAvailable = false;            // Find the longest matching namespace, defaulting to the default            //找到对应的namespace(operator/quotetask)            for (PackageConfig cfg : config.getPackageConfigs().values()) {                String ns = cfg.getNamespace();                if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {                    if (ns.length() > namespace.length()) {                        namespace = ns;                    }                }                if ("/".equals(ns)) {                    rootAvailable = true;                }             }              // 找到对应的namspace,并用uri中,去除namespace,用于获取对应的action名字            name = uri.substring(namespace.length() + 1);            // Still none found, use root namespace if found            if (rootAvailable && "".equals(namespace)) {                namespace = "/";            }        }        // 以上两个URL之所以能访问到同一个action, 关键在此处, 通过前面去掉namespace后,最后获得两个actionName为: operator/quotetask/queryByTaskId 与 /queryByTaskId .在以下代码中,直接获取最后一个"/"后的串,则都获得queryByTaskId.并找到对应的ActionMapping        if (!allowSlashesInActionNames) {            int pos = name.lastIndexOf('/');            if (pos > -1 && pos < name.length() - 1) {                name = name.substring(pos + 1);            }        }        mapping.setNamespace(namespace);        mapping.setName(cleanupActionName(name));    }

总结: 在struts中,对与URL的处理,是直接忽略了namespace 与 actionName之间的字符串的。无论是 operator/quotetask/queryByTaskId, operator/quotetask/operator/quotetask/queryByTaskId, 还是operator/quotetask/operator/quotetask/operator/quotetask/queryByTaskId最后获取到的actionMapping都是 namespace: operator/quotetask, actionName: queryByTaskId

0 0
原创粉丝点击