1 拦截器
1.1 拦截器简介
拦截器 类似于 过滤器的功能,过滤器可以过滤项目的任何请求(servlet/jsp/html/img),但拦截器只能拦截Action资源。拦截完Action,添加逻辑代码
1.2 拦截器的编写规则
struts2提供Interceptor接口用于自定义拦截器
步骤:
1)编写类,实现Interceptor接口
2)在struts.xml文件中定义和使用拦截器
<package name="inter" extends="struts-default" namespace="/inter"> <!-- 定义拦截器 --> <interceptors> <interceptor name="inter1" class="gz.itcast.a_interceptor.MyInterceptor1"></interceptor> </interceptors> <action name="user_*" class="gz.itcast.a_interceptor.UserAction" method="{1}"> <!-- 使用拦截器 --> <interceptor-ref name="inter1"></interceptor-ref> <result>/index.jsp</result> </action> </package> |
注意1:拦截器的执行顺序:
启动:1)拦截器对象创建,调用拦截器的init方法访问
访问:2)创建Action对象
3)执行拦截器的intercepot方法
3.1 执行拦截器前面的代码(invocation.invoke();方法之前的)
3.2 执行 invocation.invoke(); 放行执行下一个拦截器或Action的方法
3.3 执行拦截器后面的代码(invocation.invoke();方法之后的)
注意2:拦截器范围:
局部使用:action内起作用(interceptor-ref)
全局使用:当前包内起作用:(default-interceptor-ref)
全局使用拦截器会覆盖原有拦截器,应使用拦截器栈包含原有的拦截器
1.3 拦截器栈
概念: 当一个或多个Action同时被多个拦截器所拦截,就可以使用拦截器栈。
<interceptors> <interceptor name="inter1" class="gz.itcast.a_interceptor.MyInterceptor1"></interceptor> <interceptor name="inter2" class="gz.itcast.a_interceptor.MyInterceptor2"></interceptor> <!-- 定义栏截器栈 --> <interceptor-stack name="interStack"> <interceptor-ref name="inter1"></interceptor-ref> <interceptor-ref name="inter2"></interceptor-ref> </interceptor-stack> </interceptors> |
注意1:定义拦截器栈的时候,引用拦截器的顺序决定了创建拦截器对象的顺序。(先指定就先创建)
注意2: 当前有了拦截器栈(多个拦截器)的执行顺序:
启动:
1)创建拦截器inter1对象,调用init方法
2)创建拦截器inter2对象,调用init方法
访问:
3)执行inter1的invocation.invoke()前面代码
4)执行inter2的invocation.invoke()前面代码
5)Action的业务方法
6)执行inter2的invocation.invoke()后面代码
7)执行inter1的invocation.invoke()后面代码
注意3: 当我们的包下引用了自定以拦截器,则会把默认包下的default-stack拦截器给覆盖掉!!!
这时需要这么做(拦截器栈的嵌套):
<interceptor-stack name="myStack"> <interceptor-ref name="defaultStack"></interceptor-ref><!-- 引入了默认的18个拦截器 --> <interceptor-ref name="interStack"></interceptor-ref><!-- 引入自定义的2个拦截器 --> </interceptor-stack> |
1.4 struts2的核心流程图(关键):
2值栈
2.1 Ognl表达式简介
l OGNL表达式
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
EL表达式: 获取域对象的数据。 不能存放数据,不能调用方法 Ognl表达式: 获取域对象的数据。 可以存放数据,可以调用方法。 |
OGNL的优势:
1、支持对象方法调用,如xxx.doSomeSpecial(); 2、支持类静态的方法调用和值访问,表达式的格式: @[类全名(包括包路径)]@[方法名 | 值名],例如: @java.lang.String@format('foo %s', 'bar') 或@tutorial.MyConstant@APP_NAME; 3、支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80; 4、访问OGNL上下文(OGNL context)和ActionContext; 5、操作集合对象。 |
2.2 Ognl表达式核心OgnlContext对象
1)普通存取OgnlContext数据
OgnlContext context = new OgnlContext(); //1)创建一个OgnlContext对象 context.put("user", user);//2)把user对象存入OgnlContext对象 User user2 = (User)context.get("user");//3)从OgnlContext对象取出数据 |
2)使用Ognl表达式取出OgnlContext的数据,如果是非根对象数据,那么使用#号去取
OgnlContext context = new OgnlContext(); context.put("user", user);//往OgnlContext的非根对象 存数据 Object ognlObj = Ognl.parseExpression("#user.age");//表达式对象 Object result = Ognl.getValue(ognlObj, context, context.getRoot()); //获取数据方法 System.out.println(result); |
3)往OgnlContext的根对象存取数据,不需要使用#号,不需要key名称,直接写存入对象的属性即可!!!
OgnlContext context = new OgnlContext(); context.setRoot(user);往OgnlContext的根对象 存数据 Object ognlObj = Ognl.parseExpression("name");//Ognl表达式对象 Object result = Ognl.getValue(ognlObj, context, context.getRoot()); //获取数据方法 |
4)Ognl表达式调用静态方法
//java.util.Math OgnlContext context = new OgnlContext(); Object ognlObj = Ognl.parseExpression("@java.lang.Math@round(10.5)");//表达式对象(lang包可以只写类名) Object result = Ognl.getValue(ognlObj, context, context.getRoot()); //获取数据方法 |
2.3 struts2的值栈(ValueStack)对象(利用OgnContext对象)
ValueStack接口,最终在项目中存储数据的对象是ValueStack的实现类OgnlValueStack
ValueStack的数据存储结构:分为List栈(根栈)和Map栈(非根栈)
1)List栈主要存储Action对象和Provider代理对象
2)Map栈主要存放各个域存放的数据和用户的参数信息
* 在用户每次访问action对象的业务方法时,struts2框架会创建ActionContext对象 (OgnlValueStack对象(Action对象))
1)往域对象存放数据(非根栈)
ac.getContextMap().put("request_data", "data"); ac.getSession().put("session_data", "data"); ac.getApplication().put("application_data", "data"); |
2)向List栈存取数据(根栈)
注:定义了JavaBean结构,就会在List栈中显示,可以直接在页面获取,用Push会增加对象。
//1)获取ActionContext对象 ActionContext ac = ActionContext.getContext(); ac.getContextMap().put("userList", list); //2)从ActionContext对象获取OnglValueStack对象 ValueStack vs = ac.getValueStack(); //3)往OgnlValueStack的根对象(List栈)存放数据 vs.push(user);//往Lis栈存放数据(栈顶) vs.pop(); //从List栈中取出元素(栈顶元素) |
2.4页面获取值栈(ValueStack)数据
<%@ taglib uri="/struts-tags" prefix="s"%><%-- 导入struts2标签 --%> <%--查看值栈的所有数据 --%> <s:debug></s:debug><br/> <%-- 1)取出List栈的数据 --%> <s:property value="user.name"/> <br/> <%--2)取出Map栈的数据 --%> <s:property value="#request.request_data"/><br/> <s:property value="#session.session_data"/><br/> <s:property value="#application.application_data"/><br/> <%-- #attr : 类似于findAttribute. 依次从小到大在三个域中搜索数据: #request-> #session -> #application --%> <s:property value="#attr.session_data"/><br/> <s:property value="#parameters.name"/><br/> <hr/> <%-- 遍历集合 :List、Map--%> <s:iterator value="#request.userList" var="user"> 姓名: <s:property value="#user.name"/> - <s:property value="#user.age"/><br/> </s:iterator> |
3数据验证
struts2提供给开发者进行表单数据的后台数据验证的功能。
3.1 用代码方式对action的所有方法进行验证
struts2的数据验证的核心拦截器(jar包内已注册):
<interceptor name="validation" class="com.opensymphony.xwork2.validator.ValidationInterceptor"/> |
开发步骤:
1)Action类继承ActionSupport(为了实现Valiateable接口)
2)Action类覆盖validate方法(验证所有方法)
* 如果validate方法中出现异常,那么把错误信息放入错误信息Map集合,就直接返回错误页面
super.addFieldError("user.error.requried", "用户名不能为空!");
* 如果validate没有出现异常,那么直接运行业务方法(register)
3)在struts.xml文件中对应的action配置加上input视图,然后struts2就会自动把错误信息转发到input视图的页面上去
<result name="input">/register.jsp</result> |
4)在input视图页面上,打印出错误信息
<s:fielderror></s:fielderror> |
注意:
validate()方法对当前Action下的所有方法都会有效!!!!
3.2 用代码方式对action的指定方法进行验证
第二步骤的验证方法名称为 validate+需要验证的方法名称
例如: validateRegister() -> 可以验证register()方法
3.3 用xml配置方式对action的所有方法进行验证
xml配置数据验证的规则:
1)编写一个xml文件,名称: Action文件名-validation.xml
2)该xml文件必须放在Action文件的同一目录
注意: 这种配置方式会对action下的所有方法都生效!!!
3.4 用xml配置方式对action的指定方法进行验证
xml配置数据验证的规则:
1)编写一个xml文件,名称: Action文件名-访问方法路径-validation.xml
例如: UserAction的register方法: user_register路径访问
文件名: UserAction-user_register-validation.xml
2)该xml文件必须放在Action文件的同一目录
<validators> <!-- 验证用户名 --> <field name="user.name">(Action中需要验证的属性名称) <!-- type: 代表xwork中定义的可以使用的验证类型 --> <field-validator type="requiredstring">(验证类型) <!-- 当出现错误时,提示的错误信息 --> <message>用户名必填</message>(出现之后页面显示的信息) </field-validator> <field-validator type="stringlength"> <param name="minLength">6</param>(注入到验证类型类中的属性) <param name="maxLength">16</param> <!-- 注入正则的字符串 --> <param name="expression">^[a-zA-Z0-9]{4,12}$</param> <message>用户名必须是6-16位</message> </field-validator> </field> </validators> |
验证类型:
name="required" name="requiredstring" name="int" name="long" | name="short" name="double" name="date" name="expression" | name="fieldexpression" name="email" name="url" name="visitor" | name="conversion" name="stringlength" name="regex" name="conditionalvisitor" |
4 struts2中简化国际化的使用
1)准备不同国家的资源包
中国: message_zh_CN.properties(user=用户名)
美国: message_en_US.properties (user=username)
英国: message_en_GB.properties
2)在struts.xml文件中(修改)指定资源包加载路径的常量
struts.custom.i18n.resources=message
<constant name="struts.custom.i18n.resources" value="resources.message"></constant> |
3)在页面上使用资源包的内容
<s:text name="user"></s:text>
4)在程序中获取内容
action.getText("user");
5 防止页面的重复提交
默认情况下,struts2不支持防止重复提交的
需要在struts.xml文件中打开功能:
1) 需要在struts.xml文件中打开功能
<interceptors> <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="token"></interceptor-ref> </interceptor-stack> </interceptors> |
//当重复提交的时跳转页面 <result name="invalid.token">/model.jsp</result> |
2)在jsp页面表单内指定一个标签:<s:token></s:token>
6 Ognl常用的符号
1) { } 创建List集合
<%-- ognl表达式: 在jsp页面中创建List集合(不需要#) --%> <s:iterator value="{'eric','jacky','rose','lucy'}" var="name"> <s:property value="#name"/><br/> </s:iterator> |
2) #{ } 创建Map集合
<%-- ognl表达式: 在jsp页面中创建Map集合(需要#号) --%> <s:iterator value="#{1:'eric',2:'jacky',3:'rose',4:'lucy'}" var="entry"> 编号: <s:property value="#entry.key"/>-姓名:<s:property value="#entry.value"/><br/> </s:iterator> |
3)%{ } 把内容引入Ognl运行环境
<s:textfield name="userName" value="%{#request.userName}"></s:textfield> |