struts2笔记_day04

1、ognl介绍:

OGNL是Object-Graph Navigation Language(对象图导航语言)的缩写,它是一种功能强大的表达式语言;
    比El表达式功能强大。
        *xwork提供OGNL表达式
        *ognl-3.0.5.jar
    struts2将ognl表达式语言,集成到struts2框架中,做为它默认表达式语言。

    OGNL提供五大类功能:
        1、支持对象方法调用,如:xxx.doSomeSpecial();
        2、支持类静态的方法调用和值访问;
        3、访问OGNL上下文(OGNL context)和ActionContext;(重点:操作ValueStack值栈);
        4、支持赋值操作和表达式串联;
        5、操作集合对象。
    valueStack是值栈;
        1、从技术角度  ValueStack就是一个接口;
        2、从使用角度  ValueStack就是一个容器;

演示:在struts2中使用ognl表达式
    需要结合struts2的标签使用

    演示对象调用方法
    演示静态成员访问

    注意:在struts2中使用静态成员访问,必须设置一个常量:
    把struts.ognl.allowStaticMethodAccess=false常量在struts.xml中设置为true;

2、ValueStack:

是一个接口com.opensymphony.xwork2.util.ValueStack。
我们使用它是将其作为一个容器,用于携带action数据到页面;
在页面上通过ognl表达式获取数据。

问题1、什么是valueStack?
        1、ValueStack有一个实现类叫OgnlValueStack。
        2、每一个action都有一个ValueStack(一个请求,一个request,一个action,一个valueStack)valueStack生命周期就是request生命周期(请求--响应)
        3、ValueStack中存储了当前action对象以及其它常用web对象(request,session,applicati,parameters)
        4、struts2框架将valueStack以“struts.valueStack”为名存储到request域中。

问题2、valueStack结构?

        ValueStack中 存在root属性(CompoundRoot),context属性(OgnlContext)
        *CompoundRoot就是ArrayList
        *OgnlContext就是Map

        list集合中存储的是action相关信息
        map集合中存储的是相关映射信息,包含parameters,request,session,application,attr(前几个依次查)等;

        我们想要从list中获取数据,可以不使用#号(它就是ognl的root),
        如果我们从map中获取数据,需要使用#号(其实在struts2中的map--context就是ognlContext)

    结论:
        ValueStack它有两部分List和Map
        在struts2中List就是root,Map就是OgnlContext。
        默认情况下,在struts2中从valueStack获取数据从root中获取。

问题3、值栈对象的创建 ,ValueStack 和 ActionContext 是什么关系 ?

    ActionContext ctx = ActionContext.getContext();
        if(ctx!=null){
            stack = ctx.getValueStack();
        }
    valueStack是每一次请求时都会创建;
    在ActionContext中持有了valueStack的引用。 

问题4、如何获得值栈对象?

    对于valueStack获取有两种方式:
        1、通过request获取:
            ValueStack vs = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

        2、通过ActionContext获取:
            ValueStack vs2 = ActionContext.getContext().getValueStack();

问题5、向值栈保存数据(主要针对root)

    主要有两个方法
        push(Object obj);---->底层就是root.add(0,obj)将数据存储到栈顶;
        set(String name,Object obj);---->底层是将数据封装到HashMap中,在将这个HashMap通过push存储。

    在jsp中通过查看值栈的内容。

问题6、在JSP中获取值栈的数据:
    root中数据不需要#号,而context中 数据需要#号;

    1、如果栈顶是一个Map集合,获取时,可以直接通过Map集合的key来获取value;
        

    2、如果栈顶数据不是一个Map,没有key值,可以使用序号来获取:
        从0的位置向下查找所有;

        只查找0位置上的数据。

    在OgnlContext中获取数据
        1、request:
        2、session:
        3、application:
        4、attr:  依次从request,session,application中查找
        5、parameters:   获取请求参数
---------------------------------------------------------------------------------------------------     
ValueStack主流应用:就是解决将action数据携带到jsp页面。
    1、文本(字符串)
        1.fieldError  校验数据错误信息提示;
        2.actionError 关于逻辑操作时错误信息(例如登录失败);
        3.message 就是一个信息。

        this.addFieldError("msg","字段错误信息");
        this.addActionError("Action全局错误信息");
        this.addActionMessage("Action的消息信息");

        *fieldError 针对某一个字段错误信息(常用于表单校验)、actionError(普通错误信息,不针对某一个字段 登录失败)、actionMessage通用消息

        在jsp中使用struts2提供标签 显示消息信息
            
            
            

    2、复杂数据
        可以使用valueStack存储:

        在action中存储数据:

            //向valueStack中存储数据(root)
            ValueStack vs = ActionContext.getContext().getValueStack();
            List users = new ArrayList();
            users.add(new User("tom","123",20,"男"));
            users.add(new User("张三","456",21,"男"));
            users.add(new User("小媚","789",19,"女"));
            vs.push(users);
            //vs.set("users", users);

        在页面上获取数据:
            使用了标签来迭代集合;
            使用push存进值栈这样取:
            //这是将集合中迭代出来的每一个元素起个名字叫user,而user是存储在Context中,不在root中所以访问要加#号
                username:
password:
使用set存进值栈这样取: username: password:
----------------------------------------------------------------------------------- 关于默认压入到valueStack中的数据: 1、每次请求,访问Action对象 会被压入值栈 ------- DefaultActionInvocation 的 init方法 stack.push(action); * Action如果想传递数据给 JSP,只有将数据保存到成员变量,并且提供get方法就可以了 2、ModelDriven 接口 有一个单独拦截器 在拦截器中 ,将model对象 压入了 值栈 stack.push(model); * 如果Action 实现ModelDriven接口,值栈默认栈顶对象 就是model对象 ------------------------------------------------------------------------------------------------- 问题7、为什么EL表达式可以访问ValueStack中的数据? struts2框架中所使用的request对象,是增强后的request对象。 ${username}---->request.getAttribute("username");//el表达式本身会这么查找 增强后的request,会首先在request域范围查找,如果查找不到,会在valueStack中查找。 StrutsPreparedAndExecuteFilter的doFilter代码中 request = prepare.wrapRequest(request); * 对Request对象进行了包装 ,StrutsRequestWrapper * 重写request的 getAttribute Object attribute = super.getAttribute(s); if (attribute == null) { attribute = stack.findValue(s); } 访问request范围的数据时,如果数据找不到,去值栈中找 ? request对象 具备访问值栈数据的能力 (查找root的数据) -------------------------------------------------------------- OGNL表达式常见的使用($ # %) 1、#号使用 用法一:#代表ActionContext.getContext()上下文 ----> ActionContext().getContext().getRequest().get("name"); #request #session #application #attr #parameters 用法二:不写#默认在值栈的root中进行查找 在root中查找name属性 *查询元素时,从root的栈顶元素开始查找,如何访问指定栈中元素? 访问栈中第二个元素name属性 *访问第二个元素对象 用法三:进行投影映射(结合复杂对象遍历) 1、集合的投影(只输出部分属性

遍历集合只要name属性

2、遍历时,对数据设置条件

遍历集合只要price大于1500商品

--- 3、综合

只显示价格大于1500 商品名称

用法四:使用#构造map集合 经常结合 struts2 标签用来生成 select、checkbox、radio

使用#构造map集合 遍历

key : , value:
------------------------------- 2、%号使用 %作用:就是用于设定当前是否要解析其为ognl表达式; %{表达式} 当前表达式会被作为ognl解析; %{'表达式'}当前表达式不会被作为ognl解析。 对于s:property标签,它的value属性会被默认做为ognl。 以后,所有表达式如果仙姑要让其实ognl就这么写 %{表达式} 3、$号使用 $作用:就是在配置文件中使用ognl表达式来获取valueStack中数据 用法一 :用于在国际化资源文件中,引用OGNL表达式 在properties文件 msg=欢迎您, ${#request.username} 在页面 * 自动将值栈的username 结合国际化配置信息显示 用法二 :在Struts 2配置文件中,引用OGNL表达式 ${contentType} * ${contentType} 读取值栈中contentType数据,在Action提供 getContentType 因为Action对象会被压入值栈, contentType是Action属性,从值栈获得 结论: #使用ognl表达式获取数据,% 控制ognl表达式是否解析 ,$ 用于配置文件获取值栈的数据

3、防止表单重复提交

问题:什么是表单重复提交?
    regist.jsp---->RegistServlet
    表单重复提交  危害:刷票、重复注册、带来服务器访问压力(拒绝服务)

解决方案:
    在页面上生成一个令牌(token,就是一个随机字符串),将其存储到session中,并在表单中携带;
    在服务器端,获取数据时,也将令牌获取,将它与session中存储的token对比,没问题,将session中令牌删除。

struts2中怎样解决表单重复提交:
    在struts2中解决表单重复提交,可以使用它定义的一个interceptor。
     

    步骤:
        1、在页面上需要使用一个token标签
            在表单中添加一个标签
            就会在页面上生成一个令牌,并存在于表单中。

        2、需要在action中引入token拦截器
            

        3、需要配置视图
            /token.jsp

        通过  显示错误信息 
        覆盖重复提交信息  struts.messages.invalid.token=您已经重复提交表单,请刷新后重试

4、struts2中json插件使用:

知识点 :struts2 的 Ajax 开发 
Ajax开发客户端 和 服务器交互数据格式  --------------- json 
  * json 是最轻量级,体积最小 

服务器将程序处理结果,转换为json格式发送给 客户端 
  * json-lib 、 flexjson  工具类库 

  * struts2-json-plugin-2.3.7.jar 

案例一: 输入用户名,鼠标点击密码(触发用户名元素离焦事件),使用Ajax 将用户名发送到服务器 判断是否存在 
jquery 1.4 、 1.6 新特性比较多  (企业主流 1.4 )

使用struts2 json插件 
   要点1 :  extends 继承 json-default 
   要点2 :  type 类型写 json  

* struts2 json插件 ,默认将值栈root顶端对象 所有属性返回(get方法)

不想将company属性返回 ,在get方法上 @JSON(serialize=false)

案例二 :服务器将 商品对象 List列表返回 
如果Action 实现ModelDriven , model对象就是值栈栈顶对象,struts2 json插件默认 将model返回 

通过设置root属性,修改插件返回 根对象
   * action 将Action作为根对象返回 

只想要每个商品的 name 属性 
   方案一: 在pnum 、price 的get方法上 添加 @JSON(serialize=false)  --------> 只要@JSON注解,属性将永远不能参与 json返回 
   方案二: 设置 includeProperties 属性 
products\[\d+\]\.name       

你可能感兴趣的:(Java-EE)