Struts2 Action处理请求参数:属性驱动和模型驱动 图片看不了?点击切换HTTP 返回上层
在 Struts2 框架中,页面的请求数据和 Action 有两种基本的对应方式,分别是字段驱动(FieldDriven,也称为属性驱动)方式和模型驱动(ModelDriver)方式。本节将针对这两种 Action 处理请求参数的方式进行详细讲解。
在上述 Action 类的代码中,定义了两个字符串字段 username 和 password,这两个字段分别用于对应页面上的用户名和密码这两个表单域。
为了解决这一问题,我们可以把属性的 getter/setter 方法从 Action 中提取出来单独作为一个域对象,并在相应的 Action 中直接使用这个域对象。此种方式中的域对象一般以 JavaBean 的形式实现,JavaBean 中所封装的属性要和页面中表单的属性一一对应。此时 JavaBean 将成为数据传递的载体,并可以在其他 Action 中使用。
下面通过具体的案例演示域对象字段的驱动方式的使用。
1)在 struts2Demo02 项目的 src 目录下创建一个名称为 com.mengma.domain 的包,在包中创建一个 User 类,编写代码后如下所示。
2)在 com.mengma.action 包中创建一个名称为 UserLoginAction 的类,在类中定义一个 User 类型的域模型以及其 getter 和 setter 方法,如下所示。
在 UserLoginAction 中,首先声明了一个 User 类型的 user 对象,以及其 getter 和 setter 方法,然后在 execute() 方法中,获取了 ActionContext 对象以访问 Servlet API,下面通过对比从 User 对象获取的用户名和密码来判断是否登录成功。
需要注意的是,在使用域对象的属性驱动方式传值时,如果 JSP 页面是负责取值的,那么取值的格式必须为“对象名.属性名”;如果 JSP 页面是负责传值的,那么传值的格式可以为“模型对象名.属性名”,也可以直接是“属性名”。
3)分别创建登录页面 userLogin.jsp、登录成功页面 loginSuccess.jsp 和登录失败页面 loginError.jsp,如文件 userLogin.jsp、loginSuccess.jsp 和 loginError.jsp 所示。
4)在配置文件 struts.xml 中的 <package> 元素中添加 UserLoginAction 的信息,添加内容如下所示:
5)部署 struts2Demo02 项目到 Tomcat 服务器并启动服务器,在浏览器的地址栏中输入地址 http://localhost:8080/struts2Demo02/userLogin.jsp 访问 userLogin.jsp,浏览器的显示结果如图 1 所示。
在图 1 中输入正确的用户名“admin”和密码“123456”,单击【登录】按钮后,浏览器的显示结果如图 2 所示;如果用户名或密码错误,则进入错误页面,如图 3 所示。

图 1 登录页面

图 2 登录成功页面

图 3 错误页面
模型驱动方式要求 Action 需要通过实现 ModelDriven 接口接收请求参数,并且要重写 getModel() 方法。getModel() 方法返回的就是 Action 所使用的数据模型对象。
与属性驱动中直接使用域对象字段驱动方式的数据传递类似,模型驱动方式也是通过 JavaBean 模型进行数据传递的。只要是普通的 JavaBean,就可以充当模型部分,并且 JavaBean 中所封装的属性要与表单的属性一一对应,JavaBean 就是数据传递的载体。
使用模型驱动方式时,Action 类中通过 getModel() 方法获取模型,其示例代码如下所示:
使用模型驱动时,其对应的表单页面也要做相应调整,调整后的代码片段如下所示:
从上述代码中可以看出,使用 ModelDriver 的方式后,表单中的文本域名称已经不需要添加 user 前缀,页面上的 username 会自动对应到这个 Model 的 username 属性。
与属性驱动相比,模型驱动不需要在 Action 类中定义与表单元素一一对应的所有属性及其各属性的 getter 和 setter 方法,这减少了 Action 类中的代码量。在项目应用中具体使用哪种驱动方法,现给出以下几点建议。
1)要统一整个系统中 Action 的驱动方法,即要么都使用属性驱动,要么都使用模型驱动。
2)如果持久层对象与表单中的属性是一一对应的关系,那么建议使用模型驱动,因为模型驱动方法使 Action 类中的代码更加整洁。
3)如果持久层对象与表单中的属性不是一一对应的关系,那么建议使用属性驱动,因为不是一一对应的关系时,系统中需要提供两个 JavaBean(一个对应表单提交的数据,一个用于持久层对象)。
总之,属性驱动的方法和模型驱动的方法各有优缺点,在实际开发中,需要根据项目实际情况选择使用哪种驱动方式。
属性驱动
属性驱动是指在 Action 中通过字段属性进行与页面之间的数据传递,通常使用时会包括两种情况:一种是与基本数据类型的属性对应,另一种是直接使用域对象。1. 基本数据类型字段驱动方式的数据传递
在 Struts2 中,可以直接在 Action 中定义各种 Java 基本数据类型的字段,使这些字段与表单数据相对应,并利用这些字段进行数据传递,如下面的代码所示:1 2 3 4 5 6 7 8 | public class UserAction extends ActionSupport { private String username; // 用户名 private String password ; // 密码 // 此处省略两个属性的getter和setter方法 private String execute () throws Exception { return SUCCESS; } } |
2. 直接使用域对象字段驱动方式的数据传递
在基本数据类型字段驱动方式中,如果传入的数据很多,那么 Action 的属性也会变得很多,再加上属性对应的 getter/setter 方法,势必会导致 Action 非常臃肿。为了解决这一问题,我们可以把属性的 getter/setter 方法从 Action 中提取出来单独作为一个域对象,并在相应的 Action 中直接使用这个域对象。此种方式中的域对象一般以 JavaBean 的形式实现,JavaBean 中所封装的属性要和页面中表单的属性一一对应。此时 JavaBean 将成为数据传递的载体,并可以在其他 Action 中使用。
下面通过具体的案例演示域对象字段的驱动方式的使用。
1)在 struts2Demo02 项目的 src 目录下创建一个名称为 com.mengma.domain 的包,在包中创建一个 User 类,编写代码后如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.mengma.domain; public class User { private String username; private String password ; // username的getter和setter方法 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } // password 的getter和setter方法 public String getPassword() { return password ; } public void setPassword(String password ) { this. password = password ; } } |
1 2 3 4 5 6 7 8 9 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 | package com.mengma. action ; import com.mengma.domain. User ; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class UserLoginAction extends ActionSupport { private User user ; // 定义 User 属性 // user 属性的getter和setter方法 public User getUser() { return user ; } public void setUser( User user ) { this. user = user ; } public String execute () throws Exception { // 获取Context对象 ActionContext context = ActionContext.getContext(); if ( "admin" .equals( user .getUsername()) && "123456" .equals( user .getPassword())) { // 将用户名和密码放入session中 context.getSession().put( "username" , user .getUsername()); context.getSession().put( "password" , user .getPassword()); return SUCCESS; } else { context.getSession().put( "error" , "用户名或密码错误!" ); return ERROR; } } } |
需要注意的是,在使用域对象的属性驱动方式传值时,如果 JSP 页面是负责取值的,那么取值的格式必须为“对象名.属性名”;如果 JSP 页面是负责传值的,那么传值的格式可以为“模型对象名.属性名”,也可以直接是“属性名”。
3)分别创建登录页面 userLogin.jsp、登录成功页面 loginSuccess.jsp 和登录失败页面 loginError.jsp,如文件 userLogin.jsp、loginSuccess.jsp 和 loginError.jsp 所示。
① userLogin.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <%@ page language= "java" contentType= "text/html; charset=utf-8" pageEncoding= "utf-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head> <title>用戶登录页面</title> <style type= "text/css" > input[type=text],input[type= password ]{width:150px} </style> </head> <body> <div align= "center" > <form action = "login" method= "post" > 用户名:<input type= "text" name = "username" /><br/> 密 码:<input type= "password" name = "password" /><br/> <input type= "reset" value= "重置" /> <input type= "submit" value= "登录" /> </form> </div> </body> </html> |
② loginSuccess.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <%@ page language= "java" contentType= "text/html; charset=utf-8" pageEncoding= "utf-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head> <title>用戶登录成功页面</title> </head> <body> <p align= "center" > 您的用戶名是<%=request.getAttribute( "user.username" ) %> <br/> 密码是<%=request.getAttribute( "user.password" ) %> </p> </body> </html> |
③ loginError.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <%@ page language= "java" contentType= "text/html; charset=utf-8" pageEncoding= "utf-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head> <title>错误页面</title> </head> <body> <p align= "center" > ${error }<br/> <a href= "userLogin.jsp" >请单击此链接返回登录页面重新登录</a> </p> </body> </html> |
1 2 3 4 | < action name = "userlogin" class= "com.mengma.action.UserLoginAction" > <result name = "success" >/loginSuccess.jsp</result> <result name = "error" >/loginError.jsp</result> </ action > |
在图 1 中输入正确的用户名“admin”和密码“123456”,单击【登录】按钮后,浏览器的显示结果如图 2 所示;如果用户名或密码错误,则进入错误页面,如图 3 所示。

图 1 登录页面

图 2 登录成功页面

图 3 错误页面
模型驱动
在 Struts2 中,Action 还有另外一种方式处理请求参数,称为模型驱动(ModelDriven)。模型驱动方式要求 Action 需要通过实现 ModelDriven 接口接收请求参数,并且要重写 getModel() 方法。getModel() 方法返回的就是 Action 所使用的数据模型对象。
与属性驱动中直接使用域对象字段驱动方式的数据传递类似,模型驱动方式也是通过 JavaBean 模型进行数据传递的。只要是普通的 JavaBean,就可以充当模型部分,并且 JavaBean 中所封装的属性要与表单的属性一一对应,JavaBean 就是数据传递的载体。
使用模型驱动方式时,Action 类中通过 getModel() 方法获取模型,其示例代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package com.mengma. action ; import com.mengma.domain. User ; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class LoginAction extends ActionSupport implements ModelDriven< User > { private User user = new User (); public User getModel() { return user ; } public String execute () throws Exception { return SUCCESS; } } |
1 2 3 4 5 | <form action = "loginAction" method= "post" name = "form1" > 用户名:<input type= "text" name = "username" /><br/> 密码:<input type= "password" name = "password" /><br/> <input type= "submit" value= "登录" /> </form> |
与属性驱动相比,模型驱动不需要在 Action 类中定义与表单元素一一对应的所有属性及其各属性的 getter 和 setter 方法,这减少了 Action 类中的代码量。在项目应用中具体使用哪种驱动方法,现给出以下几点建议。
1)要统一整个系统中 Action 的驱动方法,即要么都使用属性驱动,要么都使用模型驱动。
2)如果持久层对象与表单中的属性是一一对应的关系,那么建议使用模型驱动,因为模型驱动方法使 Action 类中的代码更加整洁。
3)如果持久层对象与表单中的属性不是一一对应的关系,那么建议使用属性驱动,因为不是一一对应的关系时,系统中需要提供两个 JavaBean(一个对应表单提交的数据,一个用于持久层对象)。
总之,属性驱动的方法和模型驱动的方法各有优缺点,在实际开发中,需要根据项目实际情况选择使用哪种驱动方式。