struts2中如何根据请求路径定位到详细的访问action

在struts2中在访问一个菜单链接时,我们只需要将相应的package 命名空间和 action的name进行组合,并加上相应的后缀,就可以直接访问到相应的Action了,那么这个过程是如何进行的,多个相同命名空间的 package是如何满足互不冲突的呢,这就需要详细了解struts2中是如何解析路径信息,并根据访问路径寻找相应的action配置了。

整个过程我们可以分成以下几个步骤进行处理

  1. 解析xml,将所有可以访问到的路径信息进行保存
  2. 根据访问请求信息,取其中可用的路径
  3. 根据路径进行查找,最终查找到我们所需要的Action

解析XML

首先我们知道一个package以及action的配置如下所示:


1

2

3

4

5


<package name="packageName" extends="struts-default" namespace="/">

<action name="logic" class="detailAction" method="init">

<result name="success">/jsp/success.jsp</result>

</action>

</package>

即主要包括包名,命名空间以及action的名称。那么我们就可以将这一系列的信息通过一个类似PackageConfig的对象进行组织起来。这就是struts2里面所使用的packageConfig。我们来看它的简单定义:


1

2

3

4


protected Map<String, ActionConfig> actionConfigs;

......

protected String name;

protected String namespace = "";

其中就包括了我们所知道的包名,命名空间,以及使用action名称和每个action配置的一个map。那么,整个工程中有许多的package,struts如何进行处理呢,那就需要用到这里面的命名空间了。

我们可以把命名空间作为key,然后把每个package里面的所有action配置都作为value进行保存起来,那么使用key表示命名空间,action配置作为value,其中将action的配置再一次map化,使用以下数据结构来进行定义存储。


1


Map<String, Map<String, ActionConfig>> namespaceActionConfigs = new LinkedHashMap<String, Map<String, ActionConfig>>();

双map化,第一个key表示命名空间,第二个key表示action的名称即路径,最终的value即每个action的相应信息,这样针对以下的一个路径:


1


/contextPath/模块名/功能名/action名/操作.action

我们只需要将上下文和后面的.action除去,剩下的 /模块名/功能名/action名/操作,实际上就是一个命名空间和action路径的一个组合。我们只需要按照/分隔符挨个到map中查找即可。如果存 在 以模块名为命名空间的package信息,我们就可以直接定义到第二个map,然后 直接使用key 功能名/action名/操作进行直接匹配到相应的action即可以了。

那么整个数据结构的构建过程即在类DefaultConfiguration的方法buildRuntimeConfiguration中,如下所示:


01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24


Map<String, Map<String, ActionConfig>> namespaceActionConfigs = new LinkedHashMap<String, Map<String, ActionConfig>>();

Map<String, String> namespaceConfigs = new LinkedHashMap<String, String>();

//这里即按每个package进行循环,依次放入map中

for (PackageConfig packageConfig : packageContexts.values()) {

String namespace = packageConfig.getNamespace();

Map<String, ActionConfig> configs = namespaceActionConfigs.get(namespace);

Map<String, ActionConfig> actionConfigs = packageConfig.getAllActionConfigs();

for (Object o : actionConfigs.keySet()) {

String actionName = (String) o;

//这里先取得原先放在大map中的集合信息

ActionConfig baseConfig = actionConfigs.get(actionName);

//这里即是将当前package中的action配置再根据命名空间合并到大的map中

configs.put(actionName, buildFullActionConfig(packageConfig, baseConfig));

}

namespaceActionConfigs.put(namespace, configs);

}

}

return new RuntimeConfigurationImpl(namespaceActionConfigs, namespaceConfigs);

解析Action信息

接下来就是查找Action的过程了,当一个请求到来时,struts2首先要得知哪个action能够处理这个请求,如果没有可以处理的请求,则进行报 错或者其它提示。首先,我们知道,这个查找过程必须先去掉上下文之前的所有信息,其次再去掉后缀,只留下中间与命名空间和action名称组合的字符串, 然后再进行查找。这个过程的描述即在类DefaultActionMapper的方法getMapping中进行的,如下所示:


01

02

03

04

05

06

07

08

09

10


ActionMapping mapping = new ActionMapping();

//这一步去头和上下文

String uri = getUri(request);

//这一步去分号和后面的所有信息

int indexOfSemicolon = uri.indexOf(";");

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

//这一步去后续及后面的所有信息,如.action

uri = dropExtension(uri, mapping);

//这一步为真正的查找过程

parseNameAndNamespace(uri, mapping, configManager);

查找的具体过程与整个路径的组织有关,整个实现可以由以下步骤确定。

  1. 按/进行倒序查找,如果没有,则认为命名空间为"",整个路径即是action名称
  2. 如果在第1位,即以/开头,则认为命名空间为/,后面的即是action名称
  3. 否则配置了全命名空间搜索,即贪心搜索,即认为所有/之前的都是命名空间,后面即是action名称
  4. 否则将所有的在第一步组织的map中进行最长度化匹配,即匹配到的最长的那个命名空间即是我们所要的,后面的则是action名称
  5. 最后,如果配置了action路径中不存在/,则将整个action路径中/之间的去掉,最后的不包括/的即是action名称

以上的步骤中,1,2,3,4都是查找过程,最后的第5步为处理过程。整个的实现逻辑即与上述的一致,如下所示:


01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44


String namespace, name;

int lastSlash = uri.lastIndexOf("/");

//这里即是第1步,即在没有上下文时,整个路径 就没有/

if (lastSlash == -1) {

namespace = "";

name = uri;

//第2步,即存在命名空间为/时,或者为""时,这时/即在第1位

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

//第3步,如果贪心搜索,则最长的路径即为命名空间

} else if (alwaysSelectFullNamespace) {

// Simply select the namespace as everything before the last slash

namespace = uri.substring(0, lastSlash);

name = uri.substring(lastSlash + 1);

//第4步,最长化匹配搜索

} else {

// Try to find the namespace in those defined, defaulting to ""

Configuration config = configManager.getConfiguration();

String prefix = uri.substring(0, lastSlash);

namespace = "";

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

}

}

}

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

}

//这是第5步,针对action名称处理

if (!allowSlashesInActionNames && name != null) {

int pos = name.lastIndexOf(‘/‘);

if (pos > -1 && pos < name.length() - 1) {

name = name.substring(pos + 1);

}

}

这样即完成了查找过程,但这里仅是一个查找,并不是一个最终匹配,因为还存在着根据这个查找到的匹配结果如何映射到最终action对象的过程,即映射到actionConfig上。

映射actionConfig

整个映射过程可以分成以下几个步骤进行

  1. 首先,根据默认的匹配进行查找,如果能够查找到,就认为是最终的actionConfig,在其中也会对action名称进行模式匹配
  2. 否则对命名空间进行*号匹配,尝试进行模式匹配
  3. 最后则尝试使用默认的空命名空间进行查找

1    其实就是首先根据命名空间查找相应的子map,即actionName和actionConfig的集合,然后再在子map中查找,如果子map中查不到,则使用模式匹配。再找不到就进入到步骤2了。
2    在步骤2时,首先也会使用模式匹配查找到对应的命名空间,如果有可匹配的命名空间,就使用该命名空间再次重复第一步操作
3    还没找到,就使用默认的命名空间即""进行查找

整个实现在类DefaultActionMapper的getActionConfig方法中,如下所示:


01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26


//使用第一步操作进行匹配

ActionConfig config = findActionConfigInNamespace(namespace, name);

//使用第二步操作进行命名空间的模式匹配

// try wildcarded namespaces

if (config == null) {

NamespaceMatch match = namespaceMatcher.match(namespace);

if (match != null) {

config = findActionConfigInNamespace(match.getPattern(), name);

// If config found, place all the matches found in the namespace processing in the action‘s parameters

if (config != null) {

config = new ActionConfig.Builder(config)

.addParams(match.getVariables())

.build();

}

}

}

//使用第3步的默认匹配

// fail over to empty namespace

if ((config == null) && (namespace != null) && (!"".equals(namespace.trim()))) {

config = findActionConfigInNamespace("", name);

}

return config;

至此,整个定位过程结束。如果此处仍找不到actionConfig对象,那么就直接抛出相应的异常了,即常见的

There is no Action mapped for namespace {0} and action name {1}.
There is no Action mapped for action name {0}.

转载请标明出处:i flym
本文地址:http://www.iflym.com/index.php/code/201302270001.html

时间: 2024-11-16 16:39:14

struts2中如何根据请求路径定位到详细的访问action的相关文章

Struts2中的链接标签 &lt;s:url&gt;和&lt;s:a&gt;---在action中获取jsp表单提交的参数(转)

转自:http://sgl124764903.iteye.com/blog/444183 1.普通链接 Web程序中最普通的应用是链接到其他页面,下面看Welcome.jsp. <%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head>    

struts2中的重定向 请求里的多例和单例 springmvc struts2

dispatcher:默认的是dispatcher就是转发,携带处理后的数据到指定的jsp资源. redirect:重定向,会失去所有的请求参数.请求属性和action处理后的结果. redirection:与redirect相似,也是重新生成一个全新的请求.当需要让一个action处理结束后直接请求重定向到另一个action时使用. 注意:redirect 与redirection区别 struts2的项目里遇到一个问题,业务是这样的:修改一个post的信息,结束后使用type为redirec

Struts2中使用Velocity模板时模板资源路径配置问题

在Struts2中使用Velocity模板时,如何以相对与Web工程的路径来配置模板资源文件路径这个问题网上千篇一律的来自Velocity官方文档.官方文档中指出如果是Web工程的话,模板的相对路径是工程根路径,今天在使用的时候有如下配置: Velocity.properties(默认在WEB-INF下): resource.loader =file, classclass.resource.loader.description = Velocity Classpath Resource Loa

struts2中action手动获取參数

struts2中action手动获取Session,jsp页面參数 1. ActionContext 在Struts2开发中,除了将请求參数自己主动设置到Action的字段中,我们往往也须要在Action里直接获取请求(Request)或会话(Session)的一些信息, 甚至须要直接对JavaServlet Http的请求(HttpServletRequest),响应(HttpServletResponse)操作. 我们须要在Action中取得request请求參数"username"

项目访问路径+发送请求路径写法的相关问题

1.js中发生ajax请求路径写法 queryUrl = 'http://localhost:8080/spc/findMemberRight.do'; 规则为:ip+端口+controller的url 如果设置了代理的则为:ip+端口+代理(一般为模块名)+controller的url 2.浏览器直接访问webapp下的html 1.首先需要把webapp目录加入编译路径,IDEA设置webapp为编译路径方法如下: 2.然后访问路径变为 http://localhost:8080/right

struts2中&lt;s:property&gt;的用法

1,访问Action值栈中的普通属性: <s:property value="attrName"/> 2,访问Action值栈中的对象属性(要有get set方法): <s:property value="obj.attrName"/> <s:property value="obj1.obj2.attrName"/> 3,访问值栈中对象属性的方法 <s:property value="obj.m

Struts2中的路径问题总结

Struts2中路径问题是一个棘手的问题,初学时经常被路径问题搞得很烦,通过网上查找资料和自己实战中遇到的问题今天来对Struts2中的路径问题来一个总结,当然可能不会很完整,不过后续会进行补充: 1.  Struts2 一个要匹配路径的地方就是在处理完请求之后对页面进行分发的时候,也就是 result 元素里面的内容. 假设项目名为Struts2 在地址栏中访问action时URL基本是以 http://localhost:8080/Struts 开头 比如<action name="h

验证struts2中action的查找路径

以前看网上struts2的视频讲解时,其中讲解到action的查找路径时,该讲师说action的查找是依次向上一级查找的,例如有一个请求为/a/b/UerAction.action时,首先会到/a/b的命名空间里查找UserAction的Action,如果找不到就到/a的命名空间里查找UserAction的Action,如果还没有找到,以此类推,直到找到默认的命名空间,如果还没有找到,程序就会抛异常.可是近来我看见一本书中却是这样讲解的,还是这个请求/a/b/UerAction.action,首

web中的CSS、Xpath等路径定位方法学习

今天不到八点就到公司了,来的比较早,趁着有点时间,总结下web中的CSS.Xpath等路径定位定位的方式吧! 简单的介绍下xpath和css的定位 理论知识就不罗列了 还是利用博客园的首页.直接附上代码: 这个是xpath 1 #!/usr/bin/env python 2 # -*- coding: utf_8 -*- 3 4 from learn_webdriver import Webdriver 5 from selenium import webdriver 6 from seleni