JAVA基础知识Java学习笔记

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

2017-06-11  本文已影响10人  Acamy丶

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>
上一篇下一篇

猜你喜欢

热点阅读