- 浏览: 841826 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
renzhengzhi:
请教一下楼主,公有云和私有云的开发,具体要做哪些工作呢?我拿到 ...
4,云的4 种模式 -
SangBillLee:
我用了solr5.5,用SolrQuery查询,没法高亮,不知 ...
solr5.x快速入门 -
lw900925:
这翻译读起来真是别扭。
solr in action翻译-第一章1.1 -
springjpa_springmvc:
spring mvc demo教程源代码下载,地址:http: ...
Spring MVC性能提升 -
h416373073:
正遇到了此问题不知如何解决, 多谢分享
solr错误
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创建完成。
发表评论
-
struts源码之十
2012-12-16 20:53 1433ActionMapping创建完成,就开始执行exece方法。 ... -
struts源码之八
2012-12-16 15:04 1540创建完成ActionContext后,strtus2将当Dis ... -
struts源码之七
2012-12-16 14:37 1161struts2一个请求的处理过程分析 strtus2的 ... -
Struts2_ValueStack,OGNL详解
2012-12-15 22:24 10035引言: 闲话不多说,最近项目结束,天天泡在CSDN论坛上,不乏 ... -
struts源码之六
2012-12-15 22:05 1065struts2请求核心流程图如下: 粗略的化了一下 ... -
struts源码之五
2012-12-15 20:35 965struts2请求流程一个简图。如下图所示 只画出了前半部分 ... -
struts源码之四
2012-12-14 23:01 1057初始化Dispatcher完成, init.init ... -
struts源码之三
2012-12-14 22:36 1237在init初始化方法中我们看到这样一句 InitOpera ... -
struts源码之二
2012-12-14 22:03 1037struts2初始化静态流程如下: 详细描述 ... -
struts源码之一
2012-12-14 21:59 1366Struts2架构图 Struts2部分类介绍 ... -
Struts2中,radio标签的默认选中问题
2011-10-28 08:59 1068在Struts2中,radio标签可以使用一个list来输 ... -
struts2的itrator循环使用
2011-09-21 11:20 1085下拉框的输出 <s:iterator value=&qu ... -
Struts2通用的Action配置
2010-09-02 17:15 1649<action name="*_*" ... -
struts2的Result配置
2010-08-12 15:38 1265在struts-default.xml <resu ... -
Struts2概述
2010-07-23 15:29 1129Struts2其实并不是一个陌 ...
相关推荐
在Eclipse中关联Struts2.1.8源码,可以帮助开发者更好地理解和调试代码。步骤包括: - 下载Struts2.1.8的源码包。 - 在Eclipse中,右键点击项目,选择"Build Path" -> "Configure Build Path" -> "Libraries" -> ...
struts源码包,解压后会有一个src文件夹,此文件夹下的就是struts的源码。
孙卫琴 struts 源码 孙卫琴 struts 源码 孙卫琴 struts 源码
通过深入研究Struts源码,我们可以了解到框架如何处理请求、执行业务逻辑以及如何将数据呈现给用户。这对于提升Java Web开发技能,理解MVC模式,以及进行性能优化都有着极大的帮助。同时,熟悉源码也有助于开发者更...
最新版的Struts2源码可以从GitHub的Apache官方仓库获取,这为我们提供了深入理解其内部工作原理和定制功能提供了可能。 Struts2的核心特性包括: 1. **Action与结果**:在Struts2中,业务逻辑处理主要由Action类...
9. **Struts2插件**:Struts2允许开发者通过插件扩展框架功能,例如国际化、上传下载等。 通过分析这个Struts2项目源码,你可以学习以下技能: 1. 如何创建Action类,并定义其方法与用户请求对应。 2. 理解配置...
这篇博文“Struts2源码解读”深入剖析了Struts2的核心机制,帮助开发者更好地理解和利用这个框架。源码分析是提升编程技能和解决问题的关键,特别是对于复杂的框架如Struts2,理解其内部工作原理能够帮助我们优化...
深入理解Struts2的源码对于提升Java Web开发技能,尤其是在面试中讨论底层实现时,具有非常重要的价值。 首先,我们来看看Struts2的核心组件和设计理念: 1. **Action**:在Struts2中,Action类是业务逻辑处理的...
Struts2 源码分析 Struts2 是一个基于MVC 模式的Web 应用程序框架,它的源码分析可以帮助我们更好地理解框架的内部机制和工作流程。下面是Struts2 源码分析的相关知识点: 1. Struts2 架构图 Struts2 的架构图...
9. **国际化(Internationalization, i18n)**: Struts2支持多语言环境,通过资源包(Properties文件)实现动态切换不同语言的显示。 10. **生命周期管理**: Struts2中的Action实例默认为多例,但可以通过配置改为...
通过阅读Struts2的源码,我们可以深入了解框架如何处理请求、如何调度Action以及如何应用拦截器来扩展功能。这有助于开发者更好地定制和优化他们的应用程序,提高代码质量和性能。在实际开发中,对源码的理解能帮助...
9. **异常处理**:Struts2提供了全局的异常处理机制,可以统一处理应用中的异常,提高代码的健壮性。 10. **国际化(i18n)**:框架内置对多语言的支持,方便实现国际化应用。 在"day06"这个文件夹中,很可能包含...
这里的"struts-1.3.9 源码"指的是Struts 1.x系列的第9次次要版本的源代码。Struts 1.3.9是在2008年发布的,它提供了许多增强和修复了之前版本中的问题,以提高框架的稳定性和安全性。 首先,我们来看看`LICENSE.txt...
在深入理解Struts2的工作原理时,源码分析是必不可少的步骤。Struts2的核心设计理念和设计模式相比Struts1.x有了显著的变化,这使得它成为一个独立且成熟的框架。 首先,Struts2的架构基于WebWork的核心,这意味着...
通过对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.0工程源码(完整的struts2.0学习工程源码) 这是一个完整的工程源码,包括所用到的jar包和发布配置文件。 导入到eclipse里几个运行,struts2.0入门学习工程,适合struts2.0广大爱好者和初学者学习和交流。
孙卫琴 struts 源码 孙卫琴 struts 源码 孙卫琴 struts 源码 103m
在深入理解Struts 2的源码之前,我们需要先了解其核心概念和组件。 1. **Action类与ActionMapping** Struts 2的核心是Action类,它是业务逻辑处理的中心。每个Action类对应一个用户请求,处理后返回一个Result。...
通过深入学习OGNL的源码,开发者可以更好地定制和优化Struts2应用,提升性能,增强安全性,并能解决遇到的特定问题。这是一项值得投入时间和精力的任务,特别是对于那些希望在Web开发领域有深入理解的人来说。