您的位置:首页 > 编程语言 > Java开发

Struts2第七篇【介绍拦截器、自定义拦截器、执行流程、应用】

2018-01-21 00:00 375 查看

什么是拦截器

拦截器Interceptor…..拦截器是Struts的概念,它与过滤器是类似的…可以近似于看作是过滤器

为什么我们要使用拦截器

前面在介绍Struts的时候已经讲解过了,Struts为我们实现了很多的功能,比如数据自动封装阿..文件上传功能阿….Struts为我们提供的这些功能都是通过拦截器完成的……

数据自动封装通过
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
这个拦截器。

文件上传通过
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
这个拦截器

拦截器的设计就是基于组件设计的应用

再次回顾拦截器基础

在开始讲解Struts的时候已经说明过了struts-default.xml这个文件,它定义了Struts的所有拦截器。因为我们在启动服务器的时候会自动装载这个文件,因此我们才可以在Action中使用到Struts为我们提供的功能【数据自动封装…文件上传】

在struts-default.xml中定义的拦截器就有32个之多,Struts2为了方便我们对拦截器的引用,提供了拦截器栈的定义。

<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默认执行的是默认拦截器栈,一旦用户有指定执行哪些拦截器,那么默认的拦截器栈就不会被执行!

自定义拦截器

Struts2允许我们自定义拦截器,这就使我们能够更加灵活地操作Struts2这个框架了!

Struts2提供了Interceptor这个拦截器接口,只要我们实现这个接口,那么这就算是自定义开发拦截器了。

当然啦,大部分时候,我们定义拦截器都是继承AbstractInterceptor这个类….为了学习拦截器的内容,下面就实现Interceptor这个接口了。

编写拦截器类

当实现该接口时,有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还提供了执行等待拦截器,也就是说,当页面加载得太久了,就跳转到对应的提示页面…当服务器执行完毕了,也跳转到相对应的页面
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: