odelDriven

为什么需要ModelDriven

所谓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背后的机制?

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中请求参数的接收方式和ModelDriven机制及其运用的更多相关文章

  1. 十一、Struts2封装请求参数的方式

    十一.Struts2封装请求参数的方式 方式一.Action 本身作为model对象,通过成员setter封装(一个名字为params的拦截器干的) 注意:表单中的名称要和动作类中的名称一致(这是必须 ...

  2. struts2之请求参数接收

    struts2之请求参数接收 1. 采用基本类型接受请求参数(get/post)在Action类中定义与请求参数同名的属性,struts2便能自动接收请求参数并赋予给同名的属性.请求路径:http:/ ...

  3. struts2接受请求参数

    https://blog.csdn.net/y249839817/article/details/77702745 https://blog.csdn.net/nthack5730/article/d ...

  4. Jquery Datatables 请求参数及接收参数处理

    Jquery Datatables 请求参数及接收参数处理 /** * Created by wb-wuyifu on 2016/8/9. */ /** * Created by wb-wuyifu ...

  5. SpringMVC之请求参数的获取方式

    转载出处:https://www.toutiao.com/i6510822190219264516/ SpringMVC之请求参数的获取方式 常见的一个web服务,如何获取请求参数? 一般最常见的请求 ...

  6. SpringMVC请求参数的获取方式

    一.GET请求参数获取 1. 通过HttpServletRequest获取参数 2. 直接方法参数获取 3. RequestParam注解方式获取请求参数 4. Bean方式获取参数 5. Model ...

  7. struts2中,Action通过什么方式获得用户从页面输入的数据,又是通过什么方式把其自身的数据传给视图的?

    struts2中,Action通过什么方式获得用户从页面输入的数据,又是通过什么方式把其自身的数据传给视图的? 解答: 1)可以直接通过与表单元素相同名称的数据成员(需要存在符合命名规范set和get ...

  8. struts2获取请求参数的三种方式及传递给JSP参数的方式

    接上一篇文章 package test; import com.opensymphony.xwork2.ActionSupport; import javax.servlet.http.*; impo ...

  9. jmeter脚本中请求参数获取的几种方式

     a.从数据库获取: 譬如接口请求参数中id的值,我需要从数据库获取,如下设置: 先设置jdbc connection configuration,然后设置JDBC b.从CSV获取: 获取CSV文件 ...

随机推荐

  1. powerDesigner 报Unable to connect SQLState=08004 解决方法

    在使用PowerDesigner配置数据库连接(configure connections)的时候,点击Test connection之后弹出Unable to connect SQLState=08 ...

  2. 在IIS8添加WCF服务支持

    最近在做Silverlight,Windows Phone应用移植到Windows 8平台,在IIS8中测试一些传统WCF服务应用,发现IIS8不支持WCF服务svc请求,后来发现IIS8缺少对WCF ...

  3. 关于SoCFPGA 编译问答

    1.在Qsys里面添加了一个新的组件(不是hps里面的东西),挂在Avalon总线上,如添加了一个新ADC组件,是否需要重新编译dtb. 答:  不需要. 2.修改了相关Qsys里面的东西,是否也需要 ...

  4. 转:LoadRunner负载测试之Windows常见性能计数器,分析服务器性能瓶颈

    发布于2012-10-8,来源:博客园 监测对象 System(系统) l %Total Processor Time 系统中所有处理器都处于繁忙状态的时间百分比,对于多处理器系统来说,该值可以反映所 ...

  5. Linux字符界面下用户账户的设置

    在Linux系统字符界面下创建.修改以及删除用户账户主要使用useradd,usermod和userdel这3个命令. 一.创建用户账户 创建用户账户就是在系统中创建一个新账户,然后为新账户分配用户U ...

  6. lintcode-【简单题】快乐数

    题目: 写一个算法来判断一个数是不是"快乐数". 一个数是不是快乐是这么定义的:对于一个正整数,每一次将该数替换为他每个位置上的数字的平方和,然后重复这个过程直到这个数变为1,或是 ...

  7. android WebView问题

    1.加载本地js.css文件 今天碰到个问题,使用WebView加载html数据,本来没什么问题,loadUrl(),loadData(),都可以使用 但是如果需要引入本地的js.css文件就碰到问题 ...

  8. Extract QQ from iPhone and analyze it

    QQ is one of the most popular chat App in the world. Now let me show you how to extract QQ from iPho ...

  9. 无法使用内置管理员账户打开Microsoft Edge

    一.以管理员批准模式运行所有管理员 运行"gpedit.msc",打开本地组策略编辑器,然后依次打开"计算机配置→Windows 设置→安全设置→本地策略→安全选项&qu ...

  10. x265编译

    x265 HEVC Encoder Mission Statement Online documentation Mailing list x265-devel@videolan.org HOWTO  ...