Struts2总结之第五章拦截器

Struts2总结之第五章拦截器

拦截器概述:

  • 拦截器的概念是在Struts2里面有的。在其它地方没有。
  • Struts2是框架,封装了很多的功能,struts2里面封装的功能都是在拦截器里面。
  • Struts2里面封装了很多的功能,有很多拦截器,不是每次这些拦截器都执行,每次执行默认的拦截

Struts2里面默认的拦截器位置:

  • struts2-core-2.xxxx.jar—->struts-default.xml,在这里面配置了很多的拦截器,但是只执行默认配置的那些拦截器。

  • struts2中在struts-default.xml文件中声明了所有的拦截器。
    而struts2框架默认使用的是defaultStack这个拦截器栈。
    在这个拦截器栈中使用了18个拦截器。简单说,struts2框架
    在默认情况下,加载了18个拦截器。

  • 总的拦截器

      <interceptors>
                <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
                <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
                <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
                <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
                <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
                <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
                <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
                <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
                <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
                <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
                <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
                <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
                <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
                <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
                <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
                <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
                <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
                <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
                <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
                <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
                <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
                <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
                <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
                <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
                <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
                <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
                <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
                <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
                <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
                <interceptor name="datetime" class="org.apache.struts2.interceptor.DateTextFieldInterceptor" />
                <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
                <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
                <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
                <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
                <interceptor name="deprecation" class="org.apache.struts2.interceptor.DeprecationInterceptor" />
    
    
  • 默认 的拦截器栈

    <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="datetime"/>
                    <interceptor-ref name="multiselect"/>
                    <interceptor-ref name="staticParams"/>
                    <interceptor-ref name="actionMappingParams"/>
                    <interceptor-ref name="params"/>
                    <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-ref name="deprecation"/>
                </interceptor-stack>
    

拦截器的执行时间

​ action代理对象创建之后,action目标处理逻辑方法执行之前!!可以在代码中进行调试断点测试(测试时是通过debug调试项目)!!!

​ 通过调试你就可以发现,如果你的拦截器配置的是struts-default或者其它的拦截器组,那么你就会发现,即使你没有在项目中用到某个拦截器,比如我这里并没有实现ModelDriven接口,但是它被运行了。所以,只要你配置了相关的拦截器组,拦截器组里面的所有拦截器不管用或不用都会被执行。

介绍拦截器的底层原理:

​ struts2拦截器使用的是AOP思想。
​ AOP的底层实现就是动态代理。
​ 拦截器 采用 责任链 模式
​ 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。
​ 责任链每一个节点,都可以继续调用下一个节点,也可以阻止流程继续执行

aop思想(一种开发思想)

  • Aop是面向切面(方面) 编程,比如有一个基本功能,想要扩展功能,不通过修改源代码方式扩展功能,经常用的是通过配置文件。(上面的描述还是一个浅显的认识。在讲解Spring时,会更深入了解aop),同时,aop使用了一个技术,那就是动态代理。

责任链模式

  • 在java中有很多的设计模式,责任链模式就是其中的一种。

  • 责任链模式和过滤链很相似。

  • 过滤链:一个请求可有多个过滤器进行过滤,每个过滤器只有做放行才能到下一个过滤器。

在责任链场景:

  • 要执行多个操作,有添加,修改,删除三个操作。

  • 首先执行添加操作,添加操作执行之后,做类似于放行的操作,执行修改操作,修改操作执行之后做类似于放行操作,执行删除操作。

这里action目标逻辑方法的执行是通过动态代理方式执行,动态代理的方式执行和直接创建action对象执行方法效果是没有区别的。

aop思想和责任链模式如何应用到拦截器里面

  • 拦截器在aciton代理对象创建之后,action的目标方法执行之前执行。在拦截器执行之后再执行action方法!!!

  • 在action方法执行之前执行默认拦截器,执行过程使用aop思想,在action没有直接调用拦截器的方法,使用配置文件方式进行操作。使用配置文件是关键,把拦截器通过配置引入到项目功能的方式叫做aop思想。

  • 在执行拦截器时候,执行很多的拦截器,这个过程使用责任链模式。

  • 假如执行三个拦截器,执行拦截器1,执行拦截器1之后做放行操作,执行拦截器2,执行拦截器2之后做放行操作,执行拦截器3,执行拦截器3之后放行,最后执行action目标逻辑方法。

  • 在我们的默认拦截器配置里面,那些默认拦截器其实是都会执行的。只是关乎我们到底用不用其具体实现而已,就像是ModelDriven这个类

自定义拦截器

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

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

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

编写拦截器类

  • 当实现该接口时,有3个需要我们实现的方法:

    public class Myinterceptor implements Interceptor {
    
    	@Override
    	public void destroy() {
    	}
    
    	@Override
    	public void init() {
    		System.out.println("Interceptor  init.... ");
    	}
    
    	@Override
    	public String intercept(ActionInvocation ai) throws Exception {
    		System.out.println("intercept method");
    		return ai.invoke();
    	}
    }
    
  • init()和destory()都是和拦截器执行顺序有关的方法,

    @Override
    	public String intercept(ActionInvocation ai) throws Exception {
    		System.out.println("intercept method");
    	//调用invoke()方法,代表着放行执行下一个拦截器,如果没有拦截器了,那么就执行Action的业务代码
    		return ai.invoke();
    	}
    

在struts.xml中配置

由于我们配置了自定义拦截器,那么struts默认的拦截器栈是不会执行的。如果我们想要使用默认拦截器栈的功能,就必须把它配置在我们自定义的栈中!

<struts>
	<package name="p1" extends="struts-default"	namespace="/">
		<interceptors>
			<!-- 自定义拦截器 -->
			<interceptor name="my"	class="com.syj.action.Myinterceptor" />
				<!-- 自定义拦截器栈 -->
				<interceptor-stack name="MyStack">
					<interceptor-ref name="my"></interceptor-ref>
					<interceptor-ref name="defaultStack"></interceptor-ref>
				</interceptor-stack>
		</interceptors>
		<!-- 声明全局result,当action的返回结果不存在时会查找 -->
		<global-results>
			<result name="input">/input.jsp</result>
			<result name="login">/input.jsp</result>
		</global-results>
		
		<action	name="demo1" class="com.syj.action.Demo1">
			<!-- 引用自定义的拦截器栈 -->
			<interceptor-ref name="MyStack" />
			<result>/success.jsp</result>
		</action>
	</package>
</struts>

拦截器的执行顺序

  • Action
public class Demo1 extends ActionSupport {
	@Override
	public String execute() throws Exception {
		System.out.println("Demo1 Action...");
		return SUCCESS;
	}
}

执行结果:
在这里插入图片描述

从效果图我们可以看出,他们的执行顺序是这样的:

  • 当服务器开启的时候,会执行拦截器的init()方法
  • 当访问Action时,Action实例被创建
  • 创建完Action实例,会调用拦截器的interceptor()方法
  • 最后,执行Action的execute()方法

其实很好理解,之前我们使用Struts为我们提供数据自动封装功能的时候,是这样子的:

  • 服务器启动,加载配置文件的信息
  • 初始化默认的拦截器栈
  • 当用户访问Action时,创建Action的实例。拿到Action具体的信息【成员变量、setter和getter】
  • 执行拦截器具体的内容,根据Action具体的信息,把web端的数据封装到Action上
  • 最后在execute()就可以得到封装后的数据了!
    在这里插入图片描述

拦截器应用案例

权限控制:
		1.login.jsp------>LoginAction------------->book.jsp
						登录成功,将用户存储到session。
						
		2.在book.jsp中提供crud链接。
			每一个连接访问一个BookAction中一个方法。
			
	要求:对于BookAction中的add,update,delete方法要求用户必须登录后才可以访问。search无要求。	

	怎样解决只控制action中某些方法的拦截?
		1.创建类不在实现Interceptor接口,而是继承其下的一个子类.MethodFilterInterceptor
			不用在重写intercept方法,而是重写 doIntercept方法。
			
		2.在struts.xml文件中声明
			<interceptors>
				<intercept name="" class="">
					<param name="includeMethods">add,update,delete</param>
					<param name="excludeMethods">search</param>
				</intercept>
			</interceptors>
  1. 编写登录的页面。

    login.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
        <%@taglib prefix="s" uri="/struts-tags"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <!-- 打印返回的错误结果 -->
    <s:fielderror/>
    <s:actionerror/>
    <form action="${pageContext.request.contextPath}/login" method="post">
        登录:<input type="text" name="username"><br>
      密码:  <input type="password" name="password"><br>
        <input type="submit" value="登陆"><br>
    </form>
    </body>
    </html>
    

2.接下来进行登录的验证,如果账户和密码正确,测跳转到book.jsp

LoginAction.java

public class LoginAction extends ActionSupport implements ModelDriven<User> {
	User user = new User();

	@Override
	public User getModel() {
		return user;
	}

	public String login() throws Exception {
		// 在这里就不进行数据库的查询操作
		if ("tom".equals(user.getUsername()) && "123456".equals(user.getPassword())) {
			ServletActionContext.getRequest().getSession().setAttribute("user", user);
			return SUCCESS;
		} else {
			this.addActionError("用户名或密码错误");
			return INPUT;
		}
	}
}

实体类User.java

package com.syj.entity;

public class User {
	private String username;
	private String password;

	public String getUsername() {
		return username;
	}

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

	public String getPassword() {
		return password;
	}

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

	@Override
	public String toString() {
		return "User [username=" + username + ", password=" + password + "]";
	}
}

3.假如登录成功,跳转到action之后,我们进行增删改查操作(模仿)

book.jsp

<body>
<a href="${pageContext.request.contextPath}/book_add">book add</a><br>
<a href="${pageContext.request.contextPath}/book_update">book update</a><br>
<a href="${pageContext.request.contextPath}/book_delete">book delete</a><br>
<a href="${pageContext.request.contextPath}/book_search">book search</a><br>
</body>
</html>

4.配置struts.xml文件

struts.xml

<struts>
	<package name="p1" extends="struts-default" namespace="/">
			<global-results>
				<result name="input" >/login.jsp</result>
				<result name="login" >/login.jsp</result>
			</global-results>
			<!-- 登录action -->
			<action name="login"  class="com.syj.action.LoginAction" method="login" >
				<result>/book.jsp</result>
			</action>
			<!-- 权限验证Action -->
			<action name="book_*"  class="com.syj.action.BookAction" method="{1}" >
				
			</action>
	</package>
</struts>

5.此时我们还没有真正实现权限的控制,为此我们需要自定义拦截器,实现只有登陆了才可以进行增删改操作(重点)

自定义拦截器:

public class LoginInteceptor extends MethodFilterInterceptor {
	@Override
	protected String doIntercept(ActionInvocation ai) throws Exception {
		// 在登录时已经将用户存储到session中
		User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user");
		// 说明权限不足不允许登录
		if (user == null) {
			// 存储错误信息并在登录页面打印	
			BookAction bookAction = (BookAction) ai.getAction();
			bookAction.addActionError("权限不足请先登录");
			return Action.LOGIN;
		}
		return ai.invoke();
	}
}

注册拦截器

修改struts.xml

<struts>
	<package name="p1" extends="struts-default" namespace="/">
			<interceptors>
				<interceptor name="my" class="com.syj.Interceptor.LoginInteceptor">
					<param name="excludeMethods">search</param>
				</interceptor>
				<interceptor-stack name="MyStack">
					<interceptor-ref name="my"/>
					<interceptor-ref name="defaultStack"/>
				</interceptor-stack>
			</interceptors>
	
			<global-results>
				<result name="input" >/login.jsp</result>
				<result name="login" >/login.jsp</result>
			</global-results>
			<!-- 登录action -->
			<action name="login"  class="com.syj.action.LoginAction" method="login" >
				<result>/book.jsp</result>
			</action>
			<!-- 权限验证Action -->
			<action name="book_*"  class="com.syj.action.BookAction" method="{1}" >
				<interceptor-ref name="MyStack"/>
			</action>
	</package>
</struts>

6.执行结果

不登录直接访问book.jsp只有book search可以访问

在这里插入图片描述

当我们登录之后增删改查都可以就行操作:

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值