Struts2中数据封装机制
Struts2当中数据封装的三种机制:属性驱动、标签驱动、模型驱动。下面来一一介绍。
一、属性驱动
1、需要提供对应属性的set方法进行数据的封装。
2、表单的哪些属性需要封装数据,那么在对应的Action类中提供该属性的set方法即可。
3、表单中的数据提交,最终找到Action类中的setXxx的方法,最后赋值给全局变量。
4、注意:Struts2的框架采用的拦截器完成数据的封装。
5、注意:这种方式不是特别好:因为属性特别多,提供特别多的set方法,而且还需要手动将数据存入到对象中.
6、注意:这种情况下,Action类就相当于一个JavaBean,就没有体现出MVC的思想,Action类又封装数据,又接收请求处理,耦合性较高。
这便是struts2的数据封装中的属性封装机制,只需在Action中设置当前表单中要提交的数据的属性(注意这里可能会存在属性类型的转换问题,这个例子只涉及到String类型的属性,同时表单中提交的数据也是String类型的。所有不牵扯到类型转换问题)待表单提交过来数据时便直接会被封装到对应的属性中去。事实上这是通过java的反射机制实现的。
二、标签驱动
可以通过在页面上使用OGNL表达式进行数据封装。想要通过Struts2中的标签来实现表单数据的自动封装的前提是得在表单中加入Struts2标签支持。
<%@taglib prefix="s" uri="/struts-tags" %>
1、在页面中使用OGNL表达式进行数据的封装,就可以直接把属性封装到某一个JavaBean的对象中。
2、在页面中定义一个JavaBean,并且提供set方法:例如:private User user;
3、页面中的编写发生了变化,需要使用OGNL的方式,表单中的写法:<input type="text" name="user.username">
4、注意:只提供一个set方法还不够,如果没有user实例化,必须还需要提供user属性的get和set方法,先调用get方法,判断一下是否有user对象的实例对象,如果没有,调用set方法把拦截器创建的对象注入进来。
使用模型驱动的方式,也可以把表单中的数据直接封装到一个JavaBean的对象中,并且表单的写法和之前的写法没有区别!编写的页面不需要任何变化,正常编写name属性的值。
模型驱动的编写步骤
* 手动实例化JavaBean,即:private User user = new User();
* 相应的Action必须实现ModelDriven<T>接口,实现getModel()的方法,在getModel()方法中返回user即可!!
上述方式实现的大致原理如下:
* 当请求发送到action之前,调用我们自定义的Action类中的getModel方法,获取封装表单数据的javaBean对象
* 获得该对象之后,我们便可以获得对应的类类型
* 利用反射可以获取到类中的属性列表
* 通过request.getParameterNames()可以获取表单中的name列表
* 判断name值和属性名称,一致的情况下,反射调用属性的set方法来给对应的属性值设置参数
* 最后完成完成数据的封装
四、Action对集合对象的封装
1、把数据封装到Collection中
因为Collection接口都会有下标值,所有页面的写法会有一些区别,注意:
<input type="text" name="products[0].name" />
在Action中的写法,需要提供products的集合,并且提供get和set方法
2、把数据封装到Map中
Map集合是键值对的形式,页面的写法
<input type="text" name="map['one'].name" />
Action中提供map集合,并且提供get和set方法。
**在Action中不推荐使用模型驱动的方式来封装数据到集合中。
一、属性驱动
1、需要提供对应属性的set方法进行数据的封装。
2、表单的哪些属性需要封装数据,那么在对应的Action类中提供该属性的set方法即可。
3、表单中的数据提交,最终找到Action类中的setXxx的方法,最后赋值给全局变量。
4、注意:Struts2的框架采用的拦截器完成数据的封装。
5、注意:这种方式不是特别好:因为属性特别多,提供特别多的set方法,而且还需要手动将数据存入到对象中.
6、注意:这种情况下,Action类就相当于一个JavaBean,就没有体现出MVC的思想,Action类又封装数据,又接收请求处理,耦合性较高。
具体来看一个action的实现:
public class LoginActio extends ActionSupport{ //Action需要处理表单提交的两个数据:用户名和密码。 //此处的属性值应与表单中的name值一致 //并且必须得有对应的set和get方法 private String username;//与表单的相应name一致 private String password; @Override public execute()throws Exception{ System.out.println("username="+username); System.out.println("password="+password); return"success"; } public String getUsername() { return username; } publicvoid setUsername(String username) { this.username= username; } public String getPassword() { return password; } publicvoid setPassword(String password) { this.password= password; } }
表单提交格式如下:
<form action="LoginActio" method="post"> <input type="text" name="username"> <input type="text" name="password"> <button type="submit">提交</button> </form>
在配置完成后便可以将表单中form中的的action属性改为当前的action的name(注意后缀是.action,也可自行设置,使用constant属性)。然后启动项目转到相应页面中输入用户名和密码后可以看到在控制台中已经打印出来了相关信息。
但是我们却并没有在代码中做过任何相关的数据封装操作,但是对应的数据却已经被封装到属性当中了。这便是struts2的数据封装中的属性封装机制,只需在Action中设置当前表单中要提交的数据的属性(注意这里可能会存在属性类型的转换问题,这个例子只涉及到String类型的属性,同时表单中提交的数据也是String类型的。所有不牵扯到类型转换问题)待表单提交过来数据时便直接会被封装到对应的属性中去。事实上这是通过java的反射机制实现的。
二、标签驱动
可以通过在页面上使用OGNL表达式进行数据封装。想要通过Struts2中的标签来实现表单数据的自动封装的前提是得在表单中加入Struts2标签支持。
<%@taglib prefix="s" uri="/struts-tags" %>
1、在页面中使用OGNL表达式进行数据的封装,就可以直接把属性封装到某一个JavaBean的对象中。
2、在页面中定义一个JavaBean,并且提供set方法:例如:private User user;
3、页面中的编写发生了变化,需要使用OGNL的方式,表单中的写法:<input type="text" name="user.username">
4、注意:只提供一个set方法还不够,如果没有user实例化,必须还需要提供user属性的get和set方法,先调用get方法,判断一下是否有user对象的实例对象,如果没有,调用set方法把拦截器创建的对象注入进来。
具体的Action实例如下:
//省略包导入 /** * 动态参数封装:属性驱动 * OGNL * 所有的封装动态参数操作:都是一个叫params的拦截器封装的。 */ public class TestAction extends ActionSupport { private User user = new User();//User是一个封装好了的javaBean模型 public String execute(){ System.out.println("name is "+user.getName()+" and age is "+user.getAge()); return SUCCESS; } public User getUser() { System.out.println("getUser"); return user; } public void setUser(User user) { System.out.println("setUser"); this.user = user; } }
form表单提交如下:
<%--动态参数封装:对象导航映射 此时表单元素的name属性取值已经不是一个普通的字符串了。 而是一个OGNL表达式。 OGNL:Object Graphic Navigationg Language 对象 图 导航 语言 --%> <form action="${pageContext.request.contextPath}/testAction.action" method="post"> 用户名:<input type="text" name="user.name"/><br/> 年龄:<input type="text" name="user.age"/><br/> <input type="submit" value="提交"/> </form>
还可以使用struts2的标签:
<%--这里定位action的方式是和配置struts.xml差不多,使用namespace和action名--%> <s:form namespace="/normal" action="testAction.action" method="POST"> <%--name属性也必须这样写--%> <s:textfield name="user.name"/> <s:password name="user.passwd"/> <s:submit>提交</s:submit> </s:form>
使用模型驱动的方式,也可以把表单中的数据直接封装到一个JavaBean的对象中,并且表单的写法和之前的写法没有区别!编写的页面不需要任何变化,正常编写name属性的值。
模型驱动的编写步骤
* 手动实例化JavaBean,即:private User user = new User();
* 相应的Action必须实现ModelDriven<T>接口,实现getModel()的方法,在getModel()方法中返回user即可!!
下面看一个Action实例:
// 实现ModelDriven接口,泛型中写了我们封装的数据,也就是我们自己编写的javaBean对象User public class StudentAction extends ActionSupport implements ModelDriven<User> { // 我们必须实例化我们封装的数据,struts2会直接使用我们的这个类,将数据set进去 // 所以我们必须在这个类中写get和set方法 private User u = new User();//实例化javaBean // 实现此接口必须实现的方法,返回我们封装的数据,也就是javaBean对象 @Override public User getModel() { return u; } @Override // 这种方法我们完全没有设置什么,但是struts2依然为我们将数据放了进去 // 这里其实是java反射的应用 public String execute() throws Exception { System.out.println(u.getName()); System.out.println(u.getPasswd()); return "success"; } }
上述方式实现的大致原理如下:
* 当请求发送到action之前,调用我们自定义的Action类中的getModel方法,获取封装表单数据的javaBean对象
* 获得该对象之后,我们便可以获得对应的类类型
* 利用反射可以获取到类中的属性列表
* 通过request.getParameterNames()可以获取表单中的name列表
* 判断name值和属性名称,一致的情况下,反射调用属性的set方法来给对应的属性值设置参数
* 最后完成完成数据的封装
四、Action对集合对象的封装
1、把数据封装到Collection中
因为Collection接口都会有下标值,所有页面的写法会有一些区别,注意:
<input type="text" name="products[0].name" />
在Action中的写法,需要提供products的集合,并且提供get和set方法
2、把数据封装到Map中
Map集合是键值对的形式,页面的写法
<input type="text" name="map['one'].name" />
Action中提供map集合,并且提供get和set方法。
**在Action中不推荐使用模型驱动的方式来封装数据到集合中。