所谓ModelDriven,意思是直接把实体类当成页面数据的收集对象。比如,有实体类User如下:
package cn.com.leadfar.struts2.actions;
public class User {
private int id;
private String username;
private String password;
private int age;
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
|
假如要写一个Action,用来添加User。
第一种做法是直接在Action中定义所有需要的属性,然后在JSP中直接用属性名称来提交数据:
UserAction:
public class UserAction {
private int id;
private String username;
private String password;
private int age;
private String address;
public String add(){
User user = new User();
user.setId(id);
user.setUsername(username);
user.setPassword(password);
user.setAge(age);
user.setAddress(address);
new UserManager().addUser(user);
return "success";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
|
add_input.jsp:
<form action="test/user.action" method="post">
<input type="hidden" name="method:add">
username:<input type="text" name="username"> <br/>
password:<input type="text" name="password"> <br/>
age:<input type="text" name="age"> <br/>
address:<input type="text" name="address"> <br/>
<input type="submit" name="submit" value="添加用户">
</form> <br/>
|
上述做法不好之处是:如果实体类的属性非常多,那么Action中也要定义相同的属性。
第二种做法是将User对象定义到UserAction中,然后在JSP中通过user属性来给user赋值:
UserAction:
public class UserAction {
private User user;
public String add(){
new UserManager().addUser(user);
return "success";
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
|
add_input.jsp:
<form action="test/user.action" method="post">
<input type="hidden" name="method:add">
username:<input type="text" name="user.username"> <br/>
password:<input type="text" name="user.password"> <br/>
age:<input type="text" name="user.age"> <br/>
address:<input type="text" name="user.address"> <br/>
<input type="submit" name="submit" value="添加用户">
</form> <br/>
|
这种做法不好的地方是:JSP页面上表单域中的命名变得太长
第三种做法是利用ModelDriven机制,让UserAction实现一个ModelDriven接口,同时实现接口中的方法:getModel()。如下所示:
public class UserAction implements ModelDriven{
private User user;
@Override
public Object getModel() {
if(user == null){
user = new User();
}
return user;
}
public String add(){
new UserManager().addUser(user);
return "success";
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
|
JSP的代码如下:
<form action="test/user.action" method="post">
<input type="hidden" name="method:add">
username:<input type="text" name="username"> <br/>
password:<input type="text" name="password"> <br/>
age:<input type="text" name="age"> <br/>
<input type="submit" name="submit" value="添加用户">
</form> <br/>
|
可见,第三种做法是比较好的,Action和JSP写起来都比较简单。
ModelDriven背后的机制就是ValueStack。界面通过:username/age/address这样的名称,就能够被直接赋值给user对象,这证明user对象正是ValueStack中的一个root对象!
那么,为什么user对象会在ValueStack中呢?它是什么时候被压入ValueStack的呢?答案是:ModelDrivenInterceptor(关于Interceptor的概念,请参考后续章节的说明)。ModelDrivenInterceptor是缺省的拦截器链的一部分,当一个请求经过ModelDrivenInterceptor的时候,在这个拦截器中,会判断当前要调用的Action对象是否实现了ModelDriven接口,如果实现了这个接口,则调用getModel()方法,并把返回值(本例是返回user对象)压入ValueStack。
请看ModelDrivenInterceptor的代码:
public class ModelDrivenInterceptor extends AbstractInterceptor {
protected boolean refreshModelBeforeResult = false;
public void setRefreshModelBeforeResult(boolean val) {
this.refreshModelBeforeResult = val;
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven) action;
ValueStack stack = invocation.getStack();
Object model = modelDriven.getModel();
if (model != null) {
stack.push(model);
}
if (refreshModelBeforeResult) {
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}
|
从ModelDrivenInterceptor中,即可以看到model对象被压入ValueStack中!
其中的refreshModelBeforeResult是为了接下来描述的一个问题而提供的解决方法。
假设我们要更新一个实体对象,那么第一步首先是打开更新界面,请看下述模拟打开更新界面的代码:
public class UserAction implements ModelDriven{
private User user;
@Override
public Object getModel() {
if(user == null){
user = new User();
//user.setUsername("这是原来的User对象");
}
return user;
}
public String updateInput(){
//根据ID,查询数据库,得到User对象
user = new UserManager().findUserById(user.getId());
return "update_input";
}
|
上述代码中,new UserManager().findUserById(user.getId());这一行,将从数据库中查询相应的记录,同时转换为User对象返回。而return “update_input”;将转向更新显示页面。
更新页面如下:
<form action="test/user.action" method="post">
<input type="hidden" name="method:update">
id:<input type="text" name="id" value="<s:property value="id"/>"> <br/>
username:<input type="text" name="username" value="<s:property value="username"/>"> <br/>
password:<input type="text" name="password" value="<s:property value="password"/>"> <br/>
age:<input type="text" name="age" value="<s:property value="age"/>"> <br/>
address:<input type="text" name="address" value="<s:property value="address"/>"> <br/>
<input type="submit" name="submit" value="更新用户">
</form> <br/>
|
上述代码运行起来之后,你在更新界面上将看不到数据(id属性有值,其它属性无显示)。关键的原因是在执行到updateInput之前,user对象(在getMode()方法中创建的对象)被压到ValueStack中,这时候,UserAction和ValueStack都指向同一个user对象;但紧接着,UserAction中的user被一个新的user对象覆盖,这时候,UserAction和ValueStack不再指向同一个user对象!ValueStack中是旧的user对象,而UserAction中是新的user对象!我们在JSP中,直接通过username/address等直接访问,当然是要访问ValueStack中的旧user对象,所以它们的属性都是空的(id属性除外)!
理解上述问题很重要,当你理解了问题,那么问题的解决方法就可以有很多了:
比如,你可以把新对象的属性拷贝到旧对象上;比如,你可以先把旧对象从ValueStack中移除,然后再把新对象压入ValueStack等……
在最新的struts2版本中,ModelDrivenInterceptor提供了一个配置参数:refreshModelBeforeResult,只要将它定义为true,上述问题就被解决了!struts2的解决方案就是:先把旧的model对象从ValueStack中移除,然后再把新的model对象压入ValueStack!
分享到:
相关推荐
### Struts2学习笔记知识点梳理 #### 一、Struts2框架概述 - **背景**:Struts2作为Struts1的升级版本,融合了WebWork框架的优点,由Apache基金会维护,是一个开源、免费的MVC框架。尽管随着时间的推移,Spring MVC...
在Struts2中,学习笔记通常会涵盖以下几个关键概念: 1. **源代码查看和Javadoc**:开发者可以通过查看源代码来理解Struts2的工作原理,而Javadoc则提供了API文档,帮助理解类和方法的功能。 2. **包(Package)和...
### Struts2框架学习笔记整理 #### 一、Struts2框架概述 ##### 1.1 Struts2框架定义 Struts2是一个基于MVC(Model-View-Controller)架构模式的开源Java web应用框架,它能够帮助开发者构建可扩展且易于维护的...
1. **Action和Result**: Struts2中的Action类是业务逻辑的载体,负责处理用户请求。Action执行完成后,会返回一个Result,Result定义了如何展示结果到用户,比如跳转到一个新的页面或者显示JSON数据。 2. **拦截器...
01 Struts2-Action 5 一、 Struts作用: 5 二、 搭建Struts2的运行环境: 5 三、 Namespace 6 四、 标签 6 五、 Action 6 六、 路径问题的说明 8 七、 Action的动态调用方法 8 八、 Action通配符(wildcard)的配置 9 ...
### Struts2_Action 学习笔记与通配符配置详解 #### 一、Struts2简介及简单配置 Struts2是一个基于Java EE平台的开源Web应用框架,它继承了Struts1的优点,并在此基础上进行了大量的改进。Struts2的核心功能之一是...
在"【张冰Struts2学习笔记】0202_Struts2的三种接收用户输入的方法"中,我们主要探讨的是如何在Struts2中有效地获取并处理用户提交的数据。以下是对这三种方法的详细解析: ### 1. 使用Action属性 Struts2的核心是...
在Struts2中,拦截器扮演着至关重要的角色,它们是实现业务逻辑和控制流程分离开来的重要组件。本篇将深入探讨Struts2的核心拦截器以及其工作原理。 在Struts2中,拦截器是一个实现了`Interceptor`接口的类,它通过...
4. **文件上传**:在Struts2中,可以方便地处理文件上传。使用`org.apache.struts2.dispatcher.multipart.MultiPartRequest`类,结合Action中的属性字段,可以轻松实现文件上传功能,并对上传的文件进行合法性检查和...
1. **Action类与结果类型**:在Struts2中,Action类是业务逻辑的载体,它处理用户请求并返回结果。每个Action类对应一个或多个结果,结果类型定义了如何处理Action执行后的响应,如转发、重定向等。 2. **配置文件*...
在Struts2框架的学习中,`Action`接口与`ActionSupport`类是核心组件,用于处理用户请求并返回相应的结果。本篇笔记将深入探讨这两个关键概念,以及它们在实际开发中的应用。 首先,`Action`接口是Struts2框架中...
在这个“Struts2五种数据封装Demo”中,我们将深入探讨Struts2的数据封装机制,以及如何通过配置文件来操作Servlet的三大核心对象——Request、Session和Application。同时,我们还将了解如何从表单中获取数据并进行...
4. **Interceptor**:拦截器是Struts2中非常重要的一个概念,它可以在Action执行前后进行一系列操作,比如权限验证、事务控制等。 5. **Result**:定义了Action执行后返回的结果类型,可以是页面跳转、JSON数据返回...
本篇学习笔记主要关注的是ActionForm,它是Struts框架中用于处理用户请求的核心组件之一。 ActionForm是Struts中用于接收和验证用户输入的数据的类。当用户通过表单提交数据时,这些数据会被封装到一个ActionForm...
8. **ActionContext**:ActionContext是Struts2中的上下文对象,它封装了请求、响应以及应用范围内的数据,为Action提供了一种访问环境信息的方式。 9. **ActionSupport类**:这是Action类的一个基础实现,包含了...
这篇学习笔记将对Struts的核心概念、工作原理以及其在实际开发中的应用进行详细介绍。 一、Struts的基本概念 1. MVC模式:MVC模式是一种软件设计模式,用于将业务逻辑(Model)、用户界面(View)和控制逻辑...
Struts2 的出现是为了解决 Struts 1 中存在的问题,如过多的代码编写、类爆炸现象以及单元测试的困难。Struts2 引入了许多改进,包括更灵活的配置、更少的样板代码以及更好的测试支持。 在开始使用 Struts2 之前,...
在本文中,我们将深入探讨Struts2的主要特点、与Struts1的对比,以及如何创建一个简单的Struts2 HelloWorld应用。 首先,让我们看看Struts2与Struts1之间的关键区别: 1. **Action实例管理**: - 在Struts1中,...
SSH(Secure Shell)是一种...通过学习和分析这个示例,开发者可以更好地理解如何在Struts2中利用`ModelDriven`和`Prepareable`接口来提高代码的组织和效率。同时,这也有助于理解和实践MVC模式在实际项目中的应用。