- 浏览: 120844 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
bwhzhl:
完全忽悠人
你拿1.44的SVN配置 看到的版本的是
Po ...
(转)Apache2.2和SVN1.4.4搭建svn版本控制平台windows版 -
protti:
你没有说清楚codebehind的原理
其实在以前没有cod ...
struts2 code-behind -
fengzi1:
对天乙社区bbscs8实现的详细分析三 -
leibin2009:
一个字"好". 现在公司正在用这个框架,太 ...
WebWork教程二 -
jason34:
太爽了交个朋友可以吗??
QQ10046417
MSN:kso ...
对天乙社区bbscs8实现的详细分析一(附文档下载)
Action的单元测试
理解了ServletDispatcher,我们就明白了整个框架调用执行的顺序。Action虽然是与Web无关,可是它的创建、参数设置、执行与我们的WebWork、XWork紧密关联在一起,有我们的控制器ServletDispatcher去统一调度,那我们如何去对Action进行独立的单元测试呢?
请看下面的例子:使用单元测试框架JUnit对register.User. RegisterAction做单元测试
见example.register. RegisterActionTest类testExecuteWithProxyFactory()方法:
代码 |
public void testExecuteWithProxyFactory() throws Exception{ Map params = new HashMap(); params.put("user.username","Moxie"); params.put("user.password","mypassword"); params.put("user.email","achqian@yahoo.com.cn"); params.put("user.age",new Integer(23)); Map extraContext = new HashMap(); extraContext.put(ActionContext.PARAMETERS,params); ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy("example", "register", extraContext); proxy.setExecuteResult(false); assertEquals(proxy.execute(),"success"); RegisterAction action = (RegisterAction) proxy.getAction(); assertEquals(action.getUser().getUsername(),"Moxie"); assertEquals(action.getUser().getAge(),23); } |
下面解说这个方法:
1、 对象params表示请求参数的Map,在它里面设置了注册用户的信息。extraContext当然就是我们ActionContext上下文的容器,它里面保存了放置请求参数的对象params
2、 创建我们的ActionProxy,它传入的参数有:“example”-这个Action的命名空间,“register”-Action对应的名字,extraContext-存放Actin上下文里的对象,,执行并将它返回的值与“success”比较,测试Action是否能正确执行完成。注意:proxy.setExecuteResult(false);,因为我们是单元测试,所以Action执行完成就可以了,不用再去调用结果响应的操作,故将是否执行结果设置为“false”。
3、 Action正确执行完成之后,我们也可以测试现在Action的字段里的数据是否按照我们预期的要求正确设置。从ActionProxy对象里取得执行的Action,即RegisterAction对象,再取得它的User模型,将其数据与前面设置参数的数据进行比较,判断它是否等于我们预期设置的数值。
Result Type
前面我们学习了ServletDispatcher,它是WebWork框架机制的核心。它和Action在我们MVC模式中,扮演着控制器的角色,MVC模式通过控制器实现了我们模型和视图的分离。WebWork提供了多种活灵活视图展现方式。
我们先看看前面用户注册例子的展现方式:我们使用的是Jsp和WebWork自带的标签库,Action对应的视图当然是在xwork.xml配置文件里设置:
代码 |
<action name="register" class="example.register.RegisterAction" > <result name="success" type="dispatcher"> <param name="location">register-result.jsp</param> </result> <interceptor-ref name="params"/> </action> |
Result是Action执行完返回的一个字符串常量,它表示Action执行完成的状态,比如:执行成功、执行失败等。在我们前面Action的介绍中,详细介绍了它默认的标准Result,当然Result我们也可以自己定义,只要是一个字符串常量就可以了。
Result的值在xwork.xml配置文件里就是result标签里“name”的值,name="success"表示Action执行成功,返回“success”就对应此标签的配置,进行视图输出。
“type”就是我们的Result Type,Result Type是一个类,它在Action执行完成并返回Result之后,决定采用哪一种视图技术,将执行结果展现给用户。我们输出的类型是:type="dispatcher",它对应com.opensymphony.webwork.dispatcher.ServletDispatcherResult这个类,它将执行结果通过javax.servlet.RequestDispatcher的forward()或include()方法调度到Jsp页面展现。
我们可以自己开发Result Type,实现我们需要的视图展现方式。Result Type必需要实现com.opensymphony.xwork..Result接口。在WebWork中,它已经为我们提供了很多Result Type,实现了视图部分对JSP, Velocity, FreeMarker, JasperReports,XML等的支持,具体如下表格:
Result Type
Nname
Class
Dispatcher
dispatcher
com.opensymphony.webwork.dispatcher.ServletDispatcherResult
Redirect
redirect
com.opensymphony.webwork.dispatcher.ServletRedirectResult
Action Chaining
chain
com.opensymphony.xwork.ActionChainResult
Velocity
velocity
com.opensymphony.webwork.dispatcher.VelocityResult
FreeMarker
freemarker
com.opensymphony.webwork.views.freemarker.FreemarkerResult
JasperReports
jasper
com.opensymphony.webwork.views.jasperreports.JasperReportsResult
XML/XSL
xslt
com.opensymphony.webwork.views.xslt.XSLTResult
HttpHeader
com.opensymphony.webwork.dispatcher.HttpHeaderResult
Dispatcher:通过javax.servlet.RequestDispatcher的forward()或include()方法调度到页面展现,这样的页面一般是Jsp页面。
参数(Parameters)
是否必需
描 述
location
是
执行完成之后转向的位置
parse
否
默认的是“true”,如果设置为“false”,location参数将不会被OGNL表达式语言解析
例子:
代码 |
<result name="success" type="dispatcher"> <param name="location">register-result.jsp</param> </result> |
也可以简单写成这样:
代码 |
<result name="success" type="dispatcher">register-result.jsp</result> |
Redirect:将响应重定向到浏览器指定的位置,它将会导致Action执行完成的数据丢失或不再可用。它在程序里是通过调用javax.servlet.http.HttpServletResponse.sendRedirect(String location)方法,将响应定向到参数location指定的、新的url中。
参数(Parameters)
是否必需
描 述
location
是
执行完成之后转向的位置
parse
否
默认的是“true”,如果设置为“false”,location参数将不会被OGNL表达式语言解析
例子
代码 |
<result name="success" type="redirect"> <param name="location">foo.jsp</param> <param name="parse">false</param> </result> |
Action Chaining:一种特殊的视图结果,将Action执行完之后链接到另一个Action中继续执行。新的Action使用上一个Action的上下文(ActionContext)。
参数(Parameters)
是否必需
描 述
actionName
是
将要被链接的Action名字
namespace
否
被链接的Action的命名空间(namespace),如果不设置,默认的即是当前的命名空间
例子:
代码 |
<result name="success" type="chain"> <param name="actionName">bar</param> <param name="namespace">/foo</param> </result> |
将要调用的Action如下:
代码 |
<action name="bar" class="myPackage.barAction"> ... </action> |
Velocity:它类似Jsp的执行环境(使用JavaServlet容器),将Velocity模板转化成数据流的形式,直接通过JavaServlet输出。
参数(Parameters)
是否必需
描 述
location
是
执行完成之后转向的位置(一般是.vm页面)
parse
否
默认的是“true”,如果设置为“false”,location参数将不会被OGNL表达式语言解析
例子:
代码 |
<result name="success" type="velocity"> <param name="location">foo.vm</param> </result> |
FreeMarker:FreeMarker是一个纯Java模板引擎;一个普通的基于模板生成文本的工具,它只能应用在Web应用环境中。
参数(Parameters)
是否必需
描 述
location
是
执行完成之后转向的位置
parse
否
默认的是“true”,如果设置为“false”,location参数将不会被OGNL表达式语言解析
contentType
否
如果不指定,默认的是"text/html"
例子:
代码 |
<result name="success" type="freemarker">foo.ftl</result> |
JasperReports:将Action执行的结果通过JasperReports报表形式输出,可以指定JasperReports支持的输出格式(PDF、HTML、XLS、CSV、XML等),默认是通过PDF格式输出。
参数(Parameters)
是否必需
描 述
location
是
执行完成之后转向的位置
parse
否
默认的是“true”,如果设置为“false”,location参数将不会被OGNL表达式语言解析
dataSource
是
它是Action的一个字段(通常是一个List),OGNL表达式被用来去value stack(OgnlValueStack)重新找回这个dataSource
format
否
报表生成的数据格式,默认的是pdf
例子:
代码 |
<result name="success" type="jasper"> <param name="location">foo.jasper</param> <param name="dataSource">mySource</param> <param name="format">CSV</param> </result> |
或者默认的pdf格式
代码 |
<result name="success" type="jasper"> <param name="location">foo.jasper</param> <param name="dataSource">mySource</param> </result> |
XML/XSL:将结果转换为xml输出
参数(Parameters)
是否必需
描述
location
是
执行完成之后转向的位置
parse
否
默认的是“true”,如果设置为“false”,location参数将不会被OGNL表达式语言解析
例子:
代码 |
<result name="success" type="xslt">foo.xslt</result>
|
表达式与言EL和OGNL
OGNL介绍
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。
XWork遵循“不要重复地发明同一个轮子”的理论,它的表达式语言核心用的就是这个OGNL。我们先来看看一个简单的例子:
还记得我们用户注册的那个例子吗?我们输入框的name用到的名字就是OGNL的表达式,比如:用户名的输入框:“<input type="text" name="user.username">”,在用户注册成功之后我们要显示用户注册的信息,用了“<ww:property value="user.username"/>”。Input输入框里的“user.username”,它解析成Java语句为:getUser().setUsername();,property标签里的“user.username”解析为Java语句:getUser.getUsername();。
我们的两个表达式都是相同的,但前一个保存对象属性的值,后一个是取得对象属性的值。表达式语言简单、易懂却又功能强大,关于OGNL更多的介绍可以去http://www.ognl.org,那里有很详细的文档。
值堆栈-OgnlValueStack
OGNL在框架中的应用,最主要是支持我们的值堆栈(Value Stack)——OgnlValueStack,它主要的功能是通过表达式语言来存取对象的属性。用户界面输入数据,它会根据保存表达式将数据依次保存到它堆栈的对象中,业务操作完成,结果数据会通过表达式被获取、输出。
还记得我们用户注册的例子吗?下面我们用一段程序来演示它向OgnlValueStack中保存、取得数据的步骤:
代码 |
// DemoRegisterValueStack package example.register; import com.opensymphony.xwork.util.OgnlValueStack; /** * @author moxie-qac * achqian@yahoo.com.cn * */ public class DemoRegisterValueStack { public void demo(){ RegisterAction action = new RegisterAction(); OgnlValueStack valueStack= new OgnlValueStack(); valueStack.push(action); valueStack.setValue("user.username","Moxie"); System.out.println("username = "+valueStack.findValue("user.username")); } public static void main(String[] args) { DemoRegisterValueStack demoValueStack = new DemoRegisterValueStack(); demoValueStack.demo(); } } |
我们来看一看它的demo()方法:
1、 创建我们的Action(RegisterAction)类的对象action,将action对象压入堆栈valueStack中。在WebWrok中Action的创建、入栈是在DefaultActionInvocation构造函数中进行的,详细介绍见:ServletDispatcher原理。
2、 通过表达式语言,调用堆栈对象的get()、set()方法,设置该对象的值。
public void setValue(String expr, Object value)
语句:valueStack.setValue("user.username","Moxie");
的作用等同于:action.getUser().setUsername("Moxie");
3、 通过表达式语言,去堆栈对象中查找我们前面保存的值,并在控制台打印。valueStack.findValue("user.username")等同与语句:
action.getUser().getUsername()
最后控制台打印的结果:
username = Moxie
CompoundRoot
在OgnlValueStack中,一个堆栈其实是一个List。查看OgnlValueStack你会发现,堆栈就是com.opensymphony.xwork.util.CompoundRoot类的对象:
代码 |
public class CompoundRoot extends ArrayList { //~ Constructors ///////////////////////////////////// public CompoundRoot() { } public CompoundRoot(List list) { super(list); } //~ Methods //////////////////////////////////////////// public CompoundRoot cutStack(int index) { return new CompoundRoot(subList(index, size())); } public Object peek() { return get(0); } public Object pop() { return remove(0); } public void push(Object o) { add(0, o); } } |
我们通过表达式向堆栈对象操作时,我们并不知道堆栈中有哪些对象。OgnlValueStack会根据堆栈由上向下的顺序(先入栈在下面,最后入栈在最上面)依次去查找与表达式匹配的对象方法,找到即进行相应的存取操作。假设后面对象也有相同的方法,将不会被调用。
下面我们看一个对OgnlValueStack操作的程序,它主要演示了如何对Map对象的存取和OgnlValueStack堆栈的原理:
代码 |
/* * Created on 2004-6-15 * DemoGroupValueStack.java */ package example.register; import com.opensymphony.xwork.util.OgnlValueStack; /** * @author moxie-qac * achqian@yahoo.com.cn * */ public class DemoGroupValueStack { public void demoAction(){ DemoGroupAction action = new DemoGroupAction(); OgnlValueStack valueStack= new OgnlValueStack(); valueStack.push(action); User zhao = new User(); zhao.setUsername("zhao"); zhao.setEmail("zhao@yahoo.com.cn"); User qian = new User(); qian.setUsername("qian"); qian.setEmail("qian@yahoo.com.cn"); valueStack.setValue("users['zhao']",zhao); valueStack.setValue("users['qian']",qian); System.out.println("users['zhao'] = "+valueStack.findValue("users['zhao']")); System.out.println("users['qian'] = "+valueStack.findValue("users['qian']")); System.out.println("users size = "+valueStack.findValue("users.size")); System.out.println("allUserName[0] = "+valueStack.findValue("allUserName[0]")); } public void demoModels(){ User model_a = new User(); model_a.setUsername("model_a"); User model_b = new User(); model_b.setUsername("model_b"); User model_c = new User(); model_c.setUsername("model_c"); OgnlValueStack valueStack= new OgnlValueStack(); valueStack.push(model_a); valueStack.push(model_b); valueStack.push(model_c); System.out.println("username = "+valueStack.findValue("username")); System.out.println("[1].username = "+valueStack.findValue("[1].username")); System.out.println("[0].toString = "+valueStack.findValue("[0]")); System.out.println("[1].toString = "+valueStack.findValue("[1]")); System.out.println("[2].toString = "+valueStack.findValue("[2]")); } public static void main(String[] args) { DemoGroupValueStack demoValueStack = new DemoGroupValueStack(); demoValueStack.demoAction(); demoValueStack.demoModels(); } } /* * Created on 2004-6-15 * DemoAction.java */ package example.register; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author moxie-qac * achqian@yahoo.com.cn * */ public class DemoGroupAction { private Map users = new HashMap(); public Map getUsers(){ return this.users; } public List getAllUserName(){ return new ArrayList(users.keySet()); } public String execute(){ //执行业务操作 return null; } public String toString(){ return users.toString(); } } |
注意:
1、Map属性的存取,它的表达式语言如:users['zhao'],注意它用’’来引用HashMap的key字符串。
2、demoModels()方法演示了OgnlValueStack中堆栈的原理,请特别注意它的[0].toString、[1].toString、[2].toString,它们依次调用堆栈中对象的toString()方法,并逐一的减少堆栈最上面的对象。
控制台输出的结果如下:
users['zhao'] = username=zhao;password=null;email=zhao@yahoo.com.cn;age=0
users['qian'] = username=qian;password=null;email=qian@yahoo.com.cn;age=0
users size = 2
allUserName[0] = qian
username = model_c
[1].username = model_b
[0].toString = [username=model_c;password=null;email=null;age=0, username=model_b;password=null;email=null;age=0, username=model_a;password=null;email=null;age=0]
[1].toString = [username=model_b;password=null;email=null;age=0, username=model_a;password=null;email=null;age=0]
[2].toString = [username=model_a;password=null;email=null;age=0]
Interceptor(拦截器)框架
Interceptor(拦截器)将Action共用的行为独立出来,在Action执行前后运行。这也就是我们所说的AOP(Aspect Oriented Programming,面向切面编程),它是分散关注的编程方法,它将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是有Interceptor实现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。Interceptor在框架中的应用如下图所示:
当你提交对Aciton(默认是.action结尾的Url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action。在Action执行之前,调用被 Interceptor截取,Interceptor在Action执行前后运行。
我们在用户注册的例子中就使用了取得Request请求参数的拦截器,配置文件中<interceptor-ref name="params"/>将拦截器params组装到RegisterAction中。“params”在我们的webwork-default.xml配置文件中有定义,webwork-default.xml中拦截器的定义如下:
Interceptor(拦截器)将Action共用的行为独立出来,在Action执行前后运行。这也就是我们所说的AOP(Aspect Oriented Programming,面向切面编程),它是分散关注的编程方法,它将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是有Interceptor实现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。Interceptor在框架中的应用如下图所示:
当你提交对Aciton(默认是.action结尾的Url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action。在Action执行之前,调用被 Interceptor截取,Interceptor在Action执行前后运行。
我们在用户注册的例子中就使用了取得Request请求参数的拦截器,配置文件中<interceptor-ref name="params"/>将拦截器params组装到RegisterAction中。“params”在我们的webwork-default.xml配置文件中有定义,webwork-default.xml中拦截器的定义如下:
代码 |
<interceptors> <interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/> <interceptor name="logger" class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/> <interceptor name="chain" class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/> <interceptor name="static-params" class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/> <interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/> <interceptor name="model-driven" class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/> <interceptor name="component" class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/> <interceptor name="token" class="com.opensymphony.webwork.interceptor.TokenInterceptor"/> <interceptor name="token-session" class="com.opensymphony.webwork.interceptor.TokenSessionStoreInterceptor"/> <interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/> <interceptor name="workflow" class="com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor"/> <interceptor name="servlet-config" class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/> <interceptor name="prepare" class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/> <interceptor name="conversionError" class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/> <interceptor-stack name="defaultStack"> <interceptor-ref name="static-params"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionError"/> </interceptor-stack> <interceptor-stack name="validationWorkflowStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="validation"/> <interceptor-ref name="workflow"/> </interceptor-stack> </interceptors> |
这些都时有框架提供的默认的Interceptor,下面我来看看Interceptor使用的步骤:
1、 创建一个自己需要的Interceptor类,它必需实现com.opensymphony.xwork.interceptor.Interceptor接口,具体的开发见下面的Interceptor的原理。
2、 在配置文件(xwork..xml)中申明这个Interceptor类,它放在标签<interceptor />中,同是<interceptor />标签嵌入在<interceptors />标签内部。
3、 创建Interceptor栈,使用标签:<interceptor-stack />,让一组Interceptor可以按次序调用。(可选)
4、 指定Action所要用到的Interceptor(前面申明过的),可以用<interceptor-ref />或<default-interceptor-ref />标签。前面的标签指定某个Action所用到的Interceptor,如果Action没有被用<interceptor-ref />指定Interceptor,它将使用<default-interceptor-ref />指定的Interceptor。
框架中给我们提供了很多实用的Interceptor,它的定义上面已经给出,它的具体功能如下:
* timer:记录Action执行的时间,并做为日志信息输出;
* logger:在日志信息中输出要执行的Action信息;
* chain:将前一个执行结束的Action属性设置到当前的Action中。它被用在ResultType为“chain”指定结果的Action中,该结果Action对象会从OgnlValueStack中获得前一个Action对应的属性,它实现Action链之间的数据传递;
* static-params:将xwork.xml配置文件里定义的Action参数,设置到对应的Action中。Action参数使用<param />标签,是<action />标签的直接子元素。我们这里定义的Action类必需实现com.opensymphony.xwork.config.entities. Parameterizable接口;
* params:将Request请求的参数设置到相应Action对象的属性中,用户注册例子用到过这个拦截器;
* model-driven:如果Action实现ModelDriven接口,它将getModel()取得的模型对象存入OgnlValueStack中;
* component:激活组件功能支持,让注册过的组件在当前Action中可用,即为Action提供IoC(依赖倒转控制)框架的支持;
* token:核对当前Action请求(request)的有效标识,防止重复提交Action请求(request)。
* token-session:功能同上,但是当提交无效的Action请求标识时,它会将请求数据保存到session中。
* validation:实现使用xml配置文件({Action}-validation.xml)对Action属性值进行验证,详细请看后面介绍的验证框架。
* workflow:调用Action类的验证功能,假设Action使用ValidationAware实现验证(ActionSupport提供此功能),如果验证没有通过,workflow会将请求返回到input视图(Action的<result />中定义的)。
* servlet-config:提供Action直接对HttpServletRequest或HttpServletResponse等JavaServlet api的访问,Action要实现相应的接口,例如:ServletRequestAware或ServletResponseAware等。如果必需要提供对JavaServlet api的访问,我们建议使用ServletActionContext,在前面ActionContext章节中有介绍。
* prepare:在Action执行之前调用Action的prepare()方法,这个方法是用来准备Action执行之前要做的工作。它要求我们的Action必需实现com.opensymphony.xwork. Preparable接口
* conversionError:用来处理框架进行类型转化(Type Conversion)时的出错信息。它将存储在ActionContext中的类型转化(Type Conversion)错误信息转化成相应的Action字段的错误信息,保存在堆栈中。根据需要,可以将这些错误信息在视图中显示出来。
Interceptor的原理
下面我们来看看Interceptor是如何实现在Action执行前后调用的:
Action和Interceptor在框架中的执行,是由ActionInvocation对象调用的。它是用方法:String invoke() throws Exception;来实现的,它首先会依次调用Action对应的Interceptor,执行完成所有的Interceptor之后,再去调用Action的方法,代码如下:
代码 |
if (interceptors.hasNext()) { Interceptor interceptor = (Interceptor) interceptors.next(); resultCode = interceptor.intercept(this); } else { if (proxy.getConfig().getMethodName() == null) { resultCode = getAction().execute(); } else { resultCode = invokeAction(getAction(), proxy.getConfig()); } } |
它会在拦截器栈中遍历Interceptor,调用Interceptor的方法:
String intercept(ActionInvocation invocation) throws Exception;。
我们一直都提到,Interceptor是在Action前后执行,可是从上面的代码我们看到的却是执行完所有Interceptor的intercept()方法之后再去调用我们的Action。“在Action前后执行”是如何实现的呢?我们来看看抽象类AroundInterceptor的intercept()实现:
代码 |
public String intercept(ActionInvocation invocation) throws Exception { String result = null; before(invocation); result = invocation.invoke(); after(invocation, result); return result; } |
原来在intercept()方法又对ActionInvocation的invoke()方法进行递归调用,ActionInvocation循环嵌套在intercept()中,一直到语句result = invocation.invoke();执行结束,即:Action执行完并返回结果result,这时Interceptor对象会按照刚开始执行的逆向顺序依次执行结束。这样before()方法将在Action执行前调用,after()方法在Action执行之后运行。
发表评论
-
C3P0连接池详细配置
2008-03-28 10:06 1207转载至:http://jacreater.spac ... -
Eclipse中设置在创建新类时自动生成注释(转)
2008-03-28 10:03 1605Eclipse中设置在创建新类时自动生成注释 windo ... -
struts2 code-behind
2008-03-01 09:39 4670code-behind在struts2里有两种表现形式: 1. ... -
(转)Apache2.2和SVN1.4.4搭建svn版本控制平台windows版
2007-12-23 14:04 2979一、安装 第一步,安装Apache2.2,下载后直接安装就可 ... -
Resin 3.x 经验总结
2007-12-09 20:51 15761. 怎样关闭目录浏览 ... -
缓存管理框架原理(JCS)
2007-12-05 12:07 4024安装和配置 在web应 ... -
截取在线编辑器的字符串怎么处理
2007-11-22 10:39 1536/** * 按字节长度截取字符串(支持截取带HTML代码 ... -
Java对各种文件的操作详解(转)
2007-11-22 10:37 1879java中提供了io类库,可以轻松的用java实现对文件的各种 ... -
java时间操作函数汇总(转)
2007-11-22 10:27 16031.计算某一月份的最大天数 Calendar time=Cal ... -
很好面试题(JSP程序员) 转
2007-11-13 14:34 1875答题时间20分钟 1. System.out.printl ... -
Resin的基本使用
2007-09-15 19:44 6435使用Resin开发Java Web项目时,需要建立自己的W ... -
怎样才能成为更有创意博客
2007-05-18 06:14 1016上周在清理我的硬盘的时候,发现我的一篇老文章,说的是我给一些年 ... -
模型驱动SOA帮助提高开发团队效率
2007-07-23 06:26 962做过应用软件开发的朋友们大多都熟悉传统的开发生命周期:应用软件 ... -
WebWork教程三
2007-08-01 11:20 1457验证框架 WebWork提 ... -
WebWork教程一
2007-08-01 11:31 2951WebWork介绍 WebWork是由OpenSymph ... -
对天乙社区bbscs8实现的详细分析三
2007-08-02 08:27 4990经过前面的分析,我们已经理清楚了业务层,接下来的部分将是web ... -
对天乙社区bbscs8实现的详细分析四
2007-08-07 09:07 3035在分析三,我们已经分析出jsp页面如何通过struts2的标签 ... -
对天乙社区bbscs8实现的详细分析一(附文档下载)
2007-08-07 09:12 4948由于BBSCS8是由数据库设计-bean/hbm.xml-DA ... -
对天乙社区bbscs8实现的详细分析二
2007-08-07 09:14 1646我们仍然将分析处于service包中,首分析下上次没有分析的F ...
相关推荐
### WebWork教程知识点详解 #### 一、WebWork框架简介 **WebWork**是一个由OpenSymphony组织开发的Java Web框架,它采用了Model-View-Controller(MVC)设计模式,旨在实现组件化和代码重用。WebWork的最新版本为...
### Webwork教程知识点详解 #### 一、WebWork框架简介 **WebWork**是一个开源的Java Web应用程序框架,它的设计理念是简化Web应用的开发过程,提高开发效率。随着时间的发展,WebWork逐渐演变成了**Struts2**框架...
### WebWork教程知识点详解 #### 一、WebWork框架简介 **WebWork**是一个由OpenSymphony组织开发的、致力于组件化和代码重用的拉出式MVC(Model-View-Controller)模式的J2EE Web框架。该框架的核心设计理念在于...
在本教程中,我们将深入探讨WebWork2的核心概念、功能及其在实际开发中的应用。 WebWork2是Struts的前身,它在Struts的基础上进行了很多改进,比如更强大的动作映射、类型安全的参数绑定以及更优秀的异常处理机制。...
### WebWork2 教程详解 #### 一、引言 WebWork2 是一款轻量级的 Java Web 开发框架,它遵循 MVC (Model-View-Controller) 设计模式,旨在简化 Web 应用程序的开发流程。通过本文档的学习,您将能够掌握 WebWork2 ...
WebWork教程提供了关于如何使用WebWork框架开发Web应用程序的详细指导。它包括了WebWork基础、安装指南、HelloWorld示例、Action动作的介绍以及如何进行Action的单元测试等。此外,还涵盖了ResultType(结果类型)的...
### WebWork教程精要 #### WebWork框架概览 WebWork是OpenSymphony组织研发的一款J2EE Web框架,其核心理念在于组件化与代码复用,采用的是MVC(Model-View-Controller)设计模式的变体——即所谓的“拉出式”MVC...
这个"WebWork教程.rar"压缩包很可能包含了关于如何使用WebWork框架进行开发的详细资料,其中的"webwork.doc"文档可能是教程的核心部分。下面我们将深入探讨WebWork框架的关键知识点。 1. **MVC模式**:WebWork遵循...
总的来说,WebWork教程0.90版是一个了解和学习WebWork框架的好资源,虽然现在可能已经有更先进的版本(如Struts 2,WebWork的后续发展),但基本概念和原理依然适用。对于想要理解MVC架构以及Java Web开发的初学者,...
**WebWork教程(经典)** WebWork是一款基于Java的MVC(模型-视图-控制器)框架,它在Web应用程序开发中提供了强大的功能和灵活性。本教程旨在帮助开发者理解和掌握WebWork的核心概念和技术。 **一、WebWork介绍** ...
这个“webwork教程和上手例子”压缩包很可能是为了帮助初学者快速理解并掌握WebWork的核心概念和实际操作。让我们深入探讨一下WebWork的相关知识点。 1. **MVC架构模式**:WebWork遵循MVC设计模式,它将应用分为...
**WebWork教程(初学者的学习)** WebWork是一款基于Java的轻量级MVC(Model-View-Controller)框架,专为开发Web应用程序而设计。它简化了网页应用的构建,提高了代码的可维护性和可扩展性。对于初学者而言,理解...
WebWork是Struts 2框架的前身,它也是为了解决Web层的问题而设计的,并且提供了强大的功能,例如与XWork的动作框架集成、强大的模板技术(如Velocity和FreeMarker)以及对各种验证框架的支持。 ### 核心组件和概念 ...
WebWork是Java Web开发中的一个框架,它在早期与Struts有着密切的关系,后来成为了Struts2的基础。这个"WebWork入门教程[创建你第一个WebWork action]"将引导你了解如何利用WebWork来构建动态的Web应用程序。让我们...
### WebWork教程知识点详解 #### 一、WebWork框架简介 **WebWork**是由OpenSymphony组织开发的一款致力于组件化和代码重用的MVC模式的J2EE Web框架。该框架强调模块化设计和代码复用性,适用于构建大型企业级应用...
在"webwork教程几原码示例"中,我们可以深入学习WebWork的核心概念和实际应用。 1. **MVC架构**: MVC模式是WebWork的基础,它将应用程序分为三个主要部分:模型(Model)、视图(View)和控制器(Controller)。...
Webwork2的教程