最近学习了WebWork,感觉它相对Struts1的最大优势在于它便于测试和Interceptor,使得系统的架构更加的低藕和,提高代码的可重用性。以后是学习WebWork过程中的一些感想。
1、对Request, Response, Session对象的访问,最好采用Aware接口的方式进行访问,而不是采用ServletActionContext的方式访问。
2、文件上传(同名多文件上传只需把相应的字段改成数组)
使用MultiPartRequestWrapper上传文件
public class ReqUpload extends ActionSupport implements ServletRequestAware{
public String execute() throws Exception {
// TODO Auto-generated method stub
MultiPartRequestWrapper rap = (MultiPartRequestWrapper)(req);
File doc = null;
try
{
doc = rap.getFiles("doc")[0];
String fileName = rap.getFileNames("doc")[0];
String contentType = rap.getContentTypes("doc")[0];
File directory = new File("e:\\log\\"+fileName);
doc.renameTo(directory);
}catch(Exception e)
{
e.printStackTrace();
}
finally
{
doc.delete();
}
return SUCCESS;
}
}
使用FileUploadInterceptor
pblic String execute() throws Exception
{
for(int i = 0; i < this.getDoc().length; i++)
{
File path = new File("e:\\log\\"+this.getDocFileName()[i]);
this.getDoc()[i].renameTo(path);
}
return SUCCESS;
}
然后再Action配置中加入<interceptor-ref name="completeStack"/>
3、Field-Driven Action VS Model-Driven Action
Field-Driven Action
它一般用在页面表单比较简单的情况使用,而且可以直接用域对象作为Action的字段。
Model-Driven Action
它很像Struts的FormBean,但在WebWork中,只要普通Java对象就可以充当模型部分。Model-Driven(模型驱动的)Action要求我们的Action实现com.opensymphony.xwork.ModelDriven接口,它有一个方法:Object getModel(),我们用这个方法返回我们的模型对象就可以了。如:
public class RegisterAction implements Action,ModelDriven
{
private User user = new User();
public String execute() throws Exception
{
//在这里调用用户注册的业务逻辑,比如:将注册信息存储到数据库
return SUCCESS;
}
public Object getModel()
{
return user;
}
}
页面文件:
<form name="register" action="register.action" method="post">
Username:<input type="text" name="username"><br>
Password:<input type="text" name="password"><br>
Email:<input type="text" name="email"><br>
Age:<input type="text" name="age"><br>
<input type="submit" name="Submit"><br>
</form>
配置文件如下:
<action name="register" class="com.xxh.actions.RegisterAction">
<result name="success" type="dispatcher">
<param name="location">/register-result.jsp</param>
</result>
<interceptor-ref name="model-driven"/>
<interceptor-ref name="params"/>
</action>
4、ActionContext And ServletActionContext
ActionContext
执行Action的上下文,我们可以通过ActionContext的静态方法:ActionContext.getContext()来取得当前的ActionContext对象;通过ActionContext取得我们的HttpSession:Map session = ActionContext.getContext().getSession();WebWork框架将与Web相关的很多对象重新进行了包装,比如这里将HttpSession对象重新包装成了一个Map对象,供我们的Action使用,而不用直接和底层的HttpSession打交道。也正是框架的包装,让我们的Actoion可以完全的和Web层解藕。
ServletActionContext
这个类直接继承了ActionContext,提供了直接与JavaServlet相关对象访问的功能,它可以取得的对象有:javax.servlet.http.HttpServletRequest:HTTPservlet请求对象;javax.servlet.http.HttpServletResponse;:HTTPservlet响应对象;javax.servlet.ServletContext:Servlet 上下文信息;javax.servlet.ServletConfig:Servlet配置对象;javax.servlet.jsp.PageContext:Http页面上下文。使用 ServletActionContext. getRequest()、 ServletActionContext. getRequest().getSession()等方式获取相应的对象。
ServletActionContext和ActionContext有着一些重复的功能,在我们的Action中,该如何去选择呢?我觉得:如果ActionContext能够实现我们的功能,那最好就不要使用ServletActionContext,让我们的Action尽量不要直接去访问JavaServlet的相关对象。在使用ActionContext时有一点要注意:不要在Action的构造函数里使用ActionContext.getContext(),因为这个时候ActionContext里的一些值也许没有设置,这时通过ActionContext取得的值也许是null。
5、单元测试
使用单元测试框架JUnit对register.User. RegisterAction做单元测试
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);
}
6、Interceptor(拦截器)
Interceptor(拦截器)将Action共用的行为独立出来,在Action执行前后运行。这也就是我们所说的AOP(Aspect Oriented Programming,面向切面编程),它将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
当你提交对Aciton(默认是.action结尾的Url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action。在Action执行之前,调用被 Interceptor截取,Interceptor在Action执行前后运行。
webwork-default.xml中拦截器的定义如下:
<interceptors>
<interceptor name="alias" class="com.opensymphony.xwork.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/>
<interceptor name="component" class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/>
<interceptor name="conversionError" class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/>
<interceptor name="createSession" class="com.opensymphony.webwork.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="com.opensymphony.webwork.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="external-ref" class="com.opensymphony.xwork.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="com.opensymphony.webwork.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="com.opensymphony.webwork.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/>
<interceptor name="model-driven" class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/>
<interceptor name="static-params" class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="com.opensymphony.webwork.interceptor.ScopeInterceptor"/>
<interceptor name="servlet-config" class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring" class="com.opensymphony.webwork.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/>
<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="paramFilter" class="com.opensymphony.xwork.interceptor.ParameterFilterInterceptor" />
<interceptor name="paramRemover" class="com.opensymphony.xwork.interceptor.ParameterRemoverInterceptor" />
<interceptor name="sessionInvalidation" class="com.opensymphony.webwork.interceptor.SessionInvalidationInterceptor" />
<interceptor name="flash" class="com.opensymphony.webwork.interceptor.FlashInterceptor" />
<interceptor name="cookie" class="com.opensymphony.webwork.interceptor.CookieInterceptor" />
<interceptor name="store" class="com.opensymphony.webwork.interceptor.MessageStoreInterceptor" />
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="model-driven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
<default-interceptor-ref name="defaultStack"/>
</interceptors>
可以自定义一个自己的Interceptor, 得实现Interceptor接口,或扩展抽象类AroundInterceptor等实现一个自己的Interceptor.
1、对Request, Response, Session对象的访问,最好采用Aware接口的方式进行访问,而不是采用ServletActionContext的方式访问。
2、文件上传(同名多文件上传只需把相应的字段改成数组)
使用MultiPartRequestWrapper上传文件
public class ReqUpload extends ActionSupport implements ServletRequestAware{
public String execute() throws Exception {
// TODO Auto-generated method stub
MultiPartRequestWrapper rap = (MultiPartRequestWrapper)(req);
File doc = null;
try
{
doc = rap.getFiles("doc")[0];
String fileName = rap.getFileNames("doc")[0];
String contentType = rap.getContentTypes("doc")[0];
File directory = new File("e:\\log\\"+fileName);
doc.renameTo(directory);
}catch(Exception e)
{
e.printStackTrace();
}
finally
{
doc.delete();
}
return SUCCESS;
}
}
使用FileUploadInterceptor
pblic String execute() throws Exception
{
for(int i = 0; i < this.getDoc().length; i++)
{
File path = new File("e:\\log\\"+this.getDocFileName()[i]);
this.getDoc()[i].renameTo(path);
}
return SUCCESS;
}
然后再Action配置中加入<interceptor-ref name="completeStack"/>
3、Field-Driven Action VS Model-Driven Action
Field-Driven Action
它一般用在页面表单比较简单的情况使用,而且可以直接用域对象作为Action的字段。
Model-Driven Action
它很像Struts的FormBean,但在WebWork中,只要普通Java对象就可以充当模型部分。Model-Driven(模型驱动的)Action要求我们的Action实现com.opensymphony.xwork.ModelDriven接口,它有一个方法:Object getModel(),我们用这个方法返回我们的模型对象就可以了。如:
public class RegisterAction implements Action,ModelDriven
{
private User user = new User();
public String execute() throws Exception
{
//在这里调用用户注册的业务逻辑,比如:将注册信息存储到数据库
return SUCCESS;
}
public Object getModel()
{
return user;
}
}
页面文件:
<form name="register" action="register.action" method="post">
Username:<input type="text" name="username"><br>
Password:<input type="text" name="password"><br>
Email:<input type="text" name="email"><br>
Age:<input type="text" name="age"><br>
<input type="submit" name="Submit"><br>
</form>
配置文件如下:
<action name="register" class="com.xxh.actions.RegisterAction">
<result name="success" type="dispatcher">
<param name="location">/register-result.jsp</param>
</result>
<interceptor-ref name="model-driven"/>
<interceptor-ref name="params"/>
</action>
4、ActionContext And ServletActionContext
ActionContext
执行Action的上下文,我们可以通过ActionContext的静态方法:ActionContext.getContext()来取得当前的ActionContext对象;通过ActionContext取得我们的HttpSession:Map session = ActionContext.getContext().getSession();WebWork框架将与Web相关的很多对象重新进行了包装,比如这里将HttpSession对象重新包装成了一个Map对象,供我们的Action使用,而不用直接和底层的HttpSession打交道。也正是框架的包装,让我们的Actoion可以完全的和Web层解藕。
ServletActionContext
这个类直接继承了ActionContext,提供了直接与JavaServlet相关对象访问的功能,它可以取得的对象有:javax.servlet.http.HttpServletRequest:HTTPservlet请求对象;javax.servlet.http.HttpServletResponse;:HTTPservlet响应对象;javax.servlet.ServletContext:Servlet 上下文信息;javax.servlet.ServletConfig:Servlet配置对象;javax.servlet.jsp.PageContext:Http页面上下文。使用 ServletActionContext. getRequest()、 ServletActionContext. getRequest().getSession()等方式获取相应的对象。
ServletActionContext和ActionContext有着一些重复的功能,在我们的Action中,该如何去选择呢?我觉得:如果ActionContext能够实现我们的功能,那最好就不要使用ServletActionContext,让我们的Action尽量不要直接去访问JavaServlet的相关对象。在使用ActionContext时有一点要注意:不要在Action的构造函数里使用ActionContext.getContext(),因为这个时候ActionContext里的一些值也许没有设置,这时通过ActionContext取得的值也许是null。
5、单元测试
使用单元测试框架JUnit对register.User. RegisterAction做单元测试
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);
}
6、Interceptor(拦截器)
Interceptor(拦截器)将Action共用的行为独立出来,在Action执行前后运行。这也就是我们所说的AOP(Aspect Oriented Programming,面向切面编程),它将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
当你提交对Aciton(默认是.action结尾的Url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action。在Action执行之前,调用被 Interceptor截取,Interceptor在Action执行前后运行。
webwork-default.xml中拦截器的定义如下:
<interceptors>
<interceptor name="alias" class="com.opensymphony.xwork.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/>
<interceptor name="component" class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/>
<interceptor name="conversionError" class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/>
<interceptor name="createSession" class="com.opensymphony.webwork.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="com.opensymphony.webwork.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="external-ref" class="com.opensymphony.xwork.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="com.opensymphony.webwork.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="com.opensymphony.webwork.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/>
<interceptor name="model-driven" class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/>
<interceptor name="static-params" class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="com.opensymphony.webwork.interceptor.ScopeInterceptor"/>
<interceptor name="servlet-config" class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring" class="com.opensymphony.webwork.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/>
<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="paramFilter" class="com.opensymphony.xwork.interceptor.ParameterFilterInterceptor" />
<interceptor name="paramRemover" class="com.opensymphony.xwork.interceptor.ParameterRemoverInterceptor" />
<interceptor name="sessionInvalidation" class="com.opensymphony.webwork.interceptor.SessionInvalidationInterceptor" />
<interceptor name="flash" class="com.opensymphony.webwork.interceptor.FlashInterceptor" />
<interceptor name="cookie" class="com.opensymphony.webwork.interceptor.CookieInterceptor" />
<interceptor name="store" class="com.opensymphony.webwork.interceptor.MessageStoreInterceptor" />
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="model-driven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
<default-interceptor-ref name="defaultStack"/>
</interceptors>
可以自定义一个自己的Interceptor, 得实现Interceptor接口,或扩展抽象类AroundInterceptor等实现一个自己的Interceptor.