当Web容器收到要求(HttpServletRequest)它将要求通报给一个标准的的过滤链包括(ActionContextCleanUp)过滤器。

经由Other filters(SiteMesh ,etc),须要调用FilterDispatcher核心掌握器,然后它调用ActionMapper确定要求哪个Action,ActionMapper返回一个网络Action详细信息的ActionMaping工具。

FilterDispatcher将掌握权委派给ActionProxy,ActionProxy调用配置管理器(ConfigurationManager) 从配置文件中读取配置信息(struts.xml),然后创建ActionInvocation工具。

jsp两数相减struts2道理及设置装备摆设详解 Bootstrap

ActionInvocation在调用Action之前会依次的调用所用配置拦截器(Interceptor N)一旦实行结果返回结果字符串ActionInvocation卖力查找结果字符串对应的(Result)然后实行这个Result Result会调用一些模版(JSP)来呈现页面。

拦截器(Interceptor N)会再被实行(顺序和Action实行之前相反)末了相应(HttpServletResponse)被返回在web.xml中配置的那些过滤器和核心掌握器(FilterDispatcher)

Struts2框架的内部实行过程

上面讲了MVC中个文件的实行过程,那只是一小部分,现在来看一下全体struts2框架的实行机制,下面的图来源于官网,然后加了自己的改动。

由上图看出,全体框架的运行又牢牢环绕着核心过滤器StrutsPrepareAndExecuteFilter展开事情。
深入到filter的源码中会对理解有所帮助。
下面几篇博客对filter的先容很好。

3,默认拦截器

struts-default.xml配置文件中定义了一个默认拦截器栈,这些拦截器便是动作方法实行之前的要实行的。
常用的有封装用户表单数据到javabean的modelDriven拦截器,用于输入验证的validation拦截器,等等。

4,View和Controller之间的交互

从视图页面每次发来的用户要求都会产生一些数据,这些数据都存放在哪儿呢?实际上,每次动作类实行前,核心过滤器StrutsPrepareAndExecuteFilter都会创建2个工具:ActionContext和ValueStack,这2个工具存储了动作访问期间用到的所有数据。
这些数据又可以在jsp页面上通过strut标签和OGNL表达式来取得。

(1),ActionContext是一个map数据构造,个中的key是一些常见的域工具(application,session,request等),而value又是一个map。
也便是说ActionContext是一个大map包裹着一些小map。

(2),ValueStack是一个ArrayList数据构造,并且是一个栈构造,每次都在栈顶存取数据。

5,Controller与Model之间的交互

C和M之间的交互比较大略,利用Struts框架供应的拦截器:ModelDriven,即可实现将用户表单提交的数据封装到对应的javabean中。
要点:(1)javabean类自己编写。
(2)动作类要实现ModelDriven接口。
(3)实现抽象方法getModel()。

strut2源码剖析:

首先我们利用struts2框架都会在web.xml中注册和映射struts2,配置内容如下:

1 <filter> 2 <filter-name>struts2</filter-name> 3 <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 4 </filter> 5 <filter-mapping> 6 <filter-name>struts2</filter-name> 7 <url-pattern>/</url-pattern> 8 </filter-mapping>

注:在早期的struts2中,都是利用FilterDispathcer,从Struts 2.1.3开始,它已不推举利用。
如果你利用的Struts的版本 >= 2.1.3,推举升级到新的Filter,StrutsPrepareAndExecuteFilter。
在此研究的是StrutsPrepareAndExecuteFilter。

  StrutsPrepareAndExecuteFilter中的方法:

void init(FilterConfig filterConfig) 继续自Filter,过滤器的初始化doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 继续自Filter,实行过滤器void destroy()继续自Filter,用于资源开释void postInit(Dispatcher dispatcher, FilterConfig filterConfig) Callback for post initialization(一个空的方法,用于方法回调初始化)

web容器一启动,就会初始化核心过滤器StrutsPrepareAndExecuteFilter,并实行初始化方法,初始化方法如下:

1 public void init(FilterConfig filterConfig) throws ServletException { 2 InitOperations init = new InitOperations(); 3 Dispatcher dispatcher = null; 4 try { 5 //封装filterConfig,个中有个紧张方法getInitParameterNames将参数名字以String格式存储在List中 6 FilterHostConfig config = new FilterHostConfig(filterConfig); 7 //初始化struts内部日志 8 init.initLogging(config); 9 //创建dispatcher ,并初始化10 dispatcher = init.initDispatcher(config);11 init.initStaticContentLoader(config, dispatcher);12 //初始化类属性:prepare 、execute13 prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);14 execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);15 this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);16 //回调空的postInit方法17 postInit(dispatcher, filterConfig);18 } finally {19 if (dispatcher != null) {20 dispatcher.cleanUpAfterInit();21 }22 init.cleanup();23 }24 }

关于封装filterConfig,首先看下FilterHostConfig ,源码如下:

1 public class FilterHostConfig implements HostConfig { 2 3 private FilterConfig config; 4 //布局方法 5 public FilterHostConfig(FilterConfig config) { 6 this.config = config; 7 } 8 //根据init-param配置的param-name获取param-value的值 9 public String getInitParameter(String key) {10 return config.getInitParameter(key);11 }12 //返回初始化参数名的迭代器 13 public Iterator<String> getInitParameterNames() {14 return MakeIterator.convert(config.getInitParameterNames());15 }16 //返回Servlet高下文17 public ServletContext getServletContext() {18 return config.getServletContext();19 }20 }  只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有列举类型转为Iterator。
此类的紧张作为是对filterConfig 封装。

一个Action内包含多个要求处理方法的处理

Struts1供应了DispatchAction,从而许可一个Action内包含多个要求处理方法。
Struts2也供应了类似的功能。

处理办法紧张有以下三种办法:

1. 1 动态方法调用:

DMI:Dynamic Method Invocation 动态方法调用。

动态方法调用是指:表单元素的action不直接即是某个Action的名字,而因此感叹号后加方法名来指定对应的动作名:

<!-- 动态方法调用HTML标签与Struts2标签 --><form action=\公众computeAction!add.action\"大众 name=\公众from\"大众 ><s:form action=\"大众computeAction!add.action\"大众 name=\公众form\"大众 theme=\"大众simple\"大众 >

则用户的要求将提交到名为”computeAction”的Action实例,Action实例将调用名为”add”方法来处理要求。

当指定调用某一方法来处理要求时,就不会走默认实行处理要求的execute()方法。

把稳:要利用动态方法调用,必须设置Struts2许可动态方法调用,通过设置struts.enable.DynamicMethodInvocation常量来完成,该常量属性的默认值是true。

<struts><!-- //禁用动态方法调用,默认为true启用,false禁用 constant:name=\"大众struts.enable.DynamicMethodInvocation\公众 --><constant name=\"大众struts.enable.DynamicMethodInvocation\公众 value=\公众true\"大众 /></struts>

示列:大略的一个加法和减律例子。

1. index.jsp用户在页面输入两个数字,选择相加,或者相减

当用户点击加或减须要走同一个Action但处理要求方法不同,这里利用了js动态选择。

<body><!-- 动态方法调用 利用:Struts2标签也可以利用HTML标签 --><s: name=\"大众form\公众 theme=\"大众simple\"大众 > num1:<s:textfield name=\"大众num1\"大众 /> num2:<s:textfield name=\公众num2\"大众 /><s:submit type=\公众button\"大众 value=\"大众加\"大众 onclick=\公众computeMethod('add')\"大众 /><s:submit type=\"大众button\公众 value=\"大众减\公众 onclick=\公众computeMethod('subtract')\"大众 /></s:form><!-- js --><script type=\"大众text/javascript\公众>function computeMethod(op){ document.form.action=\公众computeAction!\"大众+op;//动态选择处理要求的方法 document.form.submit();//提交 } </script></body>

2. struts.xml配置信息,启用动态方法调用(可选)

<?xml version=\"大众1.0\"大众 encoding=\公众UTF-8\"大众?><!DOCTYPE struts PUBLIC \公众-//Apache Software Foundation//DTD Struts Configuration 2.1//EN\"大众 \"大众struts-2.1.dtd\"大众 ><struts><!-- //禁用动态方法调用,默认为true启用,false禁用 constant:name=\"大众struts.enable.DynamicMethodInvocation\公众 --><constant name=\公众struts.enable.DynamicMethodInvocation\公众 value=\公众true\"大众 /><package name=\公众struts2\"大众 extends=\公众struts-default\公众><action name=\"大众computeAction\"大众 class=\公众com.struts.ComputeAction\"大众 ><result name=\"大众fruitPage\"大众 >/fruit.jsp</result></action></package></struts>

3. ComputeAction掌握器的类处理要求

package com.struts;/

Struts2掌握器的类 @author asus /public class ComputeAction { / 属性 /private int num1; private int num2; private int fruit;//结果/ 若要求为指定操作方法默认实行execute()方法 /public String execute(){ System.out.println(\"大众当调用其它方法就不会走这个方法!
\公众); return \"大众\公众; } / 实行处理加法 /public String add(){ this.fruit=num1+num2;//加return \"大众fruitPage\"大众; } / 实行处理减法 /public String subtract(){ this.fruit=num1-num2;//减return \公众fruitPage\"大众; } / JavaBean /public int getNum1() { return num1; } public void setNum1(int num1) { this.num1 = num1; } public int getNum2() { return num2; } public void setNum2(int num2) { this.num2 = num2; } public int getFruit() { return fruit; } public void setFruit(int fruit) { this.fruit = fruit; }}

4. fruit.jsp相应结果的页面

<body><!-- 结果页面 --> 打算结果:<s:property value=\"大众fruit\"大众 /></body>

1.2Action配置method属性(示列与以上代码大多同等,只修正有变更的):

将Action类中的每一个处理方法都定义成一个逻辑Action方法。

1. index.jsp页面

<body><!-- Action配置method属性 利用:Struts2标签也可以利用HTML标签 --><s:form name=\"大众form\公众 theme=\"大众simple\"大众 > num1:<s:textfield name=\"大众num1\"大众 /> num2:<s:textfield name=\"大众num2\"大众 /><s:submit type=\公众button\公众 value=\公众加\公众 onclick=\公众computeMethod('addAction')\"大众 /><s:submit type=\"大众button\公众 value=\"大众减\"大众 onclick=\公众computeMethod('subtractAction')\公众 /></s:form><!-- js --><script type=\公众text/javascript\公众>function computeMethod(op){ document.form.action=op;//动态选择处理要求的方法 document.form.submit();//提交 } </script></body>

2. struts.xml配置信息

<?xml version=\"大众1.0\"大众 encoding=\"大众UTF-8\"大众?><!DOCTYPE struts PUBLIC \"大众-//Apache Software Foundation//DTD Struts Configuration 2.1//EN\"大众 \"大众struts-2.1.dtd\公众 ><struts><package name=\"大众struts2\"大众 extends=\"大众struts-default\"大众><action name=\公众addAction\"大众 class=\公众com.struts.ComputeAction\公众 method=\公众add\"大众 ><result name=\"大众fruitPage\公众 >/fruit.jsp</result></action><action name=\"大众subtractAction\"大众 class=\"大众com.struts.ComputeAction\"大众 method=\"大众subtract\"大众 ><result name=\"大众fruitPage\公众 >/fruit.jsp</result></action></package></struts>

  通过action元素的method属性来指定Action实行时调用的方法。

优点:使得以更加安全的办法来实现动态方法的调用,不让别人看到你的实现方法。

缺陷:繁琐,一个处理要求的方法要跟一个action。

  Struts2根据method属性查找方法有两种路子:

  1.查找与method属性值完备同等的方法

  2.查找doMethod形式的方法

  利用动态方法调用和method属性的差异:

    1.通过以上三个struts.xml中的配置信息例子来说,他们的共同点是都在操作同一个Action。

2.<form action=\"大众\"大众>中要求地址不同。

3.动态方法的返回值相同,则会通过result进入一个页面。
而method属性就算两个方法的返回值相同但进去不同的result,可能会进入两个不同的页面。

由上可以剖析出:

(1)如果利用同一个Action,不同的处理要求的方法,相应利用相同的配置(result等)则利用动态方法调用。

(2)如果利用同一个Action,不同的处理要求的方法,相应分别利用不同的配置,则利用action元素的method属性,为同一个Action配置多个名称。