struts2学习笔记-验证器

来源:互联网 发布:淘宝用红包退款 编辑:程序博客网 时间:2024/06/04 00:25

struts2验证:

1.前言(验证器的三种验证方法和两种验证类型):

三种验证方法:

​ 1.第一种:覆写继承了ActionSupport的validation方法,实现局部和全局验证;

​ 2.第二种:基于xml的验证方法,基于xml的方法也提供局部和全局验证,并且基于xml中的验证方法,中包含两种:一种字段验证,一种非字段验证;

​ 3.第三种:使用注解方式: @SkipValidation 这个注解表示不对该方法进行验证。

使用struts2的validate框架有两种验证类型:

​ a):在服务端进行验证。

​ b):在客户端进行验证。

​ 注意:如果需要使用validate框架在客户端进行验证的话,一定要使用 struts2 的s标签并且 表单 的theme不能 为:simple

2.什么时候null什么时候空?

​ 答:没有提交这个参数就是null就是当你越过表单直接访问action的时候;

3.关于验证器的一些注意事项:

​ 1).验证未通过,将不会执行相应的action方法;

​ 2).验证在方法之前执行;

​ 3). ^1[345678]\\d{9}$ 这是验证手机号的正则表达式(说明:这里是两个斜杠,因为markdown要转义);

​ 4). 一定要指定 input 视图 不然会报错:报错信息如下:

严重: Could not find action or result
​ No result defined for action com.chenhao.action.ValidationTest and result input


4.struts.xml文件的相关的代码

(xml中的局部验证以下action配置不适用):

<action name="login" class="com.chenhao.action.ValidationTest" method="loginValidation">      <result name="success">success.jsp</result>      <result name="input">validation.jsp</result> <!-- 这里就要指定input逻辑视图名 --></action>

5.覆写方法validation的验证:

在继承了ActionSupport的类中覆写validation实现 全局 的验证:

​ action类中的代码:

​ (关于name和mobile的setter和gettr省略)

public String loginValidation(){        System.out.println("login.....");        System.out.println("name="+name);        return "success";    }//这里是覆写了ActionSupport里面的方法;        @Override    public void validate() {        // TODO Auto-generated method stub        if(name==null||"".equals(name.trim())){            //如果filedErrors.size()>0则自动跳转到input视图;            this.addFieldError("name", "用户名不能为空");        }        if(mobile==null||"".equals(mobile.trim())){            //如果filedErrors.size()>0则自动跳转到input视图;            this.addFieldError("mobile", "手机号不能为空");                     }else if(!Pattern.matches("^1[345678]\\d{9}$", mobile)){//这里的正则是验证手机号的;            this.addFieldError("mobile", "手机号格式错误");        }    }

jsp页面的代码:

<form action="login.action" method="post">         用户名:<input type="text" name="name"/><br>         手机号:<input type="text" name="mobile"/><br>         gender 性别<br>         <input type="submit" value="登录"/>  </form>
在继承了ActionSupport的类中覆写validation实现 局部 的验证:

​ 注意:在创建自定义的validate方法时需要注意该方法的方法名! 该方法名由 validate+对应的表单提交的action中的 执行方法名称(首字母大写);

//要去掉覆写注释->@Overridepublic void validateLoginValidation() {        // TODO Auto-generated method stub        if(name==null||"".equals(name.trim())){            //如果filedErrors.size()>0则自动跳转到input视图;            this.addFieldError("name", "用户名不能为空");        }        if(mobile==null||"".equals(mobile.trim())){            //如果filedErrors.size()>0则自动跳转到input视图;            this.addFieldError("mobile", "手机号不能为空");                     }else if(!Pattern.matches("^1[345678]\\d{9}$", mobile)){//这里的正则是验证手机号的;            this.addFieldError("mobile", "手机号格式错误");        }    }

这样写了之后,就只会验证这个方法,其余的方法都不会验证(这个方法名的含义是validation加上要验证的方法的方法名,方法名的第一个字母要大写);

6.基于xml方式验证:

​ 1.使用XML方式检验需创建一个XML配置文件,位置在对应的Action同级目录下,命名规则为:Action名-validatioin.xml。

​ 2.校验文件可以有两种写法,一种是字段校验,一种是非字段校验。字段校验就是以字段为主,在对应字段配置下添加该字段的校验器,非字段校验就是先定义好校验器,在校验器下添加字段。

使用xml方式的全局验证:

​ 1.全局就是针对整个action对象进行xml验证;

​ 2.当我们使用全局验证时候需要在  action 对象的同目录下创建一个xml配置文件;

​ 3.文件名是由 : actionName + -validation.xml

使用xml方式的局部验证:

​ 注意:struts.xml中的配置(这是相应的表单提交的action名称也要变):

<struts>      <constant name="struts.enable.DynamicMethodInvocation" value="false" />         <package name="default" namespace="/" extends="struts-default">              <action name="login_*" class="com.chenhao.action.ValidationTest" method="{1}">            <result name="success">success.jsp</result>             <result name="input">validation.jsp</result>        </action>    </package></struts>

​ 1.局部验证是针对action对象中的某一个方法进行xml验证;

​ 2.使用局部验证的时候同样要在 action对象的同目录下创建一个xml配置文件;

​ 3.不过使用局部验证需要在struts.xml 中进行配置;

​ 4.文件名由: actionName- + methodName(如:login_local) + -validation.xml

短路校验:

​ 在字段校验或者非字段校验中加入:short-circuit=”true”,如果某个被标记为短路的校验器失败了,将会阻止其他后续的校验器的进行,然后一个错误(action错误或者字段错误,取决于校验器的类型)将会被添加到被校验的对象的ValidationContext中.

<validator type="expression" short-circuit="true">  <!-- 短路 校验器 -->    <param name="expression">email.startsWith('mark')</param>      <message>Email does not start with mark</message>  </validator>    
短路校验器的规则: 

​ 1.当非字段校验器校验失败,则其后的所有字段校验器都不会执行,而不会影响其他非字段校验器; 
​ 2.字段校验器校验失败时,其后的所有字段校验器都不会执行;
​ 注:当执行到短路,报错时,后面的字段校验器不再执行,不影响非字段校验器; 

​ 指定action中要校验的属性,指定校验器,上面指定的校验器requiredstring是由系统提供的,系统提供了能满足大部分验证需求的校验器,这些校验器的定义可以在xwork-2.x.jar中的com.opensymphony.xwork2.validator.validators下的default.xml`中找到。 
为校验失败后的提示信息,如果需要国际化,可以为message指定key属性,key的值为资源文件中的key。 

非字段型校验器是以校验器为单位的,内容模板:
<validator type="">  <!-- 校验规则器名 -->        <param name="fieldName"></param>   <!-- 要校验的属性名 -->        <param name=""></param>   <!-- 要校验的属性名 -->        <message></message>  </validator>
字段型校验器是以属性为单位的,内容模板:
<field name="">    <!-- 要校验的属性名 -->        <field-validator type="">   <!-- 校验规则器名 -->             <param name=""></param>    <!-- 校验器要使用的参数名 -->            <message></message>            </field-validator>    </field>    

校验器的运行顺序 
​ 1.非字段校验器比字段校验器先执行;
​ 2.从前往后执行;

action类的执行原理及顺序:

1).类型转换;

​ 类型转换失败是在Action调用相应属性的set方法之前发生的,类型转换失败,不影响程序的运行;

2).set方法;

​ 无论类型转换是否成功,都将执行该属性的setter方法.只不过,类型转换失败,会设置该属性值为null;

3).数据验证;

​ 当验证器对通过set方法设置的属性值进行验证时,若验证失败,则会将验证失败信息写入到一个专门的集合中fieldErrors集合.当所用数据验证完毕后,若fieldErrors集合中存在异常信息,即集合的size()大于0,则workFlow拦截器会返回一个”input”字符串,使请求转发到input视图.请求将无法到达Action,即无法执行Action方法;

​ 当然,若在类型转换时已经发生异常,不仅会将异常信息写入到fieldErrors集合,还会继续执行该属性的set方法,将null值赋予该属性.该属性接受到的为null值,肯定不是用户输入的期望的值,所以在进行数据验证时,也一定会验证失败.此时的验证失败信息也同时会写入到fieldErrors集合;

4).Action方法;

​ 经过上面的执行,如果系统中的fieldErrors集合存在异常信息,系统会自动将请求转发至input视图.如果系统中的fieldErrors没有任何异常信息,系统将执行Action方法;


在Action中获取ServletAPI:

为避免与Servlet API耦合,Struts2对HttpServletRequest,HttpSession,ServletContext进行了封装,构造了三个Map对象来替代这三种对象.当然,也可以获取到真正的这三个Servlet的API.

1.通过ActionContext获取(重要);

​ 在struts2框架中,通过Action的执行上下文类ActionContext,可以获取request/session/application对象;

​ ActionContext ctx = ActionContext.getContext();

​ Map

额外学习:在eclipse中rename时:alt+shift+r 和 f2 两个组合快捷键都可以换名称;
//方法一://下面的方式获取到的仅仅是对这些ServletAPI的域空间,//而不是真正的ServletAPI//向request域空间中放入数据(注意:暂且这样认为放入到的request域空间中数据,当学了后面的值栈//后就知道,这种理解是不对的)ActionContext.getContext().put("req","req_value");ActionContext.getContext().getSession().put("ses", "ses_value");ActionContext.getContext().getApplication().put("app", "app_value");

2.通过ServletActionContext获取(重要);

//以下获取的是真正的ServletAPI//方法二:HttpServletRequest request= ServletActionContext.getRequest();request.setAttribute("req", "req_name_value");//向session域空间中放入数据;request.getSession().setAttribute("ses", "ses_value");//向application(ServletContext)域空间中放入数据;     ServletActionContext.getServletContext().setAttribute("app","app_name");

3.通过实现特定接口来获取(了解就好);

​ 注:学会区分成员变量!!

package com.chenhao.action;import java.util.Map;import org.apache.struts2.interceptor.ApplicationAware;import org.apache.struts2.interceptor.RequestAware;import org.apache.struts2.interceptor.SessionAware;public class ValidationTest implements RequestAware,SessionAware,ApplicationAware {    //这里设置成员变量,接受覆写方法传过来的参数;    private Map<String,Object> req; //成员变量    private Map<String,Object> ses; //成员变量    private Map<String,Object> app; //成员变量    public String local(){        req.put("req", "req_value");        ses.put("ses", "ses_value");        app.put("app", "app_value");                return "success";    }    @Override        public void setApplication(Map<String, Object> arg0) {        // TODO Auto-generated method stub        this.app = arg0;            }    @Override    public void setSession(Map<String, Object> arg0) {        // TODO Auto-generated method stub        this.ses = arg0;    }    @Override    public void setRequest(Map<String, Object> arg0) {        // TODO Auto-generated method stub        this.req = arg0;    }}

struts2的基石–拦截器:

struts2内置了很多拦截器,每个拦截器完成相对独立的功能,多个拦截器的组合体称为拦截器栈.最为重要的拦截器栈是系统默认的拦截器栈DefaultStack;

​ 前言:1)当拦截器验证错误,默认转向Action.INPUT 即”input”’

​ 2)或者用注释:@InputConfig(methodName=” 方法名”,resultName=”视图”),如果methodName方法为空或者指定方法不存在时,转向resultName指定视图,使用了该标注,将不再转向”input”视图;

1.拦截器的自定义与注册;

​ 需要步骤:

​ 1.建立一个继承了AbstractInterceptor的拦截器类;

​ 2.自定义的拦截器要在struts2的配置文件中注册;

​ 例子 :权限拦截器:

​ 创建一个拦截器类:

import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class PermissionIntercept extends AbstractInterceptor {    @Override    public String intercept(ActionInvocation invocation) throws Exception {        System.out.println("-----------------------------");        //获得session中的用户信息;        String user = (String)ActionContext.getContext().getSession().get("user");        if(user != null){                    //调用action            return invocation.invoke();        }               return "error";    }}

在Struts2中的配置:

<package name="default" namespace="/" extends="struts-default">  <!-- 这里注册已经创建的拦截器 -->    <interceptors>      <interceptor name="permissionIntercept" class="com.chenhao.action.PermissionIntercept">      </interceptor>    </interceptors>    <action name="login_*" class="com.chenhao.action.SysAction" method="{1}">            <!-- 这里调用已经创建好的permissionIntercept拦截器; -->            <interceptor-ref name="permissionIntercept"/>            <!-- 因为调用了自定义的拦截器,所以不会在调用默认拦截器,所以这里人为调用,完成一些基本的操                作 -->            <interceptor-ref name="defaultStack"></interceptor-ref>            <result name="error">error.jsp</result>            <result name="success">loginout.jsp</result>     </action></package>

login.jsp页面

<body><form action="login_execute.action" method="post">    <input type="submit" value="submit"/>     <!-- 这里设置一个session -->    <%         session.setAttribute("user", "任辰皓")    %>  </form></body>

loginout.jsp页面

<body>  <!-- 这里移除session --><%    session.removeAttribute("user");%> 成功退出!!!</body>

Action无特殊设置,直接定义一个Action,方法名与所调用的一致就行 ,….省略….;

2.拦截器的另一种定义的方式(拦截器栈);

​ 把上面在Struts2中的配置如下修改就可以了(其余jsp,action等都不变);

<package name="default" namespace="/" extends="struts-default">    <interceptors>        <interceptor name="permissionIntercept"                      class="com.chenhao.action.PermissionIntercept">                    </interceptor>        <interceptor-stack name="permissionStack">                <interceptor-ref name="permissionIntercept"/>                <interceptor-ref name="defaultStack"></interceptor-ref>             </interceptor-stack>    </interceptors>    <action name="login_*" class="com.chenhao.action.SysAction" method="{1}">       <interceptor-ref name="permissionStack"></interceptor-ref>            <result name="error">error.jsp</result>            <result name="success">loginout.jsp</result>        </action></package>

3.设置默认的拦截器:

​ 说明:为了减少冗余的代码量;

只需要在struts2中配置:

<package name="default" namespace="/" extends="struts-default">   <interceptors>      <interceptor name="permissionIntercept"                     class="com.chenhao.action.PermissionIntercept">          </interceptor>      <interceptor-stack name="permissionStack">            <interceptor-ref name="permissionIntercept"/>            <interceptor-ref name="defaultStack"></interceptor-ref>           </interceptor-stack>   </interceptors>  <!-- 只需要在这里建一个默认拦截器,这个包里面的所有action执行时都会执行它,如果在action中单独指明了一个拦截器,那么就不会执行默认的拦截器 -->   <default-interceptor-ref name="permissionStack">   </default-interceptor-ref>   <action name="login_*" class="com.chenhao.action.SysAction"               method="{1}">         <result name="error">error.jsp</result>         <result name="success">loginout.jsp</result>   </action></package>

OGNL的使用:

1.特点(相对于其他表达式语言,它提供了更加丰富的功能):

​ 1.支持对象方法的调用;

​ 2.支持类静态方法的调用和常量的访问:格式为:

​ @全类限定名@方法名 |常量名;

​ 对于静态方法的访问,需要通过在struts2的配置文件struts2.xml中设置常struts.ognl.allowStaticMethodAccess=true;

​ 3.可以操作集合对象;

​ 4.可以直接创建对象;

2.值栈与OGNL(值栈就是根对象):

对于struts2中的值栈的学习,主要是要搞清楚以下几个对象间的关系:
1.值栈与ActionContext的关系;
2.值栈与值栈的Context属性的关系;
3.值栈的Context属性与ActionContext的关系;
它们的关系,通过以下几个知识点可以加深理解.
1)值栈对象:
A.值栈的实现类:

​ 在用户提交一个Action请求后,系统会马上创建两个对象:Action实例与值栈对象.

​ struts2中的值栈ValueStack是个接口,其实现类为OgnlValueStack.

//额外学习://  java中属性 和 成员变量的区别:有get  or   set方法为 属性;
B.root的属性的类型:

​ 本质是一个ArrayList,不过在这里当做栈使用;

C.Context属性的创建:

​ 在设置root的时候创建;Context本质是一个Map;

2).值栈的获取很麻烦:

​ 当一个Action请求到来是,不仅会创建一个Action实例,还会创建一个ValueStack对象,用与存放当前Action运行过程中的相关数据.当请求结束,Action实例消失,用于记录其运行期间数据的值栈也没有了意义.所以,当请求结束时,同时需要将值栈对象销毁.即值栈的生命周期与请求Request的相同.为了保证这一点,就将值栈对象通过setAttribute()方法,将其放入到了Request域属性中,并将该属性的key以常量的形式保存在ServletActionContext中.所以,为了获取值栈对象,首先需要获取到request对象,然后再获取其key,这样才能获取到值栈对象.这个过程相对是比较麻烦的.

​ 值栈的实质是request中的一个属性值.这个属性的名称为:struts.valueStack,保存在ServletActionContext的常量是STRUTS_VALUESTACK_KEY中.

public String execute(){    //从request中获取ValueStack对象    String key = ServletActionContext.STRUTS_VALUESSTACK_KEY;    HttpServletRequest request = ServletActionContext.getRequest();    ValueStack vs = (ValueStack) request.getAttribute(key);    return "success";}
3).context属性的别名:

​ 1).ActionContext是context属性的别名;

​ 怎么证明了,看下面这行(ActionContext.getContext().put(“city”,”shanghai”))代码,把语句//1 或者放在//2看看jsp页面输出的信息,可以看出来,context和ActionContext是一样的;只不过ActionContext是context的别名;

@Override    public String execute() throws Exception {        ActionContext.getContext().put("city","shanghai"); //1  //放在这里jsp页面输出beijing        String key = ServletActionContext.STRUTS_VALUESTACK_KEY;        HttpServletRequest request = ServletActionContext.getRequest();        ValueStack vs = (ValueStack) request.getAttribute(key);        //从ValueStack中获取其属性context;        Map<String,Object> context = vs.getContext();          context.put("city", "beijing");                    //2    //放在这里输出shanghai;        return "success";    }
<!-- 这是jsp页面的代码 -->city = <s:property value="#city" />    <!-- 要在表达式中访问到context中的对象,需要使用“#对象名称”的语法规则-->

以上同一个语句在不同位置输出不同的内容就能说明context和ActionContext是一样的,理由见上面的代码,后者把前者覆盖了;

注意:为了方便获取值栈的context属性,Struts2专门为其又起了个别名—-ActionContext,无论是ActionContext中存放的非根对象,还是值栈中context中存放的非根对象,它们均使用了同一个Map.即它们是同一个对象;

4).值栈的获取很简单:

​ 为了方便对值栈的访问,于是就将值栈对象直接放到了context这个Map中.通过查看OgnlValueStack的对root的初始化方法setRoot()可以看到.

protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor,CompoundRoot compoundRoot,boolean allowStaticMethodAccess) {   this.root = compoundRoot;   this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);  //OGNL其实和struts2没有联系;   this.context = Ognl.createDefaultContext(this.root, accessor, new       OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess);        //就是这句代码!!    context.put(VALUE_STACK, this);    Ognl.setClassResolver(context, accessor);    ((OgnlContext) context).setTraceEvaluations(false);    ((OgnlContext) context).setKeepLastEvaluation(false);}
//所以,ActionContext这个Map中,最终存放者如下内容(你会发现context又是ActionContext)://              |               |->root//              |->valueStack-->|//              |->request      |->context(即ActionContext)//ActionContext |->session//              |->application//              |->...//              |////向context中放入数据,就是向map中放入数据,需要指定key.struts2中已经定义号一些key,用于完成特殊功能.访问context中数据,即为非根数据,需要使用 # ;//              |-->application//              |-->session//              |-->value//context map-- |-->action//              |-->request//              |-->parameters//              |-->attr(searches,page.ruquest,session,then,application,scopes)//说明:ValueStack的context中存放的是ActionContext的地址(只是一个引用)//额外获得知识:域属性中存放的是引用(地址),不是对象;
//从request中获取Value对象;ValueStack vs2 = ActionContext.getContext().getValueStack();
5).值栈的栈操作:

​ 查看OgnlValueStack类中的peek(),pop(),push()方法可知,对ValueStack对象的栈的操作,本质是对root栈对象的操作.即,从宏观上可以直接说值栈就是根对象.但,其实根对象指的是值栈的root对象,而非根对象是值栈的context对象.

6).值栈操作:

​ 这里的值栈指的是宏观上的值栈,即包含根对象root与非根对象context.对于值栈的操作包括两方面:向值栈中放入数据,从值栈中读取数据.值栈中的数据,可以通过struts2标签显示:

​ 向值栈中放入数据分为两种,一种为显示放入,一种为隐式放入.所谓显示放入是指,显示的获取到值栈对象,然后向其中放入数据隐式放入是指,没有专门将数据直接放入值栈对象中的代码,却已经将数据放入.

​ Struts2中有一个标签 便于对值栈中数据的存放情况进行了解.其在页面上显示为一个可展开/关闭的连接;

1)搭建测试环境:

​ step1.定义实体Student(将来是要放到数据库的);

​ 相当于定义一个JavaBean;

​ Step2.定义Action;

​ 就是获得值栈;

​ Step3.注册Action;

​ Step4.定义视图页面show;

2).向root中显示放入数据;
    @Override    public String execute() throws Exception {        String key = ServletActionContext.STRUTS_VALUESTACK_KEY;        HttpServletRequest request = ServletActionContext.getRequest();        ValueStack vs = (ValueStack) request.getAttribute(key);        //在root中显示的放入了一个无名对象的方式一;        Student student = new Student("张三",23);        vs.getRoot().push(student);        //在root中显示的放入了一个无名对象的方式二;        Student student2 = new Student("李四",25);        vs.push(student2);      //---------------------------------------------------------------------------------        //放入有名对象的思路:先把对象放入Map,在再把Map放入一个ArrayList中就是一个有名的对象了;        //放入一个有名的对象的方法一;        Student student3 = new Student("liu四",25);        Map<String,Student> map = new HashMap<String,Student>();        map.put("student3", student3);        vs.push(map);        //放入一个有名对象的方法二;        Student student4 = new Student("liu456四",65);        //查看set()的api可知,set()的调用,set()方法中的实现是,先查看栈顶元素有否有Map,有就使用,        //没有就new一个        vs.set("student4", student4);//用set()方法就不需要像放入 "有名对象的方法一"麻烦了;        //将root当做是ArrayList放入数据       //这个和前面的不同这个通过add()会被放入栈底;        Student student5 = new Student("liu456四",65);        vs.getRoot().add(student5);        return "success";    }

​ jsp访问方式:

<s:debug/><br>  <!-- 一种调试标签,详细的百度 -->name = <s:property value="name"/><br>age = <s:property value="age"/><br>name = <s:property value="student3.name"/><br>age = <s:property value="student3.age"/><br>name = <s:property value="student4.name"/><br>age = <s:property value="student4.age"/><br>
3).向root中隐式放入数据;
//root中隐式放入数据  重点掌握//在action中定义要提交的属性名,并指定set,get方法,这就是向值栈中隐式的放入数据;
4).向context中显示放入数据;
//向ActionContext中显示添加数据,就是以下的形式;ActionContext.getContext().put("some","req_value");//这句话相当于;--------------------->----                                                                                        |//              |-->application                                                         |//              |-->session                                                             |//              |-->value                                                               |//context map-- |-->action(the current action)这是一个引用                                |//              |-->request                                                             |//              |-->parameters                                                          |//              |-->attr(searches,page.ruquest,session,then,application,scopes)          |//              |---->some   //就会被添加到这里---<-------------------------------<---------|
5).向context中隐式放入数据;

注意:以下两类的参数是隐式的放入的

​ A.请求参数

​ B.Action对象

//额外知识:在网页中由表单提交的数据在服务端接受的时候都是由 数组 接受的,因为它要兼顾一个参数多个值的情况//比如:复选框就是一个参数多个值的情况;
<!-- jsp中的页面代码 --><%-- 当Action中没有name和age的属性声明时,以下就只有parameters.name-->  <!-- #parameters.name底层执行的是request.getParameters("name") 读的是参数,所以在action类中尽管没有相应属性的set,get方法一样可以读到 --><s:property value="#parameters.name"/><br><!-- #request.name底层执行的是request.getAttribute("name") 读的是属性值 -->  <s:property value="#request.name"/><br><s:property value="#action.name"/><br>

当请求到来,马上创建一个action对向,在root和context中都要放入一个action对象;

6).数据的加载顺序;

​ A.root中数据的加载顺序:

​ 当在Action中仅仅向context放入某数据some后,页面无论是通过#从context中读取数据,还是不使用#直接从root中读取数据,均可得到放入的值,就是先在root中查找没有再在context中查找;

public class ValidationTest extends ActionSupport {    public String local(){        ActionContext.getContext().put("some","req_value");        return "success";    }}

jsp页面:

some=<s:property value="some"/><br> <!-- 在root目录中也能读取是因为,struts2的内部实现的支持,如果在root中找不到,struts2的内部实现会到context中去寻找; -->some=<s:property value="#some"/><br><!--  -->

​ B.request中数据的加载顺序:

            request.some底层执行的是request.getAttribute("some");            #request.some被struts2包装后的查找顺序是:                1).request域空间;                2).root                3).Context          
//用ServletActionContext 可以把参数放入request中去;//ActionContext.getContext().put("some","req_value");这行代码不能真正的把属性传入request中,只是传入了context中,正确方法如下:HttpServletRequest request = ServletActionContext.getRequest();request.setAttribute("some","req_value");
7).OGNL对于集合的操作(此节内容了解即可):

​ Struts2 中使用OGNL对于集合的操作主要涉及以下集中情况:

​ 1),创建List与Map集合;

​ 2),遍历List与Map集合;

​ 3),集合元素的判断;

​ 4),集合投影;

​ 5),集合过滤;

A.创建List与Map集合:

​ 注:以下的代码只有jsp页面中有,无其他代码;

    <br>------------------list---------------------    <!-- 在s:set中定义的都直接当如到了context中 -->    <s:set name="mylist" value="{'zs','ls','ww'}">    </s:set><!-- iterator标签默认会将当前迭代对象放入到值栈栈顶  -->    <s:iterator value="#mylist"><br>        <s:property/><br><!-- property标签默认会输出值栈栈顶元素 -->    </s:iterator>
<br>------------------map---------------------                            <!-- Map定义是 # 开头 -->    <s:set name="myMap" value="#{'moblie':'1234567','QQ':'923047' }"/>    <!-- 方法一 -->    <s:iterator value="#myMap" var="entry">        <s:property/><br>    </s:iterator>    <!-- 方法二  -->    <s:iterator value="#myMap" var="entry">        <s:property value="entry"/><br>    </s:iterator>        <!-- 方法三 -->    <s:iterator value="#myMap">        <s:property value="key"/> = <s:property value="value"/><br>    </s:iterator>
B.集合元素的判断:

​ 判断 ‘zs’ 是否在集合里面?

<!-- 需要 A 的代码.in 表示是否在? not in表示是否不在?  --><s:property value="'zs' in #myList"/><br><s:property value="'zs' not in #myList"/>
C.集合投影:

​ 注:集合查询:指对于集合中的所有的数据(相当于行),值选择集合的某个属性值(字段)作为一个新的集合.即:行数不变,只选择列;使用如 “集合.{字段名} “的语法投影;

​ 注:需要建个实体类(例子中,新建的一个叫Student的实体类,并且其中有 ame 和 age 属性 )!

<br>-------------------创建三个Student实体类对象------------------    <s:bean id="Student1" name="com.chenhao.action.Student">        <s:param name="name" value="'zhangsan'"></s:param>        <s:param name="age" value="34"></s:param>    </s:bean>    <s:bean id="Student2" name="com.chenhao.action.Student">        <s:param name="name" value="'zsan'"></s:param>        <s:param name="age" value="34"></s:param>    </s:bean>    <s:bean id="Student3" name="com.chenhao.action.Student">        <s:param name="name" value="'zhangn'"></s:param>        <s:param name="age" value="34"></s:param>    </s:bean>    <br>-----------------将前面的三个student对象的name属性组成一个List,方便映射--------------------    <s:set name="students" value="{#Student2,#Student3,#Student1}"></s:set>    <s:iterator value="#students"><br>        <s:property/>    </s:iterator>    <br>    <br>----------------集合的映射--------------------    <!-- 只要几个元素的某一个属性,例如下面只要students的name属性,这就叫集合的投影 -->    <s:set name="studentNames" value="#students.{name}"></s:set>    <s:property value="studentNames"/><!-- 说明:在<s:bean/>中的name属性里的值为实体类的权限定名 -->

D.集合的查询:

​ 注:以下的代码需要 上面 B 中的代码!!!!

    <br>---------------集合的查询---查询前面的三个Student对象中年龄大于23岁的 所有人----------------    <s:iterator value="#students.{? #this.age > 23}"><br><!-- ?  代表所有人 -->    <s:property/>    </s:iterator>    <br>---------------集合的查询---查询前面的三个Student对象中年龄大于23岁的 第一个人--------------    <s:iterator value="#students.{$#this.age > 23}"> <br> <!-- $ 代表第一个人 -->        <s:property/>    </s:iterator>