struts2框架(四)拦截器,国际化,Ognl表达式

Intercetor, 即为拦截器。
1) 在Struts2中,把每一个功能都用一个个的拦截器实现;用户想用struts的哪个功能的时候,可以自由组装使用。
2)Struts2中,为了方法用户对拦截器的引用,提供了拦截器栈的定义,里面可以包含多个拦截器。 文件夹(文件, 文件2) 拦截器栈(拦截器,拦截器2)
3)Struts2中,如果用户没有指定执行哪些拦截器,struts2有一个默认执行的栈,defaultStack;
一旦如果用户有指定执行哪些拦截器,默认的拦截器栈就不会被执行
拦截器的设计,就是基于组件设计的应用!

1.自定义拦截器

1.1 编写辅助测试用action

public class HelloAction extends ActionSupport{
    public HelloAction() {
        System.out.println("1. Action实例创建了");
    }
    
    @Override
    public String execute() throws Exception {
        System.out.println("3. 执行了请求处理的方法: execute");
        return super.execute();
    }
}

1.2 编写拦截器类

public class HelloInterceptor implements Interceptor{
    
    // 启动时候执行
    public HelloInterceptor(){
        System.out.println("创建了拦截器对象");
    }

    // 启动时候执行
    @Override
    public void init() {
        System.out.println("执行了拦截器的初始化方法");
    }

    // 拦截器业务处理方法 (在访问action时候执行? 在execute之前执行?)
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("2. 执行Action之前");
        
        // 调用下一个拦截器或执行Action  (相当于chain.doFilter(..)
        // 获取的是: execute方法的返回值
        String resultFlag = invocation.invoke();
        
        System.out.println("4. 拦截器,业务处理-结束" + resultFlag);
        
        return resultFlag;
    }   

    @Override
    public void destroy() {
        System.out.println("销毁....");
    }
}

1.3 进行相关配置

<struts>
    <package name="hello" extends="struts-default"> 
        <!-- 【拦截器配置】 -->
        <interceptors>      
            <!-- 配置用户自定义的拦截器 -->
            <interceptor name="helloInterceptor" class="cn.itcast.a_interceptor.HelloInterceptor"></interceptor>
            
            <!-- 自定义一个栈: 要引用默认栈、自定义的拦截器 -->
            <interceptor-stack name="helloStack">
                <!-- 引用默认栈 (一定要放到第一行)-->
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <!-- 引用自定义拦截器 -->
                <interceptor-ref name="helloInterceptor"></interceptor-ref>
            </interceptor-stack>            
        </interceptors>
                
        <!-- 【执行拦截器,第一种写法: 当前包下所有的acntion都执行helloStack栈】 
        <default-interceptor-ref name="helloStack"></default-interceptor-ref>
        -->
    
        <!-- Action配置 -->
        <action name="hello" class="cn.itcast.a_interceptor.HelloAction">
        
            <!--执行拦截器,第二种写法: 只是在这一个Action中执行helloStack栈 
            <interceptor-ref name="defaultStackt"></interceptor-ref>
            <interceptor-ref name="helloInterceptor"></interceptor-ref>
            -->
            
            <!--执行拦截器,第三种写法:执行用户栈(与第二种写法一样, 只在当前aciton中执行自定义栈)-->
            <interceptor-ref name="helloStack"></interceptor-ref>            
        
            <result name="success">/index.jsp</result>
        </action>   
    
    </package>
</struts>

当我们访问helloAction时效果如下:

可以看到,如过滤器一样,拦截器的构造方法和初始化也是在tomcat服务器启动时执行,当用户访问action时,先创建action实例,然后执行过滤器intercept方法,再执行action的execute方法,执行完后回到intercept。最扣在tomcat停止服务时会销毁拦截器对象。生命周期时序图如下:

2.国际化

对比servlet的国际化,struts里面更简单

2.1 步骤

a). 写资源文件
基础名.properties  【默认的语言环境的配置】  
基础名_语言简称_国家简称.properties
b). 读取资源文件,再使用

程序:ResourceBundle (同servlet)
JSP:
1)jstl表亲啊 (同servlet)
2)struts标签获取资源文件内容

2.2 实例

1. 写资源文件

Msg.properties 默认的语言环境; 找不到配置就找它
Msg_en_US.properties 美国

2. 加载
<!-- struts.xml 通过常量加载资源文件 -->
    <constant name="struts.custom.i18n.resources" value="cn.acamy.config.msg"></constant>
3. 使用: 标签name值直接写配置文件中的key
<%@taglib uri="/struts-tags" prefix="s" %>
<s:text name="title"></s:text>
推荐用法:
  <s:i18n name="cn.acamy.config.msg">
        <s:text>  标签必须放到标签体中。
  </s:i18n>

3.Ognl表达式

OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。

3.1 OgnlContext 的用法

OGNL 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map 的接口。

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

import org.junit.Test;

// OgnlContext用法
public class OgnlDemo1 {

    /**
     * 1. Ognl表达式语言语言取值,取非根元素的值,必须用#号
     * @throws Exception
     */
    @Test
    public void testOgnl() throws Exception {
        // 创建一个Ognl上下文对象
        OgnlContext context = new OgnlContext();
        // 放入数据
        User user = new User();
        user.setId(100);
        user.setName("Jack");
        // 【往非根元素放入数据, 取值的时候表达式要用"#"】
        context.put("user", user);
        
        // 获取数据(map)
        // 先构建一个Ognl表达式, 再解析表达式
        Object ognl = Ognl.parseExpression("#user.name");
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        
        System.out.println(value);
    }
    
    /**
     * 2. Ognl表达式语言语言取值,取根元素的值,不用带#号
     * @throws Exception
     */
    @Test
    public void testOgn2() throws Exception {
        // 创建一个Ognl上下文对象
        OgnlContext context = new OgnlContext();
        // 放入数据
        User user = new User();
        user.setId(100);
        user.setName("Jack");
        // 【往根元素放入数据】
        context.setRoot(user);
        
        // 获取数据(map)
        // 先构建一个Ognl表达式, 再解析表达式
        Object ognl = Ognl.parseExpression("address.province");
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        
        System.out.println(value);
    }
    
    /**
     * 3.Ognl对 静态方法调用的支持
     * @throws Exception
     */
    @Test
    public void testOgn3() throws Exception {
        // 创建一个Ognl上下文对象
        OgnlContext context = new OgnlContext();
        
        // Ognl表单式语言,调用类的静态方法
        //Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
        // 由于Math类在开发中比较常用,所以也可以这样写
        Object ognl = Ognl.parseExpression("@@floor(10.9)");
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        System.out.println(value);
    }
}

3.2 ValueStack

ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础。
ValueStack贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前Action 对象和其他相关对象.Struts2框架把 ValueStack 对象保存在名为 “struts.valueStack” 的request请求属性中。

3.2.1 ValueStack的获取

    // 获取值栈对象的2种方式
    private void getVs() {
        // 获取值栈对象,方式1:
        HttpServletRequest request = ServletActionContext.getRequest();
        ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");

        // 获取值栈对象,方式2:
        ActionContext ac = ActionContext.getContext();
        ValueStack vs2 = ac.getValueStack();

        System.out.println(vs1 == vs2);// true
    }

3.2.2 ValueStack的数据结构

通过调试可以看到:struts中的ValueStack为其实现类OgnlValueStack,核心包含了作为Map栈的OgnlContext对象和继承了ArrayList的对象栈的CompoudRood对象,其中OgnlContext还封装了CompoudRood对象。

数据结构图如下:

对象栈: Struts  把动作和相关对象压入 ObjectStack 中--List
Map栈: Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中
    Struts 会把下面这些映射压入 ContextMap 中
        parameters: 该 Map 中包含当前请求的请求参数
        request: 该 Map 中包含当前 request 对象中的所有属性
        session: 该 Map 中包含当前 session 对象中的所有属性
        application:该 Map 中包含当前 application  对象中的所有属性
        attr: 该 Map 按如下顺序来检索某个属性: request, session, application

3.3 Ognl表达式

3.3.1 #的作用

a) 用来区分访问的是Map栈不审List栈

 #号主要用于访问访问Map栈信息,不使用#号主要用于访问List(对象栈)信息。
 举例:
      <s:property value="#request.username"/>
      <s:property value="#request.userpsw"/>
      <s:property value="address"/>    // 获取对象栈信息(默认从栈顶检索)

Struts2的property 标签中value属性值会特意的将其中的值以OGNL表达式的方式进行运行。

b) 在JSP页面构建Map集合

格式:#{key:value,key:value...}
举例
      Struts2的radio标签主要任务是在页面中显示单选按钮
      <s:radio list="#{'male':'男','female':'女'}" name="gender"></s:radio><br/>
      运行结果源码:
       <input type="radio" name="gender" id="gendermale" value="male"/>男
       <input type="radio" name="gender" id="genderfemale" value="female"/>女

3.3.2 $号的作用

$号的作用
      在国际化资源文件中,引用OGNL表达式
      在Struts2配置文件中,引用OGNL表达式
举例
      ognl.xml配置文件
       <action name="ognlAction_*" class="cn.itcast.ognl.OgnlAction" method="{1}">
              <result name="success">/ognl/ognl.jsp?username=${#request.username}</result>
       </action>
       在ognl.jsp中获取携带的参数:
       <s:property value="%{#parameters.username[0]}"/>

3.3.3 %号的作用

$号的作用
      “%”符号的作用是在当Struts2标签的属性值为OGNL表达式时OGNL表达式却被理解为字符串类型原样输出时,用于通知执行环境%{}里的是OGNL表达式。 
举例
      Struts2中的textfield标签主要用于在页面中显示一个文本输入框数据。类似input
      <s:textfield value="#request.username"></s:textfield>
      此时#request.username被理解为一个普通的字符串,因此直接显示。因为这里脱离了
      运行OGNL的环境即:<s:property value="OGNL表达式"/>环境。
      通知运行环境将#request.username以OGNL表达式运行:
      <s:textfield value="%{#request.username}"></s:textfield>
总结
       为了方便使用%{}我们可以在任何地方都直接添加%{}来确保运行OGNL表达式:
       <s:property value="%{#request.username}"/>

4.Struts2标签

4.1 if/elseif/else标签

if/elseif/else 基本的流程控制.‘If’标签可单独使用也可以和‘Else If’标签和(或)一个多个‘Else’一起使用

<s:if test="#person.age<24">少年</s:if>
<s:elseif test="#person.age<26">中年</s:elseif>
<s:else>老年</s:else>

4.2 property标签

用于输出指定值:

格式:
<s:property value=“#name" default="a default value" />     
 default:可选属性, 如果需要输出的属性值为null,则显示该属性指定的值
 escape:可选属性,指定是否格式化HTML代码。
 value:   可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值。

举例:
<s:property value="#user.id"/>
<s:property/>:输出栈顶的值

4.3 debug标签

struts的调试标签:可以观测值栈数据

<s:debug></s:debug>

4.4 iterator标签

用于对集合进行迭代,这里的集合包含List、Set和数组。

<!-- list迭代 -->
<s:iterator var="user" value="#request.list" status="st">
    <s:property value="#user.id"/>
    <s:property value="#user.name"/>
</s:iterator>

<!-- map迭代 -->
<s:iterator var="en" value="#request.map" status="st
    <s:property value="#en.key"/>
    <s:property value="#en.value.name"/>
</s:iterator>

    <!-- Ognl表达式可以取值,也可以动态构建集合 -->
    <br/>一、.构建 list集合</br>
    <s:iterator var="str" value="{'a','b'}">
        <s:property value="#str"/>
    </s:iterator>
    
     <br/>一、.构建 map集合</br>
     <s:iterator var="en" value="#{'cn':'China','usa':'America'}">
        <s:property value="#en.key"/>
        <s:property value="#en.value"/>  <br/>
     </s:iterator>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容