Struts2第七篇【介紹攔截器、自定義攔截器、執行流程、應用】

什麼是攔截器

攔截器Interceptor…..攔截器是Struts的概念,它與過濾器是相似的…能夠近似於看做是過濾器html

爲何咱們要使用攔截器

前面在介紹Struts的時候已經講解過了,Struts爲咱們實現了不少的功能,好比數據自動封裝阿..文件上傳功能阿….Struts爲咱們提供的這些功能都是經過攔截器完成的……java

  • 數據自動封裝經過<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>這個攔截器。
  • 文件上傳經過<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>這個攔截器

攔截器的設計就是基於組件設計的應用mysql

再次回顧攔截器基礎

在開始講解Struts的時候已經說明過了struts-default.xml這個文件,它定義了Struts的全部攔截器。由於咱們在啓動服務器的時候會自動裝載這個文件,所以咱們才能夠在Action中使用到Struts爲咱們提供的功能【數據自動封裝…文件上傳】web

在struts-default.xml中定義的攔截器就有32個之多,Struts2爲了方便咱們對攔截器的引用,提供了攔截器棧的定義。sql

<interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="debugging"/>
            </interceptor-stack>

也就是說:當咱們要引用多個攔截器的時候,只要把攔截器都放在棧裏頭,在外邊引用攔截器便可!數據庫

值得注意的是:Struts2默認執行的是默認攔截器棧,一旦用戶有指定執行哪些攔截器,那麼默認的攔截器棧就不會被執行!apache


自定義攔截器

Struts2容許咱們自定義攔截器,這就使咱們可以更加靈活地操做Struts2這個框架了!服務器

Struts2提供了Interceptor這個攔截器接口,只要咱們實現這個接口,那麼這就算是自定義開發攔截器了。markdown

固然啦,大部分時候,咱們定義攔截器都是繼承AbstractInterceptor這個類….爲了學習攔截器的內容,下面就實現Interceptor這個接口了。session

編寫攔截器類

  • 當實現該接口時,有3個須要咱們實現的方法:
public class MyInterceptor implements Interceptor { @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation actionInvocation) throws Exception { return null; } } 

init()和destory()都是和攔截器執行順序有關的方法,咱們如今先不理會….首先來說解intercept這個方法

/** * @param actionInvocation 攔截器的執行狀態 */
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {

        //調用invoke()方法,表明着放行執行下一個攔截器,若是沒有攔截器了,那麼就執行Action的業務代碼
        actionInvocation.invoke();
        return null;
    }

這很容易就能讓咱們想起在學習過濾器中的doFilter()方法,實際上是差很少的!


在struts.xml中配置

像Struts默認的攔截器同樣,咱們自定義的攔截器是須要咱們在struts中配置的。

因爲咱們配置了自定義攔截器,那麼struts默認的攔截器棧是不會執行的。若是咱們想要使用默認攔截器棧的功能,就必須把它配置在咱們自定義的棧中!

<package name="xxx" extends="struts-default" >

        <interceptors>
            <!--配置用戶自定義的攔截器-->
            <interceptor name="MyInterceptor" class="TestAction"/>

            <!--自定義攔截器棧,咱們配置了自定義的攔截器,默認的攔截器棧就不會被執行,所以,想要使用默認的攔截器功能,就要配置進來-->
            <interceptor-stack name="mystack">
                <!--引用默認的攔截器棧,必定要放在第一行-->
                <interceptor-ref name="defalutStack"/>

                <!--引用自定義的攔截器-->
                <interceptor-ref name="MyInterceptor"/>
            </interceptor-stack>
        </interceptors>

        <!--上面配置了攔截器棧,可是沒有被執行...下面配置執行攔截器-->
        <default-interceptor-ref name="mystack"/>

        <action name="TestAction" class="TestAction" method="execute">
            <result name="success">/index.jsp</result>

        </action>


    </package>

攔截器的執行順序

咱們來觀察攔截器和Action類的執行順序…只要在對應的方法上向控制檯輸出就好了!

  • 攔截器
public class MyInterceptor implements Interceptor {
    @Override
    public void destroy() {

        System.out.println("我是攔截器的銷燬方法");

    }

    @Override
    public void init() {

        System.out.println("我是攔截器的初始化方法");
    }


    /** * @param actionInvocation 攔截器的執行狀態 */
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {

        System.out.println("我是攔截器的攔截方法");

        //調用invoke()方法,表明着放行執行下一個攔截器,若是沒有攔截器了,那麼就執行Action的業務代碼
        //可當作是過濾器的doFilter()方法
        actionInvocation.invoke();
        return null;
    }
}
  • Action類
public class TestAction extends ActionSupport {

    public TestAction() {
        System.out.println("我是Action類,我被初始化了!");
    }

    @Override
    public String execute() throws Exception {

        System.out.println("我是Action類的執行方法");


        return null;

    }
}

效果

這裏寫圖片描述

從效果圖咱們能夠看出,他們的執行順序是這樣的:

  • 當服務器開啓的時候,會執行攔截器的init()方法
  • 當訪問Action時,Action實例被建立
  • 建立完Action實例,會調用攔截器的interceptor()方法
  • 最後,執行Action的execute()方法

其實很好理解,以前咱們使用Struts爲咱們提供數據自動封裝功能的時候,是這樣子的:

  • 服務器啓動,加載配置文件的信息
  • 初始化默認的攔截器棧
  • 當用戶訪問Action時,建立Action的實例。拿到Action具體的信息【成員變量、setter和getter】
  • 執行攔截器具體的內容,根據Action具體的信息,把web端的數據封裝到Action上
  • 最後在execute()就能夠獲得封裝後的數據了!

這裏寫圖片描述


攔截器應用案例

需求:當用戶登錄成功,跳轉到顯示用戶的JSP頁面中。當用戶登錄失敗,從新返回登錄界面。若是用戶直接訪問顯示用戶的JSP頁面,那麼返回到登錄界面

這裏寫圖片描述

分析

實現這個需求,咱們可使用過濾器的。只要獲取用戶的請求URL,再判斷URL是否是爲list.jsp,若是是,咱們返回到登錄的界面就行了。

如今,爲了對攔截器的理解,咱們使用攔截器去完成這個功能!


搭建配置環境

  • 導入咱們c3p0.xml文件
  • 導入c3p0開發包
  • 導入mysql開發包
  • 寫數據庫鏈接池工具類
  • dbUtils開發包
  • 8個struts2須要用到的開發包

這裏寫圖片描述

  • 建立數據庫表,導入數據

這裏寫圖片描述

編寫entity

package zhongfucheng.entity;

/** * Created by ozc on 2017/5/3. */
public class User {


    private String id ;
    private String username;
    private String cellphone;
    private String email;
    private String password;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getCellphone() {
        return cellphone;
    }

    public void setCellphone(String cellphone) {
        this.cellphone = cellphone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

編寫DAO

package zhongfucheng.dao;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import zhongfucheng.entity.User;
import zhongfucheng.utils.Utils2DB;

import java.sql.SQLException;
import java.util.List;

/** * Created by ozc on 2017/5/3. */
public class UserDao {

    public User login(User user) {

        try {
            String sql = "SELECT * FROM user WHERE username = ? AND password = ?";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
            return (User) queryRunner.query(sql, new BeanHandler(User.class), new Object[]{user.getUsername(), user.getPassword()});
        } catch (SQLException e) {
            new RuntimeException("登錄失敗了!");
        }

        return null;
    }

    public List<User> getAll() {

        try {
            String sql = "SELECT * FROM user";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
            return (List<User>) queryRunner.query(sql, new BeanListHandler(User.class));
        } catch (SQLException e) {
            new RuntimeException("登錄失敗了!");
        }

        return null;
    }

}

編寫Service

public class Service {

    UserDao userDao = new UserDao();

    public User login(User user) {
        return userDao.login(user);

    }

    public List<User> getAll() {
        return userDao.getAll();
    }
}

編寫登錄的JSP頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登錄頁面</title>
</head>
<body>

<form action="${pageContext.request.contextPath}/user_login" method="post">
    <input type="text" name="username"><br>
    <input type="password" name="password"><br>
    <input type="submit" value="登錄"><br>
</form>
</body>
</html>

編寫處理請求的Action

package zhongfucheng.action;

import com.opensymphony.xwork2.ActionContext;
import zhongfucheng.entity.User;
import zhongfucheng.service.Service;

import java.util.List;
import java.util.Map;

/** * Created by ozc on 2017/5/3. */
public class UserAction {


    /****************1.封裝數據********************/
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    /***************2.調用Service*******************/
    Service service = new Service();


    //登錄
    public String login() {

        User user = service.login(this.user);

        if (user == null) {
            return "input";
        } else {
            //將user的信息存到Session域對象中
            Map<String, Object> session = ActionContext.getContext().getSession();
            session.put("user", user);


            //登錄成功
            return "login";
        }
    }

    //查看user信息
    public String list() {

        //拿到全部用戶的信息
        List<User> users = service.getAll();

        //存到request域對象中
        Map<String, Object> request = ActionContext.getContext().getContextMap();

        request.put("users", users);

        return "list";
    }

}

struts.xml配置文件

<package name="xxx" extends="struts-default" >
        <action name="user_*" class="zhongfucheng.action.UserAction" method="{1}" >

            <!--若是登錄成功,重定向到Action中,執行list業務方法-->
            <result name="login" type="redirectAction">user_list</result>

            <!--若是是list,那麼跳轉到list.jsp頁面-->
            <result name="list" >/WEB-INF/list.jsp</result>
        </action>

    </package>

到目前爲止,咱們登錄或者不登錄均可以獲得用戶的具體信息….這是不合理的

咱們想要的效果是:只有用戶正在調用login方法,或者該用戶已經登錄了,才能夠查看具體的用戶信息

這裏寫圖片描述

所以,咱們們要攔截它們,只有用戶調用的是login方法時或者已經登錄的狀況下,才能跳轉到對應的顯示頁面


攔截器

package zhongfucheng;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/** * Created by ozc on 2017/5/3. */
public class Interceptor extends AbstractInterceptor{


    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {

        //獲得正在執行的代理對象
        ActionProxy proxy = actionInvocation.getProxy();

        //經過代理對象獲得正在執行的方法
        String method = proxy.getMethod();


        //若是方法的名字不是login,那麼就讓他們返回到login頁面上
        if (!method.equals("login")) {

            //查看用戶是否登錄了
            Object user = ActionContext.getContext().getSession().get("user");

            //若是沒有登錄,回到login頁面
            if (user == null) {

                return "input";
            } else {

                //登錄了,那麼就讓它訪問具體的用戶信息頁面
                return actionInvocation.invoke();
            }
        } else {

            //若是是訪問login方法,那麼就讓它執行
            return actionInvocation.invoke();
        }

    }
}

Struts.xml

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

<struts>
    <package name="xxx" extends="struts-default">

        <interceptors>
            <!--配置自定義的攔截器-->
            <interceptor name="Interceptor1" class="zhongfucheng.Interceptor"/>

            <!--配置攔截器棧,把默認的攔截器棧都加載自定義的攔截器棧中-->
            <interceptor-stack name="myStack">
                <interceptor-ref name="Interceptor1"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>

        </interceptors>


        <!--讓Struts執行攔截器-->

        <!--【執行攔截器:第一種寫法: 當前包下全部的acntion都執行myStack棧】-->
        <default-interceptor-ref name="myStack"></default-interceptor-ref>


        <!--第二種寫法: 只是在這一個Action中執行myStack棧 <interceptor-ref name="defaultStackt"></interceptor-ref> <interceptor-ref name="loginCheck"></interceptor-ref> -->

        <!-- 第三種寫法:執行用戶棧(與第二種寫法同樣, 只在當前aciton中執行自定義棧) -->
        <!-- <interceptor-ref name="myStack"></interceptor-ref>-->

        <action name="user_*" class="zhongfucheng.action.UserAction" method="{1}">

            <!--若是登錄成功,重定向到Action中,執行list業務方法-->
            <result name="login" type="redirectAction">user_list</result>

            <!--若是是list,那麼跳轉到list.jsp頁面-->
            <result name="list">/WEB-INF/list.jsp</result>


            <!--若是是直接訪問Action或者沒有用戶登錄,返回login頁面-->
            <result name="input">/login.jsp</result>

        </action>


    </package>
</struts>

效果:

只有當用戶登錄了才能查看用戶具體信息,直接訪問Action會跳轉回

這裏寫圖片描述


Struts2其餘攔截器

計時攔截器

Struts2自帶了計時攔截器,也就是用來統計每一個Action執行的時間

執行等待攔截器

若是頁面執行得太慢了,Struts2還提供了執行等待攔截器,也就是說,當頁面加載得過久了,就跳轉到對應的提示頁面…當服務器執行完畢了,也跳轉到相對應的頁面

相關文章
相關標籤/搜索