MVC with Webwork2 Xwork
Action...1 ActionContext...3 ActionProxyFactory Factory...4 ActionProxyFactory Proxy AOP...7 XworkInterceptor...8 Interceptor...9 LoginAction...10 LoginInterceptor...12 Action Result ActionChainResult...14 EL OGNL...16 OGNL...17...17...18...20...20 List Array Map...21 (projection,selection)...22 MVC ValueStack...24 OgnlValueStack...24 ActionContext OgnlStackValue...26 Interceptor...26 ParametersInterceptor staticparametersinterceptor...26 ChainingInterceptor...26 ModelDrivenInterceptor...26 ValidationInterceptor Xwork...26 AOP...26...26 EL...26 XWork...26 Xwork+Hessian...27
Model2 MVC WebWork Command Xwork XWork WebWork1 Webwork2 Web - WebWork - JPublish - OSWorkFlow - AOBao Ivory Xwork WebWork Type MVC Xwork WebWork Action Xwork Xwork Action public interface Action extends Serializable { public static final String SUCCESS = "success"; public static final String NONE = "none"; public static final String ERROR = "error"; public static final String INPUT = "input"; public String execute() throws Exception; String execute,execute Action public class SignupAction implements Action { private UserService userservice; private String username; private String password; private String confirm; private String email; public String execute() throws Exception { getuserservice().createuser(username, password, email); return SUCCESS; private UserService getuserservice() { if(userservice == null) 1
userservice = new MemoryUserService(); return userservice; set get SignupAction Action Action Struts Action Action Web Hessian TestCase public void testcreateuser() throws Exception { SignupAction action = new SignupAction(); action.setusername("test"); action.setemail("test@test.com"); action.setpassword("1234"); action.setconfirm("1234"); String result = action.execute(); assertequals(result,action.success); SideBar: l TestCase main System.out.println println TestCase assert TestCase public void testcreateuser() throws Exception { SignupAction action = new SignupAction(); action.setusername("test"); action.setemail("test@test.com"); action.setpassword("1234"); action.setconfirm("1234"); String result = action.execute(); assertequals(result,action.success); User TDD User user = action.getuser(); 2
assertequals("test",user.getusername()); ActionContext Action WebWork SignupAction WebWork Action action execute WebWork action SignupAction Web Webwork HtteRequest username action Action execute struts : public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForm HttpServletRequest HttpServletResponse, Action Action Form Xwork ActionContext import com.opensymphony.xwork.actioncontext;... ActionContext ac = ActionContext.getContext(); ActionContext Map WebWork action Action ActionContext getcontext : public static ActionContext getcontext() { ActionContext context = (ActionContext) actioncontext.get(); if (context == null) { OgnlValueStack vs = new OgnlValueStack(); context = new ActionContext(vs.getContext()); setcontext(context); 3
return context; actioncontext ThreadLocal Action ActionContext Action ActionContext execute FormBean ActionContext Action ActionContext ActionProxyFactory Factory Action ActionContext ActionContext Factory ActionProxyFactory. public void testcreateuserwithproxyfactory() throws Exception { Map params = new HashMap(); params.put("username", "test"); params.put("email", "test@test.com"); params.put("password", "1234"); params.put("confirm", "1234"); Map context = new HashMap(); context.put(actioncontext.parameters, params); Xwork ActionProxyFactory factory = ActionProxyFactory.getFactory(); ActionProxy proxy = factory.createactionproxy("", "signup", context); proxy.execute(); SignupAction action = (SignupAction) proxy.getaction(); String result = action.execute(); assertequals(result, Action.SUCCESS); Map Action JavaBean key value Map ActionContext.PARAMETERS Context. factory.createactionproxy ActionProxy 4
map Action ActionContext JUnit java.lang.exception: Could not open file xwork.xml Action createactionproxy Xwork xwork.xml signup Action xwork.xml classpath xwork.xml <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd"> <xwork> <package name="default"> <action name="signup" class="org.erptao.flex.book.xwork.signupaction"> </action> </package> </xwork> package signup org.erptao.flex.book.xwork.signupaction.! action execute public String execute() throws Exception { Map params = username = ActionContext.getContext().getParameters(); (String) params.get("username"); password = (String) params.get("password"); email = (String)params.get("email"); getuserservice().createuser(username, password, email); return SUCCESS; public void testcreateuserwithproxyfactory() throws Exception { Map params = new HashMap(); params.put("username", "test"); params.put("email", "test@test.com"); params.put("password", "1234"); params.put("confirm", "1234"); Map context = new HashMap(); context.put(actioncontext.parameters, params); 5
ActionProxyFactory factory = ActionProxyFactory.getFactory(); ActionProxy proxy = factory.createactionproxy("", "signup", context); String result = proxy.execute(); SignupAction action = (SignupAction) proxy.getaction(); assertequals(result, Action.SUCCESS); User user = action.getuser(); assertequals("test", user.getusername()); assertequals("test@test.com",user.getemail()); TestCase Xwork execute setusername,setpassword ActionContext execute : public String execute() throws Exception { getuserservice().createuser(username, password, email); return SUCCESS; Xwork Action Bean factory struts FormBean Action SignupAction execute public String execute() throws Exception { Map params = username = ActionContext.getContext().getParameters(); (String) params.get("username"); password = (String) params.get("password"); confirm = (String) params.get("confirm"); email = (String)params.get("email"); if(password==null confirm==null!password.equals(confirm)) { throw new Exception("password not set or confirm!= password"); getuserservice().createuser(username, password, email); 6
return SUCCESS; Action Factory factory Bean execute factory execute profiling factory AOP ActionProxyFactory Proxy AOP [XXX ]AOP xwork.xml signupaction ParametersInterceptor <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd"> <xwork> <package name="default"> <interceptors> <interceptor name="params" class="com.opensymphony.xwork.interceptor.parametersinterceptor"/> </interceptors> <action name="signup" class="org.erptao.flex.book.xwork.signupaction"> <interceptor-ref name="params"/> </action> </package> </xwork> xwork.xml <interceptors> <interceptor name="params" class="com.opensymphony.xwork.interceptor.parametersinterceptor"/> <interceptors> package action inteceptor interceptor interceptor stack 7
action interceptor interceptor Interceptor Xwork signup execute TestCase XworkInterceptor Interceptor J2EE Interceptor javax.serlet.filter JBoss Interceptor Interceptor AOP AspectJ Interceptor AOP Xwork Interceptor Action execute execute execute execute Xwork Interceptor Interceptor public interface Interceptor { void init(); void destroy(); String intercept(actioninvocation invocation) throws Exception; init interceptor Interceptor destroy interceptor intercept Intercept String action excute String Interceptor action ActionInvocation public interface ActionInvocation extends Serializable { Action getaction(); boolean isexecuted(); ActionContext getinvocationcontext(); ActionProxy getproxy(); Result getresult() throws Exception; String getresultcode(); OgnlValueStack getstack(); void addpreresultlistener(preresultlistener listener); String invoke() throws Exception; :Invoke(). Interceptor Interceptor 8
Interceptor Intercetor 1 Interceptor Interceptor Interceptor Xwork Action 2 Interceptor Action AOP Before Around After Interceptor XWork AroundInterceptor AroundInterceptor execute invoke Xwork AroundInterceptor Action public abstract class AroundInterceptor implements Interceptor { public void destroy() { public void init() { public String intercept(actioninvocation invocation) throws Exception { String result = null; before(invocation); result = invocation.invoke(); after(invocation, result); return result; protected abstract void after(actioninvocation dispatcher, String result) throws Exception; protected abstract void before(actioninvocation invocation) throws Exception; AroundInterceptor before After After result, result. Interceptor 9
LoginAction Authenticator public interface Authenticator { boolean login(string username,string password); public class DefaultAuthenticator implements Authenticator { private UserService userservice;; /** * */ public DefaultAuthenticator(UserService userservice) { this.userservice = userservice; // TODO Auto-generated constructor stub public boolean login(string username, String password) { User user = userservice.getuserbyname(username); if(user == null) return false; if(user.getpassword()==null) { return password==null; else { return user.getpassword().equals(password); UserService IoC protected void setup() throws Exception { service = new MemoryUserService(); service.createuser("zhansan","123","zhangsan@z.com"); public void testlogin() throws Exception { Map params = new HashMap(); params.put("userservice",service); 10
params.put("username", "syy"); params.put("password", "123"); Map context = new HashMap(); context.put(actioncontext.parameters, params); ActionProxyFactory factory = ActionProxyFactory.getFactory(); ActionProxy proxy = factory.createactionproxy("", "login", context); String result = proxy.execute(); assertequals(result, Action.SUCCESS);,setup UserService testlogin params.put("userservice",service); params.put("username", "syy"); params.put("password", "123"); userservice public class LoginAction implements Action { private String username; private String password; private Authenticator authenticator; /* (non-javadoc) * @see com.opensymphony.xwork.action#execute() */ public String execute() throws Exception { Map params = ActionContext.getContext().getParameters(); username = (String) params.get("username"); password = (String) params.get("password"); UserService service = (UserService) params.get("userservice"); if(getauthenticator(service).login(username,password)) return SUCCESS; else return ERROR; public Authenticator getauthenticator(userservice service) { 11
if(authenticator==null) { authenticator = new DefaultAuthenticator(service); return authenticator; assertequals(result, Action.SUCCESS); assertequals(result, Action.ERROR); params = new HashMap(); params.put("userservice",service); params.put("username", "zhansan"); params.put("password", "123"); context = new HashMap(); context.put(actioncontext.parameters, params); proxy = factory.createactionproxy("", "login", context); result = proxy.execute(); assertequals(result, Action.SUCCESS); User user = service.getuserbyname("zhansan"); asserttrue(user.getlastlogintime()>=beforetime); asserttrue(user.getlastlogintime()<=system.currenttimemillis()); LoginInterceptor LoginInterceptor public class LoginInterceptor extends AroundInterceptor{ protected void after(actioninvocation dispatcher, String result) throws Exception { ActionContext context = dispatcher.getinvocationcontext(); Map params = context.getparameters(); String username = (String) params.get("username"); UserService service = (UserService) params.get("userservice"); User user = service.getuserbyname(username); 12
if(user!=null) user.setlastlogintime(system.currenttimemillis()); /* (non-javadoc) * @see com.opensymphony.xwork.interceptor.aroundinterceptor#before(com.opens ymphony.xwork.actioninvocation) */ protected void before(actioninvocation invocation) throws Exception { // TODO Auto-generated method stub,interceptor ActionInvocation ActionContext xwork <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd"> <xwork> <package name="default"> <interceptors> <interceptor name="login" class="org.erptao.flex.book.xwork.logininterceptor"/> </interceptors> <action name="login" class="org.erptao.flex.book.xwork.loginaction"> <interceptor-ref name="login"/> </action> </package> </xwork> TestFirst Interceptor Interceptor TDD TestCase Interceptor Interceptor 13
Action Result ActionChainResult Action execute Interceptor MVC C C action Action execute String Xwork string Xwork String Xwork.xml Result Result execute SignupAction ActionChainResult <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd"> <xwork> <package name="default"> <result-types> <result-type name= chain class= com.opensymphony.xwork.actionchainresult /> </result-types> <action name="signup" class="org.erptao.flex.book.xwork.signupaction"> <result name="success" type="chain"> <param name="actionname">showsuccess</param> </result> <result name="error" type="chain"> <param name="actionname">showerror</param> </result> </action> </xwork> <action name="showsuccess" class="org.erptao.flex.book.xwork.showsuccessaction"> </action> <action name="showerror" class="org.erptao.flex.book.xwork.showerroraction"> </action> 14
package Result Xwork : <result-types> <result-type name= chain class= com.opensymphony.xwork.actionchainresult /> </result-types> ActionChainResult Action result-type action <result name="success" type="chain"> <param name="actionname">showsuccess</param> </result> <result name="error" type="chain"> <param name="actionname">showerror</param> </result> SignupAction SUCCESS showsuccess action ERROR showerroraction. Xwork.xml public class ShowSuccessAction extends TestCase implements Action{ private String username; private String password; private String confirm; private String email; /* (non-javadoc) * @see com.opensymphony.xwork.action#execute() */ public String execute() throws Exception { Map params = ActionContext.getContext().getParameters(); username = (String) params.get("username"); password = (String) params.get("password"); confirm = (String) params.get("confirm"); email = (String) params.get("email"); fail(); return Action.SUCCESS; ShowSuccessAction TestCase Action action UserTest, fail() assertequals(username,"test"); assertequals(email, "test@test.com"); assertequals(password, "1234"); assertequals(confirm, "1234"); 15
Xwork Result actionname,( <param name="actionname">showsuccess</param>) Result execute public void execute(actioninvocation invocation) throws Exception { HashMap extracontext = new HashMap(); extracontext.put(actioncontext.value_stack, ActionContext.getContext().getValueStack()); extracontext.put(actioncontext.parameters, ActionContext.getContext().getParameters()); extracontext.put("com.opensymphony.xwork.interceptor.component.compon entmanager", ActionContext.getContext().get("com.opensymphony.xwork.interceptor.co mponent.componentmanager")); if (log.isdebugenabled()) { log.debug("chaining to action " + actionname); one // if the namespace wasn't explicitly defined, assume the current if (this.namespace == null) { this.namespace = invocation.getproxy().getnamespace(); proxy = ActionProxyFactory.getFactory().createActionProxy(this.namespace, actionname, extracontext); proxy.execute(); Xwork Action Controller Web Webwork Result EL OGNL Action Web Form 16
username Action username Action Action Action 1 TextField Data String Action string FormBean 2 Action Action action action 3 list map 4 5 JSP javabean JSTL EL.,Velocity WebWork Web tag Xwork Xwork OGNL Object Graph Navigation Language Web Tapestry WebObjects http://www.ognl.org/ OGNL Java OGNL OGNL OGNL JavaBean setter/getter OGNL 17
User public class User { public Group getgroup() { public class Group { private Map users = new HashMap(); private String name; public Group(String name) { this.name = name; public boolean containuser(string username) { return users.containskey(username); public void adduser(user user) { user.setgroup(this); users.put(user.getusername(),user); public Collection getallusers() { return Collections.unmodifiableCollection(users.values()); user group.name group.containuser ( test ) group.allusers.size() Ognl TestCase public void testget() throws OgnlException { User user = new User("test","123","a@a.com"); Object name = getvalue(user,"username",null); assertequals("test",name); Map context = new HashMap(); context.put("hello","hi! "); Object hello = getvalue(user,"#hello + username",context); assertequals("hi! test",hello); 18
public Object getvalue(object rootobject,string expr,map context) throws OgnlException { if(context==null) return Ognl.getValue(Ognl.parseExpression(expr), rootobject); return Ognl.getValue(Ognl.parseExpression(expr), context, rootobject); getvalue Ognl ognl.ognl: Ognl.getValue(Ognl.parseExpression(expr), context, rootobject); string JavaCC AST Context ognl assert "username", context user username "#hello + username" context hello Hi! #hello + username #hello OGNL # TestCase Group group = new Group("testGroup"); group.adduser(user); Object currentgroupusercount = getvalue(user,"group.allusers.size()",null); assertequals(new Integer(1),currentGroupUserCount); Map usercontext = new HashMap(); usercontext.put("requestuser","tttt"); Object hasuser = getvalue(user,"group.containuser( #requestuser )",usercontext); assertequals(boolean.false,hasuser); usercontext.put("requestuser","test"); hasuser = getvalue(user,"group.containuser( #requestuser )",usercontext); assertequals(boolean.true,hasuser); ognl this Object usercountstring = 19
getvalue(user,"group.allusers.size().tostring()",null); assertequals("1",usercountstring); usercountstring = getvalue(user,"group.allusers.size().(#this+1).tostring()",null); assertequals("2",usercountstring); ognl Map newname = new HashMap(); newname.put("newname","ttttttt"); getvalue(user,"username=#newname",newname); assertequals(user.getusername(),"ttttttt"); public void testsetvalue() throws OgnlException { User user = new User("test","123","a@a.com"); setvalue(user,"username",null,"test1"); assertequals(user.getusername(),"test1"); Group group = new Group("testGroup"); group.adduser(user); setvalue(user,"group.name",null,"testgoup1"); assertequals(group.getname(),"testgoup1"); root Context getvalue() OGNL OGNL java b B BigDecimals h H BigIntegers true false null 20
@class@member @org.erptao.flex.someclass@somestaticfiel @org.erptao.flex.someclass@somestaticmethod(args) List Array Map List {element1,element2,element3,.. list List public void testlist() throws OgnlException { User user = new User("test","123","a@a.com"); Object usernameinlist = getvalue(user,"username in {'123','456',null,'tttt'",null); assertequals(boolean.false,usernameinlist); usernameinlist = getvalue(user,"username in {'123','test',null,'tttt'",null); assertequals(boolean.true,usernameinlist); { 123 test null, ttt OGNL List Group group = new Group("test"); group.adduser(user); User anotheruser = new User("test1","123","a@a.com"); group.adduser(anotheruser); User justanotheruser = new User("test2","123","a@a.com"); group.adduser(justanotheruser); Object firstuser = getvalue(user, "group.alluserlist[0]",null); assertequals(user,firstuser); Object seconduser = getvalue(user, "group.alluserlist[1]",null); assertequals(anotheruser,seconduser); Array public void testarray() throws OgnlException { User user = new User("test", "123", "a@a.com"); Group group = new Group("test"); group.adduser(user); User anotheruser = new User("test1", "123", "a@a.com"); group.adduser(anotheruser); User justanotheruser = new User("test2", "123", "a@a.com"); group.adduser(justanotheruser); Object usernameinlist = 21
getvalue(user, "username in new String[] {'123','test',null,'tttt'", null); assertequals(boolean.true, usernameinlist); new ObjectType[] {. Object thirduser = getvalue(user,"group.alluserlist.toarray()[2]",null); assertequals(justanotheruser,thirduser); Map public void testmap() throws OgnlException { Map map = new HashMap(); getvalue(map,"putall(#{ 'foo' : 'foo value', 'bar' : 'bar value' )",null); assertequals(map.get("foo"),"foo value"); assertequals(map.get("bar"),"bar value"); #{ 'foo' : 'foo value', 'bar' : 'bar value' Map,map #{ key1:value1, key2:value2, (projection,selection) OGNL projection selection, selection collection.{xxx public void testporjectionandselection() throws OgnlException { User user = new User("test", "123", "a@a.com"); Group group = new Group("test"); group.adduser(user); User anotheruser = new User("test1", "123", "a@a.com"); group.adduser(anotheruser); User justanotheruser = new User("test2", "123", "a@a.com"); group.adduser(justanotheruser); List usernames = (List) getvalue(user,"group.alluserlist.{username",null); assertequals(usernames.size(),3); 22
assertequals(usernames.get(0),"test"); assertequals(usernames.get(1),"test1"); assertequals(usernames.get(2),"test2"); { #this User nullemailuser = new User("test2", "123", null); group.adduser(nullemailuser); List useremaildomains = (List) getvalue(user,"group.alluserlist.{#this.email==null? null : email.substring(email.indexof('@')+1)",null); assertequals(useremaildomains.size(),4); assertequals(useremaildomains.get(0),"a.com"); assertequals(useremaildomains.get(1),"b.com"); assertequals(useremaildomains.get(2),"c.com"); assertequals(useremaildomains.get(3),null); group.alluserlist.{#this.email==null? null : email.substring(email.indexof('@')+1) user email null null domain email domain Selection collection.{x YYY X? ^ $ List nonnullemailusers = (List)getValue(user,"group.allUserList.{? #this.email!=null",null); assertequals(nonnullemailusers.size(),3); List firstnonnullemailuser = (List)getValue(user,"group.allUserList.{^ #this.email!=null",null); assertequals(firstnonnullemailuser.size(),1); assertequals(firstnonnullemailuser.get(0),user); List lastnonnullemailuser = (List)getValue(user,"group.allUserList.{$ #this.email!=null",null); assertequals(lastnonnullemailuser.size(),1); assertequals(lastnonnullemailuser.get(0),justanotheruser); selection projection SQL List nonnulluserdomains = (List) getvalue(user,"group.alluserlist.{? #this.email!=null.{#this.email.substring(email.indexof('@')+1)",nul 23
l); assertequals(nonnulluserdomains.size(),3); assertequals(nonnulluserdomains.get(0),"a.com"); assertequals(nonnulluserdomains.get(1),"b.com"); assertequals(nonnulluserdomains.get(2),"c.com"); OGNL Xwork OGNL MVC ValueStack XWork Model-2 MVC C View JSP Tag struts tag <logic:iterate id="relative" name="myformbean" property= relatives > <bean:write name="relative" property="value"/> </logic:iterate> webwork <webwork:iterator value= relatives > <webwork:property value= name /> </webwork:iterator> struts tag id bean bean tag Struts nested tag bean tag nested:xx Webwork nested Xwork ValueStack OgnlValueStack OgnlValueStack OGNL root OGNL TestCase OgnlValueStack stack = new OgnlValueStack(); User user = new User("test", "123", "a@a.com"); stack.push(user); dumpstack(stack.getroot()); Object name = stack.findvalue("username"); 24
assertequals("test", name); OgnlValueStack, user push dumpstack username OgnlValueStack OGNL root CompundRoot dump: private void dumpstack(compoundroot root) { System.out.println("---stack top---"); for(int i=0;i<root.size();i++) { System.out.println(root.get(i).toString()); System.out.println("---stack bottom---"); dump ---stack top--- [username:test] ---stack bottom--- stack.getcontext().put("hello", "Hi! "); Object helloname = stack.findvalue("#hello+username"); assertequals("hi! test", helloname); Group Group group = new Group("testGroup"); stack.push(group); dumpstack(stack.getroot()); name = stack.findvalue("name"); assertequals("testgroup", name); ---stack top--- [groupname:testgroup] [username:test] ---stack bottom--- name group name = stack.findvalue("username"); assertequals("test", name); stack Group username ValueStack User username Group Group anothergroup = new Group("testGroup1"); stack.push(anothergroup); dumpstack(stack.getroot()); ---stack top--- [groupname:testgroup1] [groupname:testgroup] [username:test] 25
---stack bottom--- testgroup name name = stack.findvalue("name"); assertequals("testgroup1", name); name = stack.findvalue("[1].name"); assertequals("testgroup", name); ActionContext OgnlValueStack Interceptor ParametersInterceptor staticparametersinterceptor ChainingInterceptor ModelDrivenInterceptor ValidationInterceptor Xwork AOP EL XWork 26
Xwork+Hessian 27