Struts学习之值栈的理解

转自:http://blog.csdn.net/hanxuemin12345/article/details/38559979

    页面一个请求发送过来,依次经过一系列拦截器(处理公共部分,如:往数据中心(值栈)填充数据,所处理工作与业务无关),ActionResult

 

1,经过一系列拦截器

介绍其中的两个拦截器:ModelDrivenParams;

 

——一个请求过来,首先创建一个值栈对象,经过初始化,然后Map和对象栈中放入一些数据

(1)值栈的结构:

(2)Map和对象栈中分别存入什么数据:

Map中:request=session=…application=…attr=…,parameters=…

 

对象栈中:action对象,…

 

初始化完之后,还会经过很多拦截器,其中一个拦截器ModelDriven(封装model,把model放入对象栈的栈顶),一个拦截器Params(参数封装,放入参数)

(1)经过拦截器

(2)再经过ModelDriven拦截器:

   Action中实现ModelDriven<>,并实现它的方法:

   Public class RoleActionextends ActionSupport implements ModelDriven<Role>{

        private Role model = new Role();

        private Role getModel(){   //获取栈顶的model对象

           return model;

        }

   }

 

ModelDriven的作用:model对象放入对象栈栈顶(原来栈顶是action,现在栈顶是model)

(3)经过拦截器

(4)再经过Params拦截器

   Params拦截器的作用:封装参数。

   如何封装?——做了两件事:第一,先到对象栈中封装;第二,再到Map中封装;

   例子:假如,现在对象栈中有model对象在(含有idname属性)在栈顶,action对象(含有idage属性);页面访问地址:xx.action?id=3&name=ab&age=20&xx=00;

   经过Params拦截器时,它如何将参数封装?

——先从栈顶开始找,依次找到idnameage属性,通过各自的Set方法依次设值id=3,name=ab,age=20(注:虽然对象栈中有两个id属性,但是由于model对象的id属性在栈顶,所以找到此id属性就设值,不会继续往下找),但是对象栈中没有xx属性,于是栈中就没有这个参数了,通过对象栈就无法得到xx参数,但是Map中有parameters,可以把所有参数放入parameters中,无论在对象栈中有没有写属性,在parameters中都能得到

——经过一系列拦截器之后,此时数据中心就有了数据,那我们就可以从中获取数据(ActionJsp中均可从中获取并使用)

2,思考:值栈对象作用范围是什么?

——一次请求。因为每发送一个请求过来,都要经过这样一系列过程:拦截器(往值栈中压入数据)——>Action——>Request 

3,细节扩充:

(1)由值栈对象,如何操作Map

——ActionContext.getContext()

                            .put(k,v);//Map中放入数据

                            .get(k);//Map中获取数据

或:ActionContext.getContext.getValueStack()

                                          .put(k,v);//Map中放入数据

                                          .get(k);//Map中获取数据

(2)有了值栈对象,如何操作对象栈

——ActionContext.getContext().getValueStack()

                                         .push(obj);//向对象栈中放入数据

                                         .pop();//从对象栈中获取数据

(3)所以,值栈中有了对象,Action中如何使用栈中的数据:

——通过ActionContext()操作Map,操作对象栈

(4)所以,值栈中有了对象,jsp中如何使用栈中的数据:

——通过OGNL表达式获取

 

 

OGNL表达式的格式和语法:

格式:

(1)Struts.xml中的格式为:${ongl};

(2)Jsp中的格式为:%{ongl};

(注:只能写在Struts2的自定义标签的属性中)

语法:

user =findValue("user");//从栈中获取user属性

#user = map.get("user"); //Map中获取user对象

#user.name=map.get("user").getName();//Map中获取user对象的name属性

(findvalue(expr))的查找顺序:

(1)从对象栈中查找指定名称的属性,从栈顶开始向下找,找到后就返回;

(2)如果从对象栈中没有找到属性,则从Map中查找对应的key值,找到后就返回。

例子:


4,总结

    通过此篇博客,我们需要了解什么?
(1)页面一个请求过来,Struts2中依次经过了哪几个过程?
    —— 一系列拦截器——>Action——>Request;
——ModelDriven和Params拦截器分别的主要作用;
(2)值栈的概念?
——值栈的结构:对象栈、Map;
——对象栈、Map分别存放什么数据;
(3)(1)和(2)是如何结合在一起的?
——请求过来,一开始经过拦截器,初始化并创建对象栈,经过ModelDriven和Params拦截器时,分别往值栈中封装对象和封装参数,分别封装到相应的地方,此时数据中心中有就有了数据。
    以上均是拦截器为我们做的工作,我们只需写Action(通过ActionContext()操作Map,操作对象栈)和Jsp(通过OGNL表达式获取栈中数据)即可。
 
 
  
 

增强一个类常用的方式:装饰者模式,动态代理,继承

用EL表达式取值:

el取值能够获取到action里面的值,具体原理就是,它重写的request,进行了request域的增强,里面进行了以下操作:

el取值时,如果request域里面能够找到目标值,那么就把值返回到页面。如果在request域里面不能够取到目标值,那么就通过值栈获取。

ActionContext.getContext().getValueStack().findValue(“key”);如果查找到值就返回数据。这里的request是通过HttpServletRequestWrapper重写过。

所以在el表达式获取Action里面存取的值的时候效率没有通过Struts标签来的快。推荐用struts标签和ongl来获取Action里面的数据。

el在获取Action里面的值时,action里面的字段也必须提供get方法。否则无法获取到值。

//服务端代码:

public class Pr_getList {
    private List<User> usl=null;

    public List<User> getUsl() {
        return usl;
    }

    public String execute(){


        usl=new ArrayList<User>();
        User tempUser=new User("胡艺宝", "123465");
        usl.add(tempUser);
        return "success";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
<!-- 客户端jsp代码: -->
<!-- 在使用jstl标签以前要先导入jstl标签库,这里使用的jstl标签库是1.2版本 -->
<c:forEach items="${usl }" var="temp">
        ${temp.name }<br>
        ${temp.password }
</c:forEach>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
//这个是增强request的源码:

ActionContext ctx = ActionContext.getContext();
        Object attribute = super.getAttribute(key);

        if (ctx != null && attribute == null) {
            boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE));

            // note: we don't let # come through or else a request for
            // #attr.foo or #request.foo could cause an endless loop
            if (!alreadyIn && !key.contains("#")) {
                try {
                    // If not found, then try the ValueStack
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE);
                    ValueStack stack = ctx.getValueStack();
                    if (stack != null) {
                        attribute = stack.findValue(key);//这就是el能够获取到值栈里面的关键
                    }
                } finally {
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE);
                }
            }
        }
        return attribute;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

ognl两个符号的使用#号和%的使用

使用#来获取context中的数据

//服务端的代码:
public class Pr_getRequestByContext {
    private User us;

    public User getUs() {
        return us;
    }

    public String execute(){
        us=new User("胡艺宝", "123456789");
        ((RequestMap)ActionContext.getContext().getValueStack().getContext().get("request")).put("user", us);//把数据保存到context的request中
//其中你也可以通过ActionContext.getContext().get("request")获取到的效果和上面的一样。
        System.out.println(ServletActionContext.getRequest().getAttribute("user"));//验证是否能够在HttpServletRequest中获取到user,事实证明能够获取到。猜测RequestMap的最底层依赖了HttpServletRequest
        return "success";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
<!-- 这个是jsp客户端的代码 -->
<s:property value="#request.user"/>
  • 1
  • 2

运行后能够成功获取user数据

%号的使用

场景:在struts2表单标签里面使用ognl表达式,如果直接在struts2表单标签里面使用ognl表达式会不识别,只有使用%号之后才会识别。

//服务端代码就用上面那个
  • 1
  • 2
<!-- 客户端jsp代码,成功运行输出后的代码: -->

<s:textfield name="username" value="%{#request.user.name}"></s:textfield>
  • 1
  • 2
  • 3

OK!!!完成!!

posted @ 2017-11-11 23:56  山里的小龙人  阅读(114)  评论(0)    收藏  举报