Struts2(四)

1. Struts2中的拦截器

1.1 Struts2的拦截器基本概念

1.1.1 拦截器概述

在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者在定义的action执行的前后加入执行的代码,也可以在一个action执行前阻止其执行。也就是说它提供了一种可以提取action中可重用代码,统一管理和执行的方式

拦截器链 (Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

拦截器和过滤器是有几分相似,但是也有区别:

  • 过滤器是servlet规范中的一部分,任何java web工程都可以使用。
  • 拦截器是struts2框架自己的,只有使用了struts2框架的工程才能用。
  • 过滤器在url-pattern中配置了**/***之后,可以对所有要访问的资源拦截。
  • 拦截器它是只有进入struts2核心内部之后,才会起作用,如果访问的是jsp,html,css,image或者js是不会进行拦截的。

同时,拦截器还是AOP编程思想的具体体现形式。**AOP(Aspect-Oriented Programming)**简单的说就是:

  • 在不修改源码的基础上,已有的方法进行动态增强。
  • 在struts2中,拦截器它就是对我们的动作方法进行增强。(其实就是把重复性的代码提取出来,然后放到拦截器中,统一管理,统一调用)

1.1.2 拦截器的执行时机

在访问struts2核心内部时,在动作方法执行之前先正序执行,然后执行动作方法,执行完动作方法和结果视图之后,再倒序执行。**所以它是先进后出,是个栈的结构。**具体可参考下图:

image-20200608142116219

1.2 自定义拦截器

直接或间接的实现Interceptor接口

public interface Interceptor extends Serializable {
    void init();
    void destroy();
    String intercept(ActionInvocation invocation) throws Exception;
}

该接口提供了三个方法,其具体介绍如下。

  • void init():该方法在拦截器被创建后会立即被调用, 它在拦截器的生命周期内只被调用一次. 可以在该方法中对相关资源进行必要的初始化。
  • void destroy():该方法与init方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器相关的资源。它在拦截器的生命周期内,也只被调用一次。
  • String intercept(ActionInvocation invocation) throws Exception:该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求, 该方法就会被调用一次。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该参数的invoke()方法,将控制权转给下一个拦截器或者转给Action的execute()方法。

继承抽象拦截器类AbstractIntercepter

public abstract class AbstractInterceptor implements Interceptor {
    public void init() {}
    public void destroy() {}
    public abstract String intercept(ActionInvocation invocation) throws Exception;
}

AbstractInterceptor有一个子类MethodFilterInterceptor,该类中提供了两个属性,可以告知拦截器对哪些方法进行拦截或者对哪些方法排除。

img

1.2.1 第一步:编写普通java类,继承AbstractInterceptor

/**
 * 自定义拦截器
 * 步骤:
 *  第一步:编写一个普通类,继承AbstractInterceptor(也可以实现Interceptor接口)
 *  第二步:配置拦截器
 *      <!-- 声明一个拦截器 -->
 *      <interceptors>
 *          <interceptor name="myInterceptor" class="com.itheima.web.interceptors.MyInterceptor"></interceptor>
 *      </interceptors>
 *      <!-- 引用拦截器:写在action标签的内部。当我们写了自己的拦截器引用时,默认的拦截器栈就失效了 -->
 *      <interceptor-ref name="myInterceptor"></interceptor-ref>
 *  拦截器的放行:
 *      invocation.invoke();
 *  返回值的内容是:
 *      动作方法的返回值
 *  关于结果视图的执行时机以及拦截器的返回值问题
 *      在放行之前,拦截器的返回值可以控制显示哪个结果视图。一旦放行之后,它一定会显示动作方法返回值所匹配的结果视图,此时已经不管拦截器返回什么内容。
 *  多个拦截器的执行顺序问题:
 *      是由引用顺序决定的,与声明顺序无关
 *
 * @author wgy
 */
public class MyInterceptor extends AbstractInterceptor {

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("访问Action之前:MyInterceptor拦截了。。。。");
        //放行
        String rtValue = invocation.invoke();
        System.out.println("访问Action之后:MyInterceptor拦截了。。。。");
        return rtValue;
    }
}

1.2.2 第二步:在struts.xml中配置拦截器

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.devMode" value="true"/>

    <package name="p1" extends="struts-default">
        <!-- 声明一个拦截器 -->
        <interceptors>
            <interceptor name="myIntercepter" class="com.wgy.web.interceptors.MyInterceptor"/>
        </interceptors>

        <action name="demo1" class="com.wgy.web.action.Demo1Action" method="demo1">
            <!-- 引用拦截器:当我们写了自己的拦截器引用时,默认的拦截器栈就失效了 -->
            <interceptor-ref name="myIntercepter"/>
            <result>/success.jsp</result>
        </action>
    </package>
</struts>

1.3 案例-检查登录拦截器

1.3.1 定义拦截器

/**
 * 检查登录拦截器
 *
 * @author wgy
 */
public class CheckLoginInterceptor2 extends MethodFilterInterceptor {

    @Override
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        Object obj = ServletActionContext.getRequest().getSession().getAttribute("userinfo");
        if(obj == null){
            //没登录,去登录
            return "login";
        }
        //已登录,就放行
        return invocation.invoke();
    }
}

1.3.2 配置拦截器

<package name="myDefault" extends="struts-default" abstract="true">
    <!-- 声明拦截器 -->
    <interceptors>
        <interceptor name="checkLogin" class="com.wgy.web.interceptors.CheckLoginInterceptor2"/>
        <!-- 定义一个自己的拦截器栈 -->
        <interceptor-stack name="myDefaultStack">
            <interceptor-ref name="checkLogin">
                <!-- 告知拦截器,哪些方法需要拦截,哪些方法不需要拦截 -->
                <param name="excludeMethods">userLogin</param>
            </interceptor-ref>
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
    </interceptors>
    <!-- 把我们自定义的拦截器栈声明为默认拦截器栈 -->
    <default-interceptor-ref name="myDefaultStack"/>
    <global-results>
    	<result name="login">/login.jsp</result>
    </global-results>
</package>

1.3.3 编写和配置Action

动作类

public class BBSAction extends ActionSupport implements ServletRequestAware {

    private HttpServletRequest request;

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }

    /**
     * 娱乐
     * @return
     */
    public String demo1(){
        System.out.println(request);
        return SUCCESS;
    }

    /**
     * 体育
     * @return
     */
    public String demo2(){
        System.out.println(request);
        return SUCCESS;
    }

    /**
     * 军事
     * @return
     */
    public String demo3(){
        System.out.println(request);
        return SUCCESS;
    }

    /**
     * 登录方法
     * @return
     */
    public String userLogin(){
        //往session域中存入一个登录标记
        ServletActionContext.getRequest().getSession().setAttribute("userinfo", "");
        return SUCCESS;
    }
}

配置

<package name="p1" extends="myDefault">
    <action name="demo1" class="com.wgy.web.action.BBSAction" method="demo1">
    	<result name="success">/demo1.jsp</result>
    </action>

    <action name="demo2" class="com.wgy.web.action.BBSAction" method="demo2">
    	<result name="success">/demo2.jsp</result>
    </action>

    <action name="demo3" class="com.wgy.web.action.BBSAction" method="demo3">
    	<result name="success">/demo3.jsp</result>
    </action>

    <action name="login" class="com.wgy.web.action.BBSAction" method="userLogin">
    	<result name="success" type="redirect">/main.jsp</result>
    </action>
</package>

2. Struts2的注解配置

2.1 使用前提

Struts2框架,它不仅支持基于XML的配置方式,同时也支持基于注解配置的方式。

注解和XML的配置,都是告知struts2框架,当我们jsp页面发送请求,根据配置执行对应动作类的方法,并根据返回值,前往指定的结果视图(jsp页面或者其他动作)。它们只是配置的形式不一样。

其次要想使用struts2的注解,必须要导入一个新的jar包。该jar包是: struts2-convention-plugin-2.3.24.jar

2.2 常用注解

2.2.1 @NameSpace

出现的位置:
    它只能出现在package上或者Action类上。一般情况下都是写在Action类上。
作用:
    指定当前Action中所有动作方法的名称空间。
属性:
    value:指定名称空间的名称。写法和xml配置时一致。不指定的话,默认名称空间是""。
示例:
@Namespace("/customer")
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {

    private Customer customer = new Customer();
    
    @Override
    public Customer getModel() {
        return customer;
    }
}

2.2.2 @ParentPackage

出现的位置:
    它只能出现在package上或者Action类上。一般情况下都是写在Action类上。
作用:
    指定当前动作类所在包的父包。由于我们已经是在类中配置了,所以无需在指定包名了。
属性:
    value:指定父包的名称。
示例:
@ParentPackage("struts-default")
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {

    private Customer customer = new Customer();
    
    @Override
    public Customer getModel() {
        return customer;
    }
}

2.2.3 @Action

出现的位置:
    它只能出现在Action类上或者动作方法上。一般情况下都是写在动作方法上。
作用:
    指定当前动作方法的动作名称。也就是xml配置时action标签的name属性。
属性:
    value:指定动作名称。
    results[]:它是一个数组,数据类型是注解。用于指定结果视图。此属性可以没有,当没有该属性时,表示不返回任何结果视图。即使用response输出响应正文。
    interceptorRefs[]:它是一个数组,数据类型是注解。用于指定引用的拦截器。
示例:
/**
 * 获取添加客户页面
 * @return
 */
@Action(value="addUICustomer",results={
    @Result(name="addUICustomer",location="/jsp/customer/add.jsp")
})
public String addUICustomer(){
    return "addUICustomer";
}

2.2.4 @Result

出现的位置:
    它可以出现在动作类上,也可以出现在Action注解中。
作用:
    出现在类上,表示当前动作类中的所有动作方法都可以用此视图。
    出现在Action注解中,表示当前Action可用此视图。
属性:
    name:指定逻辑结果视图名称。
    type:指定前往视图的方式。例如:请求转发,重定向,重定向到另外的动作。
    location:指定前往的地址。可以是一个页面,也可以是一个动作。
示例:
/**
 * 保存客户
 * @return
 */
@Action(value="addCustomer",results={
    @Result(name="addCustomer",type="redirect",location="/jsp/success.jsp")
})
public String addCustomer(){
    customerService.saveCustomer(customer);
    return "addCustomer";
}

2.2.5 @Results

出现的位置:
    它可以出现在动作类上,也可以出现在Action注解中。
作用:
    用于配置多个结果视图。
属性:
    value:它是一个数组,数据类型是result注解。
示例:
@Results({
    @Result(name="login",location="/login.jsp"),
    @Result(name="error",location="/error.jsp")
})
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {

    private Customer customer = new Customer();
    
    @Override
    public Customer getModel() {
        return customer;
    }
}

2.2.6 @InterceptorRef

出现的位置:
    它可以出现在动作类上或者Action注解中。
作用:
    用于配置要引用的拦截器或者拦截器栈
属性:
    value:用于指定拦截器或者拦截器栈
示例:
出现在动作方法上:
/**
 * 查询所有客户
 * @return
 */
@Action(value="findAllCustomer",
    results={
    	@Result(name="findAllCustomer",location="/jsp/customer/list.jsp")
    },
    interceptorRefs={
    	@InterceptorRef("myDefaultStack")
    }
)
public String findAllCustomer(){
    customers = customerService.findAllCustomer();
    return "findAllCustomer";
}

出现在动作类上:
@InterceptorRef("myDefaultStack")
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {

    private Customer customer = new Customer();
    
    @Override
    public Customer getModel() {
        return customer;
    }
}

2.3 案例-注解实现客户保存和查询列表

2.3.1 拷贝必备jar包

导入jar包: struts2-convention-plugin-2.3.24.jar

2.3.2 使用注解配置Action

/**
 * 客户的动作类
 *
 * @author wgy
 */
@ParentPackage("struts-default")//指定当前包的父包
@Namespace("/customer")
@Results({
        @Result(name="customerList",type="redirect",location="findAllCustomer.action"),
        @Result(name="error",location="/jsp/error.jsp"),
        @Result(name="addUICustomer",location="/jsp/customer/add.jsp"),
        @Result(name="findAllCustomer",location="/jsp/customer/list.jsp")
})
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {

    private ICustomerService customerService = new CustomerServiceImpl();

    private Customer customer = new Customer();

    private List<Customer> customers;

    @Override
    public Customer getModel() {
        return customer;
    }

    /**
     * 查询所有客户
     * @return
     */
    @Action("findAllCustomer")
    public String findAllCustomer(){
        //1.调用service查询客户
        List<Customer> customers = customerService.findAllCustomer();
        //2.返回
        return "findAllCustomer";
    }

    /**
     * 获取添加客户页面
     * @return
     */
    @Action("addUICustomer")
    public String addUICustomer(){
        return "addUICustomer";
    }

    /**
     * 添加客户
     * @return
     */
    @Action("addCustomer")
    public String addCustomer(){
        customerService.saveCustomer(customer);
        return "customerList";
    }

    /**
     * 删除客户
     * @return
     */
    @Action("deleteCustomer")
    public String deleteCustomer(){
        customerService.deleteCustomer(customer);
        return "customerList";
    }

    //------getters and setters--------------

    public List<Customer> getCustomers() {
        return customers;
    }

    public void setCustomers(List<Customer> customers) {
        this.customers = customers;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值