`
韩悠悠
  • 浏览: 839745 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

struts源码之九

 
阅读更多

strtsu2完成request的封装后,就创建ActionMapping

ActionMapping的创建过程也很明了。

 

ActionMapping mapping = prepare.findActionMapping(request, response, true);

 

首先,去 request中寻找是否有,如果有则返回,否则创建一个。

 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, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
            }
        }

        return mapping;
    }

 

 

注意关键的地方是通过Dispatcher取得容器Container创建,传入的参数是request和ConfigurationManager

 

dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());

 

request不必多说,ConfigurationManager在初始化的时候也说了,是配置文件的管理类,包括了各种provider

 

默认的实现是DefaultActionMapper

 

 public ActionMapping getMapping(HttpServletRequest request,
                                    ConfigurationManager configManager) {
        ActionMapping mapping = new ActionMapping();
        String uri = getUri(request);

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

        uri = dropExtension(uri, mapping);
        if (uri == null) {
            return null;
        }

        parseNameAndNamespace(uri, mapping, configManager);

        handleSpecialParameters(request, mapping);

        if (mapping.getName() == null) {
            return null;
        }

        parseActionName(mapping);

        return mapping;
    }

 

 在进一步了解之前,我们先看看ActionMapping。

 

public class ActionMapping {

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

 

 

ActionMapping是一个实体类,对应的就是一个action所包含的元素,比如名称,民名空间,方法,参数,返回值以及可能的扩展。

 

返回ActionMapping的创建,首先是初始化了一个空的ActionMapping。

然后取得当前请求的URI

 

ActionMapping mapping = new ActionMapping();
        String uri = getUri(request);

 

 

从request中取得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());
    }

 

然后从uri中去掉action请求的后缀。

比如xxx.xxx.do,则去掉.do

protected String dropExtension(String name, ActionMapping mapping) {
        if (extensions == null) {
            return name;
        }
        for (String ext : extensions) {
            if ("".equals(ext)) {
                // This should also handle cases such as /foo/bar-1.0/description. It is tricky to
                // distinquish /foo/bar-1.0 but perhaps adding a numeric check in the future could
                // work
                int index = name.lastIndexOf('.');
                if (index == -1 || name.indexOf('/', index) >= 0) {
                    return name;
                }
            } else {
                String extension = "." + ext;
                if (name.endsWith(extension)) {
                    name = name.substring(0, name.length() - extension.length());
                    mapping.setExtension(ext);
                    return name;
                }
            }
        }
        return null;
    }

 然后从uri中分析action请求中的name和namespace

 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
            for (Object cfg : config.getPackageConfigs().values()) {
                String ns = ((PackageConfig) 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;
                }
            }

            name = uri.substring(namespace.length() + 1);

            // Still none found, use root namespace if found
            if (rootAvailable && "".equals(namespace)) {
                namespace = "/";
            }
        }

        if (!allowSlashesInActionNames && name != null) {
            int pos = name.lastIndexOf('/');
            if (pos > -1 && pos < name.length() - 1) {
                name = name.substring(pos + 1);
            }
        }

        mapping.setNamespace(namespace);
        mapping.setName(name);
    }

 

分析的过程也很简单,分析完成后放入mapping中。需要注意的是在分析的过程中读取配置文件,通过Configuration完成的。

  Configuration config = configManager.getConfiguration();
            String prefix = uri.substring(0, lastSlash);
            namespace = "";
            boolean rootAvailable = false;
            // Find the longest matching namespace, defaulting to the default
            for (Object cfg : config.getPackageConfigs().values()) {
                String ns = ((PackageConfig) 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;
                }
            }

 

处理完成,然后处理特殊参数

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;
                }
            }
        }
    }

 

需要注意这个类PrefixTrie,用来匹配前缀的对象

在DefaultActionMapper初始化的时候创建

 

 

 public DefaultActionMapper() {
        prefixTrie = new PrefixTrie() {
            {
                put(METHOD_PREFIX, new ParameterAction() {
                    public void execute(String key, ActionMapping mapping) {
                        if (allowDynamicMethodCalls) {
                            mapping.setMethod(key.substring(
                                    METHOD_PREFIX.length()));
                        }
                    }
                });

                put(ACTION_PREFIX, new ParameterAction() {
                    public void execute(String key, ActionMapping mapping) {
                        String name = key.substring(ACTION_PREFIX.length());
                        if (allowDynamicMethodCalls) {
                            int bang = name.indexOf('!');
                            if (bang != -1) {
                                String method = name.substring(bang + 1);
                                mapping.setMethod(method);
                                name = name.substring(0, bang);
                            }
                        }
                        mapping.setName(name);
                    }
                });

                put(REDIRECT_PREFIX, new ParameterAction() {
                    public void execute(String key, ActionMapping mapping) {
                        ServletRedirectResult redirect = new ServletRedirectResult();
                        container.inject(redirect);
                        redirect.setLocation(key.substring(REDIRECT_PREFIX
                                .length()));
                        mapping.setResult(redirect);
                    }
                });

                put(REDIRECT_ACTION_PREFIX, new ParameterAction() {
                    public void execute(String key, ActionMapping mapping) {
                        String location = key.substring(REDIRECT_ACTION_PREFIX
                                .length());
                        ServletRedirectResult redirect = new ServletRedirectResult();
                        container.inject(redirect);
                        String extension = getDefaultExtension();
                        if (extension != null && extension.length() > 0) {
                            location += "." + extension;
                        }
                        redirect.setLocation(location);
                        mapping.setResult(redirect);
                    }
                });
            }
        };
    }

 然后在handleSpecialParameters才有了处理

 

 

  ParameterAction parameterAction = (ParameterAction) prefixTrie
                        .get(key);
                if (parameterAction != null) {
                    parameterAction.execute(key, mapping);
                    uniqueParameters.add(key);
                    break;
                }

 

处理的是预先添加的,代码如下:

protected static final String METHOD_PREFIX = "method:";

    protected static final String ACTION_PREFIX = "action:";

    protected static final String REDIRECT_PREFIX = "redirect:";

    protected static final String REDIRECT_ACTION_PREFIX = "redirectAction:";

 

注意这里使用的回调函数。

 parameterAction.execute(key, mapping);

 

具体的实现则在初始化中的实现

 public void execute(String key, ActionMapping mapping) {
                        String location = key.substring(REDIRECT_ACTION_PREFIX
                                .length());
                        ServletRedirectResult redirect = new ServletRedirectResult();
                        container.inject(redirect);
                        String extension = getDefaultExtension();
                        if (extension != null && extension.length() > 0) {
                            location += "." + extension;
                        }
                        redirect.setLocation(location);
                        mapping.setResult(redirect);
                    }

 

这样就给mapping设置了。

 

就拿这个例子来说把,创建了ServletRedirectResult

然后放入mapping中,在后续的执行中会使用,我们可以进入ServletRedirectResult 看看这个类,

有一个核心方法doExecute。

在我们调用action返回的时候会调用到这里doExecute。

这里暂时不做详细介绍,

代码如下:

 protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
        ActionContext ctx = invocation.getInvocationContext();
        HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE);

        if (isPathUrl(finalLocation)) {
            if (!finalLocation.startsWith("/")) {
                ActionMapping mapping = actionMapper.getMapping(request, Dispatcher.getInstance().getConfigurationManager());
                String namespace = null;
                if (mapping != null) {
                    namespace = mapping.getNamespace();
                }

                if ((namespace != null) && (namespace.length() > 0) && (!"/".equals(namespace))) {
                    finalLocation = namespace + "/" + finalLocation;
                } else {
                    finalLocation = "/" + finalLocation;
                }
            }

            // if the URL's are relative to the servlet context, append the servlet context path
            if (prependServletContext && (request.getContextPath() != null) && (request.getContextPath().length() > 0)) {
                finalLocation = request.getContextPath() + finalLocation;
            }

            ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(invocation.getResultCode());
            if (resultConfig != null) {
                Map<String, String> resultConfigParams = resultConfig.getParams();

                for (Map.Entry<String, String> e : resultConfigParams.entrySet()) {
                    if (!getProhibitedResultParams().contains(e.getKey())) {
                        String potentialValue = e.getValue() == null ? "" : conditionalParse(e.getValue(), invocation);
                        if (!suppressEmptyParameters || ((potentialValue != null) && (potentialValue.length() > 0))) {
                            requestParameters.put(e.getKey(), potentialValue);
                        }
                    }
                }
            }

            StringBuilder tmpLocation = new StringBuilder(finalLocation);
            urlHelper.buildParametersString(requestParameters, tmpLocation, "&");

            // add the anchor
            if (anchor != null) {
                tmpLocation.append('#').append(anchor);
            }

            finalLocation = response.encodeRedirectURL(tmpLocation.toString());
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Redirecting to finalLocation " + finalLocation);
        }

        sendRedirect(response, finalLocation);
    }

 

回到我们的 DefaultActionMapper中,完成了上面的处理,进入parseActionName

分析action的名称。

 parseActionName(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));

                mapping.setMethod(name.substring(exclamation + 1));
            }
        }
        return mapping;
    }

 

如果为空则之间返回,否则处理类似name!method这样的请求 action

处理完成返回.ActionMapping

actionMapping处理完成后放入request中。

if (mapping != null) {
                    request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
                }

 

至此,ActionMapping创建完成。

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    struts2.1.8 struts2源码 Eclipse关联这个可以

    在Eclipse中关联Struts2.1.8源码,可以帮助开发者更好地理解和调试代码。步骤包括: - 下载Struts2.1.8的源码包。 - 在Eclipse中,右键点击项目,选择"Build Path" -&gt; "Configure Build Path" -&gt; "Libraries" -&gt; ...

    struts框架的源码包

    struts源码包,解压后会有一个src文件夹,此文件夹下的就是struts的源码。

    孙卫琴struts源码.part1.rar

    孙卫琴 struts 源码 孙卫琴 struts 源码 孙卫琴 struts 源码

    struts源码struts源码struts源码

    通过深入研究Struts源码,我们可以了解到框架如何处理请求、执行业务逻辑以及如何将数据呈现给用户。这对于提升Java Web开发技能,理解MVC模式,以及进行性能优化都有着极大的帮助。同时,熟悉源码也有助于开发者更...

    struts2源码最新

    最新版的Struts2源码可以从GitHub的Apache官方仓库获取,这为我们提供了深入理解其内部工作原理和定制功能提供了可能。 Struts2的核心特性包括: 1. **Action与结果**:在Struts2中,业务逻辑处理主要由Action类...

    struts2 项目源码

    9. **Struts2插件**:Struts2允许开发者通过插件扩展框架功能,例如国际化、上传下载等。 通过分析这个Struts2项目源码,你可以学习以下技能: 1. 如何创建Action类,并定义其方法与用户请求对应。 2. 理解配置...

    struts2 源码解读

    这篇博文“Struts2源码解读”深入剖析了Struts2的核心机制,帮助开发者更好地理解和利用这个框架。源码分析是提升编程技能和解决问题的关键,特别是对于复杂的框架如Struts2,理解其内部工作原理能够帮助我们优化...

    struts2框架源码

    深入理解Struts2的源码对于提升Java Web开发技能,尤其是在面试中讨论底层实现时,具有非常重要的价值。 首先,我们来看看Struts2的核心组件和设计理念: 1. **Action**:在Struts2中,Action类是业务逻辑处理的...

    struts2 源码分析

    Struts2 源码分析 Struts2 是一个基于MVC 模式的Web 应用程序框架,它的源码分析可以帮助我们更好地理解框架的内部机制和工作流程。下面是Struts2 源码分析的相关知识点: 1. Struts2 架构图 Struts2 的架构图...

    struts2 源码

    9. **国际化(Internationalization, i18n)**: Struts2支持多语言环境,通过资源包(Properties文件)实现动态切换不同语言的显示。 10. **生命周期管理**: Struts2中的Action实例默认为多例,但可以通过配置改为...

    Struts2源码阅读

    通过阅读Struts2的源码,我们可以深入了解框架如何处理请求、如何调度Action以及如何应用拦截器来扩展功能。这有助于开发者更好地定制和优化他们的应用程序,提高代码质量和性能。在实际开发中,对源码的理解能帮助...

    struts2学习 源码

    9. **异常处理**:Struts2提供了全局的异常处理机制,可以统一处理应用中的异常,提高代码的健壮性。 10. **国际化(i18n)**:框架内置对多语言的支持,方便实现国际化应用。 在"day06"这个文件夹中,很可能包含...

    struts-1.3.9 源码

    这里的"struts-1.3.9 源码"指的是Struts 1.x系列的第9次次要版本的源代码。Struts 1.3.9是在2008年发布的,它提供了许多增强和修复了之前版本中的问题,以提高框架的稳定性和安全性。 首先,我们来看看`LICENSE.txt...

    Struts2源码分析

    在深入理解Struts2的工作原理时,源码分析是必不可少的步骤。Struts2的核心设计理念和设计模式相比Struts1.x有了显著的变化,这使得它成为一个独立且成熟的框架。 首先,Struts2的架构基于WebWork的核心,这意味着...

    struts-1.2.9源码

    通过对Struts 1.2.9源码的深入学习,开发者可以了解Web应用的典型开发流程,掌握如何有效地组织和管理复杂的业务逻辑,以及如何优雅地处理用户交互。虽然Struts 1已逐渐被Struts 2和Spring MVC等更新框架替代,但它...

    STRUTS2源码解析

    STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析...

    struts2.0工程源码(完整的struts2.0学习工程源码)

    struts2.0工程源码(完整的struts2.0学习工程源码) 这是一个完整的工程源码,包括所用到的jar包和发布配置文件。 导入到eclipse里几个运行,struts2.0入门学习工程,适合struts2.0广大爱好者和初学者学习和交流。

    孙卫琴struts源码.part3.rar

    孙卫琴 struts 源码 孙卫琴 struts 源码 孙卫琴 struts 源码 103m

    Struts 2的源码

    在深入理解Struts 2的源码之前,我们需要先了解其核心概念和组件。 1. **Action类与ActionMapping** Struts 2的核心是Action类,它是业务逻辑处理的中心。每个Action类对应一个用户请求,处理后返回一个Result。...

    struts2中的OGNL的源码

    通过深入学习OGNL的源码,开发者可以更好地定制和优化Struts2应用,提升性能,增强安全性,并能解决遇到的特定问题。这是一项值得投入时间和精力的任务,特别是对于那些希望在Web开发领域有深入理解的人来说。

Global site tag (gtag.js) - Google Analytics