Struts2基础复习系列(5)

十、 拦截器

1. 拦截器在struts2的作用(引用轻量级JavaEE企业应用实战第四版)

a. 连接器把大部分核心控制器需要完成的工作按功能分开定义,每个拦截器完成一个功能。而这些拦截器可以自由选择,灵活组合,甚至不用任何拦截器,开发者需要使用哪些拦截器,只需要在struts.xml文件中进行配置即可。
b. struts2框架的绝大部分功能都是通过拦截器完成的。当StrutsPrepareAndExecuteFilter拦截到用户请求后,大量拦截器会对用户请求进行处理,然后调用用户开发的Action实例来处理请求。
c. struts2默认开启大量通用功能拦截器,只要继承了struts-default包即可起作用。

拦截器与Action关系如下:
拦截器与Action关系

2. 拦截器配置

a. 只需要为拦截器类指定一个拦截器名,配置如下
<interceptor/><interceptor name=”拦截器名” class=”拦截器实现类”/>
还可以通过<parm name=”参数名”>参数值</param>指定拦截器相应参数。
b. 拦截器栈,配置方法如下:
<interceptor-stack name=”拦截器栈名称”>
        <interceptor-ref name=”拦截器一”>
        <interceptor-ref name=”拦截器二”>
        <interceptor-ref name=”拦截器三”></interceptor-stack>    

还可以在interceptor-ref中配置参数,同样利用

<parm name=”参数名”>参数值</param>

的方式。另外,每个拦截器栈还可以继续引用别的拦截器栈。

<interceptor-stack name=”拦截器栈一”>
        <interceptor-ref name=”拦截器一”>
        <interceptor-ref name=”拦截器二”></interceptor-stack>    
        <interceptor-stack name=”拦截器栈二”>
        <interceptor-ref name=”拦截器三”>
        <interceptor-ref name=”拦截器栈一”></interceptor-stack>    
c. 配置时需要interceptors标签将配置信息包裹。如下:
<interceptors>
<interceptor name=”拦截器一” class=”拦截器一实现类”/>
            <interceptor-stack name=”拦截器栈一”>
            <interceptor-ref name=”拦截器一”></interceptor-stack>    
</interceptors>
d. 配置默认拦截器:<default-interceptor-ref name=”拦截器名或拦截器栈名”>
e. 上面的配置必须在package标签先进行的
  1. 实现拦截器
    struts2所定义的拦截器接口,Interceptor接口
public interface Interceptor extends Serializable {
        //销毁方法,在拦截器实例被销毁前调用,一般用于关闭init打开的资源
                void destroy();
//初始化方法,在执行interceptor前,系统回调此方法,只执行一次,一般用//于初始化资源
            void init();
            //执行相应的拦截操作
String intercept(ActionInvocation invocation) throws Exception;
}
  1. 使用示例:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<constant name="struts.configuration.xml.reload" value="true"></constant>
<package name="interceptor"  extends="struts-default" namespace="/">
    <interceptors>
        <interceptor name="loginInterce" class="com.struts.interceptor.LogInterceptor"></interceptor>
    </interceptors>

    <action method="{1}" name="login_*" class="com.struts.review1.LoginAction">
        <result name="success">/success.jsp</result>
        <interceptor-ref name="loginInterce"></interceptor-ref>
    </action>
</package>
</struts>    
    package com.review.domain;

public class Admin {

    private String loginId;
    private String pw;

    public String getLoginId() {
        return loginId;
    }
    public void setLoginId(String loginId) {
        this.loginId = loginId;
    }
    public String getPw() {
        return pw;
    }
    public void setPw(String pw) {
        this.pw = pw;
    }
    @Override
    public String toString() {
        return "Admin [loginId=" + loginId + ", pw=" + pw + "]";
    }
}

package com.struts.review1;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.review.domain.Admin;

public class LoginAction extends ActionSupport implements ModelDriven<Admin>{

    private Admin model = new Admin();

    public String login() {
        System.out.println(model);
        if(model.getLoginId().equals("FiShelly.") && model.getPw().equals("110210")){
            System.out.println("======= login success =======");
        }
        return SUCCESS;
    }

    @Override
    public Admin getModel() {
        // TODO Auto-generated method stub
        return model;
    }
}
    <form method="post" action="login_login.action">
        loginId:<input type="text" name="loginId"/><br>
        password:<input type="password" name="pw"/><br>
        <input type="submit" value="submit"/>
    </form>

部署运行会发现出现异常。
空指针异常
空指针异常
显然是空指针异常,通过控制台的错误提示,我们发现model对象的各个属性没被赋值,同时拦截器是被执行了,其中mode是通过模型驱动赋值的,而模型驱动又是依靠默认拦截器栈实现的,那么我们不妨推断下由于执行了自定义的拦截器,而导致默认拦截器栈没有执行。这样我们实验一下,将引用拦截器的代码注释掉。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<constant name="struts.configuration.xml.reload" value="true"></constant>
<package name="interceptor"  extends="struts-default" namespace="/">
    <interceptors>
        <interceptor name="loginInterce" class="com.struts.interceptor.LogInterceptor"></interceptor>
    </interceptors>

    <action method="{1}" name="login_*" class="com.struts.review1.LoginAction">
        <result name="success">/success.jsp</result>
        <!--  <interceptor-ref name="loginInterce"></interceptor-ref>-->
    </action>
</package>
</struts>    

成功
发现,运行成功了。这表示我们的推断是正确的,那么进一步,是什么原因导致默认拦截器栈没有被执行呢?首先,我们知道,由于基础了struts-default,而struts的默认拦截器栈又是在struts-default中定义的,因此我们定义的package应该是继承了struts的默认拦截器栈的,但是呢,由于我们自己配置了自定义的拦截器栈,导致struts先执行我们的自定义拦截器了,而没有去执行struts的默认拦截器栈,这样一来将导致没有拦截到http请求中参数信息,而导致空指针异常。那么接下来对代码的修改方式有2种。
第一种是直接在原有的<interceptor-ref>上在写多一个<interceptor-ref name=”defaultStack”>这样一来,struts就会先执行默认拦截器栈,在执行自定义的拦截器。

<action method="{1}" name="login_*" class="com.struts.review1.LoginAction">
        <result name="success">/success.jsp</result>
        <interceptor-ref name="defaultStack"></interceptor-ref>
        <interceptor-ref name="loginInterce"></interceptor-ref>
    </action>

第二种是自定义一个拦截器栈,在自定义的拦截器栈中引用struts2的默认拦截器栈。同时将包的默认拦截器栈换成我们自定义的拦截器栈。

<interceptors>
<interceptor name="loginIn" class="com.struts.interceptor.LogInterceptor"></interceptor>
        <interceptor-stack name="privilegeStack">
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <interceptor-ref name="loginIn"></interceptor-ref>
                <!-- 
                <interceptor-ref name="aa"></interceptor-ref>
                 -->
        </interceptor-stack>
</interceptors>
<default-interceptor-ref name="privilegeStack"></default-interceptor-ref>

这样一来,程序就可以成功执行。如下
成功
在这里顺便一提拦截器的执行顺序:通常认为,先配置的拦截器,会得到先执行的机会。但是实际上则是,在invocation.invoke()方法执行之前是顺序执行的,在其执行完之后是逆序的。其实也可以通过栈先进后出的思想来考虑,拦截器拦截,排第一个的先进栈执行,当到invocation.invoke()后则停住让排在后面的进栈执行,又遇到invocation.invoke()时停住,让后面的进栈执行,不断重复这个过程,直到最后一个拦截器进栈为止,当最后一个拦截器进栈执行完invocation.invoke()方法后,相应的则是依次出栈,出栈则是后进先出,这样一来就逆序执行了,但注意,这里可以这么理解,但实际上invocation.invoke()方法只会执行一次,而非多次的。
拦截器执行顺序

十一、 属性驱动与模型驱动

1. 上面说拦截器的是提到了模型驱动,因此在这里就来讲解下相关的知识。

首先是在Servlet中表单填写后封装成对象是比较麻烦的,因为需要重复使用request.getParameter这个方法,或者使用第三方框架来实现。但是在struts中则将这个过程变得简单了。因为struts2框架会帮我们做好封装的事情,前提是你得遵循struts定义好的规则。而struts2为我们提供了常用的两种封装属性的方式,一种是属性驱动,另一种则是模型驱动。通过这两种方式能够简单的将填写表单的内容封装成相应的对象。而实现这样方式的原理则是通过之前讲的拦截器来实现的。

2. 属性驱动

可以实现页面字符串与基本数据类型的转换。只需要在Action定义好相关需要封装的对象实例,提供set/get方法后即可,但是这里需要在页面表单的name属性中加入相关的前缀。
页面表单:

<form method="post" action="admin_add.action">
        loginId:<input type="text" name="admin.loginId"/><br>
        password:<input type="password" name="admin.pw"/><br>
        radio:<input type="radio" name="flag" value="0"/>否
<input type="radio" name="admin.flag" value="0"/>是<br>
        checked:<input type="checkbox" name="admin.hobby" value="aaa">aaa
                <input type="checkbox" name="admin.hobby" value="bbb">bbb
                <input type="checkbox" name="admin.hobby" value="ccc">ccc
                <input type="checkbox" name="admin.hobby" value="ddd">ddd
                <input type="checkbox" name="admin.hobby"value="eee">eee<br>
        <input type="submit" value="submit"/>
</form>
Admin.java:
package com.review.domain;

import java.util.Arrays;

public class Admin {

    private String loginId;
    private String pw;
    private String[] hobby;
    private int flag;

    public String getLoginId() {
        return loginId;
    }
    public void setLoginId(String loginId) {
        this.loginId = loginId;
    }
    public String getPw() {
        return pw;
    }
    public void setPw(String pw) {
        this.pw = pw;
    }
    public String[] getHobby() {
        return hobby;
    }
    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }
    public int getFlag() {
        return flag;
    }
    public void setFlag(int flag) {
        this.flag = flag;
    }
    @Override
    public String toString() {
        return "Admin [loginId=" + loginId + ", pw=" + pw + ", hobby="
                + Arrays.toString(hobby) + ", flag=" + flag + "]";
    }


}
    AdminAction.java
    private Admin admin ;
    public Admin getAdmin() {
        return admin;
    }
    public void setAdmin(Admin admin) {
        this.admin = admin;
    }
    public String add(){
        System.out.println(admin);
        return "success";
    }

表单显示:
表单
控制台输出:
输出

3. 模型驱动

使用模型驱动,则必须实现ModelDriven接口,并实现getmodel方法,返回model对象即可。用这种方式则可以在表单中省下填写前缀的步骤。

AdminAction.java:
public class AdminAction  extends ActionSupport implements ModelDriven<Admin> {

    private Admin model = new Admin();
    @Override
    public Admin getModel() {
        return model;
    }
    public String add(){
        System.out.println(model);
        return "success";
    }
}
<form method="post" action="admin_add.action">
        loginId:<input type="text" name="loginId"/><br>
        password:<input type="password" name="pw"/><br>
        radio:<input type="radio" name="flag" value="2"/>否<input type="radio" name="flag" value="1"/>是<br>
        checked:<input type="checkbox" name="hobby" value="aaa">aaa
                <input type="checkbox" name="hobby" value="bbb">bbb
                <input type="checkbox" name="hobby" value="ccc">ccc
                <input type="checkbox" name="hobby" value="ddd">ddd
                <input type="checkbox" name="hobby" value="eee">eee<br>
</form>

结果与属性驱动也是一样就不发出来了

4. 使用哪种属性驱动还是模型驱动

其实并没有特别的硬性要求一定要使用哪种,因此可以根据具体的要求具体而定,不过一般来说要么只是用属性驱动,要么就只使用模型驱动。

最近要考试,所以写的不多,今天先这么多吧,有不当的地方望指出~~谢谢

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值