1、拦截器概念
过滤器Filter这个概念我们在Java Web中接触过,而Struts拦截器与它相比,在功能、概念可以说是几乎一样(大佬就是喜欢折腾,老是搞几套一样的东西)。拦截器在Struts非常重要,比如前面使用过的表单参数自动注入,模型转换等等。
Struts默认的拦截器配置在文件struts-default.xml
中
2、拦截器的执行时机
拦截器按照在struts.xml配置文件调用的顺序进行拦截,结果视图后逆序执行。(有点像递归算法,后面的有多个拦截器同时拦截的实例。)
3、拦截器的部分类结构
4、自定义拦截器
实例1:自定义实现单个拦截器
第一步:创建一个拦截器,并继承AbstractInterceptor
抽象类,实现intercept
方法。
package cn.hestyle.web.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("开始拦截...");
String invoke = actionInvocation.invoke();
System.out.println(invoke);
System.out.println("拦截放行...");
return invoke;
}
}
第二步:在struts.xml
申明自定义的拦截器
第三步:在struts.xml
中将拦截器运用于Action
浏览器访问hello.action控制台输出
实例2:自定义实现多个拦截器
创建两个拦截器
package cn.hestyle.web.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyInterceptor1 extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("开始拦截1...");
String invoke = actionInvocation.invoke();
System.out.println(invoke);
System.out.println("拦截放行1...");
return invoke;
}
}
package cn.hestyle.web.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyInterceptor2 extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("开始拦截2...");
String invoke = actionInvocation.invoke();
System.out.println(invoke);
System.out.println("拦截放行2...");
return invoke;
}
}
struts.xml
配置文件
浏览器访问hello.action
控制台输出
5、拦截器应用(用户登录)
业务逻辑:
首先准备login.jsp
,main.jsp
, studentList.jsp
, teacherList.jsp
页面
只有登录了才能访问main.jsp
, studentList.jsp
, teacherList.jsp
页面
当登录成功后,跳转到main.jsp
,main.jsp
可以跳转到学生和老师列表
①、Demo结构
②、动作类
package cn.hestyle.web.action;
import cn.hestyle.model.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import org.apache.struts2.ServletActionContext;
//通过ModelDriven<User>将表单转换为User模型
public class loginAction extends ActionSupport implements ModelDriven<User> {
private User user = new User();
public String login(){
//检测账号合法性
if ("hestyle".equals(user.getUsername()) && "123456".equals(user.getPassword())){
//将user账号信息存到session中
ServletActionContext.getRequest().getSession().setAttribute("user", user);
return "success";
} else {
return "toLogin";
}
}
@Override
public User getModel() {
return user;
}
}
package cn.hestyle.web.action;
import com.opensymphony.xwork2.ActionSupport;
public class MainAction extends ActionSupport {
public String main(){
return "success";
}
}
package cn.hestyle.web.action;
import com.opensymphony.xwork2.ActionSupport;
public class StudentListAction extends ActionSupport {
public String stuList(){
return "success";
}
}
package cn.hestyle.web.action;
import com.opensymphony.xwork2.ActionSupport;
public class TeacherListAction extends ActionSupport {
public String tchList(){
return "success";
}
}
③、拦截器
package cn.hestyle.web.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import org.apache.struts2.ServletActionContext;
import javax.servlet.http.HttpSession;
/**
* 检测是否登录过
*/
public class CheckLoginInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
//获取session
HttpSession session = ServletActionContext.getRequest().getSession();
//检查session中是否有user登录账号信息
if (session.getAttribute("user") != null) {
//放行
String invoke = actionInvocation.invoke();
return invoke;
} else {
return "toLogin";
}
}
}
④、struts.xml
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="p1" extends="struts-default">
<!-- 申明checkLogin拦截器 -->
<interceptors>
<interceptor name="checkLoginInterceptor" class="cn.hestyle.web.interceptor.CheckLoginInterceptor"></interceptor>
</interceptors>
<!-- 全局结果视图 -->
<global-results>
<result name="toLogin">/login.jsp</result>
</global-results>
<!-- 登录action -->
<action name="login" class="cn.hestyle.web.action.loginAction" method="login">
<result name="success">/WEB-INF/main.jsp</result>
</action>
<!-- 访问main.jsp的动作,需要使用checkLoginInterceptor拦截器检测是否登录 -->
<action name="main" class="cn.hestyle.web.action.MainAction" method="main">
<interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="success">/WEB-INF/main.jsp</result>
</action>
<!-- 访问studentList.jsp的动作,需要使用checkLoginInterceptor拦截器检测是否登录 -->
<action name="stuList" class="cn.hestyle.web.action.StudentListAction" method="stuList">
<interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="success">/WEB-INF/studentList.jsp</result>
</action>
<!-- 访问teacherList.jsp的动作,需要使用checkLoginInterceptor拦截器检测是否登录 -->
<action name="tchList" class="cn.hestyle.web.action.TeacherListAction" method="tchList">
<interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="success">/WEB-INF/teacherList.jsp</result>
</action>
</package>
</struts>
:如果一个动作配置了自定义拦截器,则struts不会再使用默认的拦截器,需要手动添加<interceptor-ref name="defaultStack"></interceptor-ref>
默认拦截器!
⑤、浏览器访问效果
必须先登录过,在session中记录user信息,才能访问main.jsp
, studentList.jsp
, teacherList.jsp
页面。
在上面的struts.xml
配置文件中,不难看出main
、stuList
、tchList
三个动作需要登录session拦截器、默认拦截器组拦截,登录拦截器需要使用默认拦截器组拦截,拦截器配置有些冗余。下面将对其进行优化:
方式一:抽取一个抽象包,声明一个新的拦截器组,放置登录session拦截器、默认拦截器组。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- 在抽象包中申明拦截器、拦截器组-->
<package name="p1" extends="struts-default" abstract="true">
<!-- 申明checkLogin拦截器 -->
<interceptors>
<interceptor name="checkLoginInterceptor" class="cn.hestyle.web.interceptor.CheckLoginInterceptor"></interceptor>
<!-- 申明一个拦截器分组:包含自定义拦截器、默认拦截器组 -->
<interceptor-stack name="myInterceptorStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 全局结果视图 -->
<global-results>
<result name="toLogin">/login.jsp</result>
</global-results>
</package>
<!-- 继承p1包 -->
<package name="p2" extends="p1">
<!-- 登录action -->
<action name="login" class="cn.hestyle.web.action.loginAction" method="login">
<result name="success">/WEB-INF/main.jsp</result>
</action>
<!-- 访问main.jsp的动作,使用myInterceptorStack拦截器组 -->
<action name="main" class="cn.hestyle.web.action.MainAction" method="main">
<interceptor-ref name="myInterceptorStack"></interceptor-ref>
<result name="success">/WEB-INF/main.jsp</result>
</action>
<!-- 访问studentList.jsp的动作,使用myInterceptorStack拦截器组 -->
<action name="stuList" class="cn.hestyle.web.action.StudentListAction" method="stuList">
<interceptor-ref name="myInterceptorStack"></interceptor-ref>
<result name="success">/WEB-INF/studentList.jsp</result>
</action>
<!-- 访问teacherList.jsp的动作,使用myInterceptorStack拦截器组 -->
<action name="tchList" class="cn.hestyle.web.action.TeacherListAction" method="tchList">
<interceptor-ref name="myInterceptorStack"></interceptor-ref>
<result name="success">/WEB-INF/teacherList.jsp</result>
</action>
</package>
</struts>
方式二:方式一还是有些不彻底,我们修改默认拦截器分组为我们自定义的拦截器分组,那么所有包中的所有action都被登录session拦截器、struts的拦截器组拦截。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- 在抽象包中申明拦截器、拦截器组-->
<package name="p1" extends="struts-default" abstract="true">
<!-- 申明checkLogin拦截器 -->
<interceptors>
<interceptor name="checkLoginInterceptor" class="cn.hestyle.web.interceptor.CheckLoginInterceptor"></interceptor>
<!-- 申明一个拦截器分组:包含自定义拦截器、默认拦截器组 -->
<interceptor-stack name="myInterceptorStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 修改包中的默认拦截器组为自定义拦截器组 -->
<default-interceptor-ref name="myInterceptorStack"></default-interceptor-ref>
<!-- 全局结果视图 -->
<global-results>
<result name="toLogin">/login.jsp</result>
</global-results>
</package>
<!-- 继承p1包 -->
<package name="p2" extends="p1">
<!-- 包中的四个action都被已修改的拦截器组myInterceptorStack拦截 -->
<action name="login" class="cn.hestyle.web.action.loginAction" method="login">
<result name="success">/WEB-INF/main.jsp</result>
</action>
<action name="main" class="cn.hestyle.web.action.MainAction" method="main">
<result name="success">/WEB-INF/main.jsp</result>
</action>
<action name="stuList" class="cn.hestyle.web.action.StudentListAction" method="stuList">
<result name="success">/WEB-INF/studentList.jsp</result>
</action>
<action name="tchList" class="cn.hestyle.web.action.TeacherListAction" method="tchList">
<result name="success">/WEB-INF/teacherList.jsp</result>
</action>
</package>
</struts>
这样也会造成一个问题,就是登录action也被登录session拦截器拦截了,所以需要修改登录session拦截器的实现。
首先来看一下AbstractInterceptor
抽象类的子类MethodFilterInterceptor
。
我们只要将CheckLoginInterceptor
修改为实现抽象类MethodFilterInterceptor
,并且在struts.xml配置中,把login这个动作排除不拦截即可。
设置myInterceptorStack拦截器组中的checkLoginInterceptor拦截器不拦截login。
这样login被defaultStack拦截器组拦截,main、stuList、tchList被defaultStack拦截器、登录session验证拦截器组拦截,符合业务需求。
可能有部分道友被后面拦截器组的定义、修改啥的绕蒙了,建议多看几遍,其实并不难理解。