第四章 使用拦截器追加工作流
4.1 为什么要拦截请求
在尽量隔离WEB应用的程序关注点时,拦截器极大地提高了分离水平。特别是,拦截器消除了Action组件中的横切任务。
4.2 拦截器的工作原理
框架不直接调用Action的execute()方法,而是创建一个叫做ActionInvocation的对象,它封装了Action执行相关的所有处理细节。
public interface ActionInvocation extends Serializable { /** * Get the Action associated with this ActionInvocation. * * @return the Action */ Object getAction(); /** * Gets whether this ActionInvocation has executed before. * This will be set after the Action and the Result have executed. * * @return <tt>true</tt> if this ActionInvocation has executed before. */ boolean isExecuted(); /** * Gets the ActionContext associated with this ActionInvocation. The ActionProxy is * responsible for setting this ActionContext onto the ThreadLocal before invoking * the ActionInvocation and resetting the old ActionContext afterwards. * * @return the ActionContext. */ ActionContext getInvocationContext(); /** * Get the ActionProxy holding this ActionInvocation. * * @return the ActionProxy. */ ActionProxy getProxy(); /** * If the ActionInvocation has been executed before and the Result is an instance of {@link ActionChainResult}, this method * will walk down the chain of <code>ActionChainResult</code>s until it finds a non-chain result, which will be returned. If the * ActionInvocation's result has not been executed before, the Result instance will be created and populated with * the result params. * * @return the result. * @throws Exception can be thrown. */ Result getResult() throws Exception; /** * Gets the result code returned from this ActionInvocation. * * @return the result code */ String getResultCode(); /** * Sets the result code, possibly overriding the one returned by the * action. * <p/> * The "intended" purpose of this method is to allow PreResultListeners to * override the result code returned by the Action. * <p/> * If this method is used before the Action executes, the Action's returned * result code will override what was set. However the Action could (if * specifically coded to do so) inspect the ActionInvocation to see that * someone "upstream" (e.g. an Interceptor) had suggested a value as the * result, and it could therefore return the same value itself. * <p/> * If this method is called between the Action execution and the Result * execution, then the value set here will override the result code the * action had returned. Creating an Interceptor that implements * {@link PreResultListener} will give you this oportunity. * <p/> * If this method is called after the Result has been executed, it will * have the effect of raising an IllegalStateException. * * @param resultCode the result code. * @throws IllegalStateException if called after the Result has been executed. * @see #isExecuted() */ void setResultCode(String resultCode); /** * Gets the ValueStack associated with this ActionInvocation. * * @return the ValueStack */ ValueStack getStack(); /** * Register a {@link PreResultListener} to be notified after the Action is executed and * before the Result is executed. * <p/> * The ActionInvocation implementation must guarantee that listeners will be called in * the order in which they are registered. * <p/> * Listener registration and execution does not need to be thread-safe. * * @param listener the listener to add. */ void addPreResultListener(PreResultListener listener); /** * Invokes the next step in processing this ActionInvocation. * <p/> * If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit * ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor * to execute. If there are no more Interceptors to be applied, the Action is executed. * If the {@link ActionProxy#getExecuteResult()} method returns <tt>true</tt>, the Result is also executed. * * @throws Exception can be thrown. * @return the return code. */ String invoke() throws Exception; /** * Invokes only the Action (not Interceptors or Results). * <p/> * This is useful in rare situations where advanced usage with the interceptor/action/result workflow is * being manipulated for certain functionality. * * @return the return code. * @throws Exception can be thrown. */ String invokeActionOnly() throws Exception; /** * Sets the action event listener to respond to key action events. * * @param listener the listener. */ void setActionEventListener(ActionEventListener listener); void init(ActionProxy proxy) ; }
当框架收到一个请求时,它首先决定这个URL映射到哪个Action。这个Action的一个实例会被加入到一个新创建的ActionInvocation实例中。接着,框架咨询声明性架构(通过应用程序的XML或者Java注解),以发现哪些拦截器应该触发,以及按什么顺序触发。除了这些核心元素,ActionInvocation还拥有对其他重要信息(例如Servlet请求对象和当前Action可用的结果组件的映射)的引用。
ActionInvocation公开了invoke()方法,框架通过调用这个方法开始Action的执行。当框架调用这个方法时,ActionInvocation通过执行拦截器栈中第一个拦截器开始这个调用过程。注意,invoke()方法并不总是映射到第一个拦截器,ActionInvocation负责跟踪执行过程到达的状态,并且通过调用拦截器的intercept()方法把控制权交给栈中合适的拦截器。重要的是,intercept()方法把ActionInvocation实例作为一个参数。
public String intercept(ActionInvocation invocation) throws Exception { ... }
后续拦截器的继续执行,最终执行Action,这些都是通过递归调用ActionInvocation的invoke()方法实现。每次invoke()方法被调用时,ActionInvocation都会查询自身的状态,调用接下来的任何一个拦截器。
因此,在通常的执行中,调用过程向下通过所有拦截器,直到栈中再也没有拦截器时,触发Action。另外,ActionInvocation在内部管理处理状态,因此它总是直到自己现在处在栈的什么位置。
拦截器在触发时能做什么:
- 做一些预处理。在这个阶段拦截器可以用来准备、过滤、改变或者操作任何可以访问的重要数据。这些数据包括所有与当前请求相关的关键对象和数据,也包括Action。
- 通过调用invoke()方法将控制转移给后续的拦截器,直到Action。或者通过返回一个控制字符串中断执行。在这个阶段,如果拦截器决定请求不应该继续,他可以不调用ActionInvocation实例上的invoke()方法,而是直接返回一个控制字符串。通过这种方式可以停止后续的执行,并且决定哪个结果被呈现。
- 做一些后加工。在这个阶段,任何一个返回的拦截器可以修改可以访问的对象的数据作为后加工,但是此时结果已经确定了。
4.3 研究内建的Struts 2拦截器
4.3.1 工具拦截器
- timer拦截器。记录执行花费的时间
- logger拦截器。提供了一个简单的日志记录机制
4.3.2 数据转移拦截器
- params拦截器(defaultStack)。params拦截器不知道这些数据最终会去哪里,它只是把数据转移到ValueStack上发现的第一个匹配的属性上。
- static-params拦截器(defaultStack)。它也将参数转移到ValueStack公开的属性上,不同的是参数的来源。这个拦截器转移的参数定义在声明性架构的Action元素中。
- autowiring拦截器。这个拦截器为使用Spring管理应用程序资源提供了一个集成点。
-
servlet-config拦截器(defaultStack)。该拦截器提供了一种将来源于Servlet API的各种对象注入到Action的简洁方法。这个拦截器通过将各种对象设置到Action必须实现的接口公开的设置方法的方式工作。每个接口包含一个方法——当前资源的设置方法。不同的接口用于获取与Servlet环境相关的不同对象。
ServletContextAware设置ServletContext
ServletRequestAware设置HttpServletRequest
ServletResponseAware设置HttpServletResponse
ParameterAware设置Map类型的请求参数
RequestAware设置Map类型的请求属性
SessionAware设置Map类型的会话属性
ApplicationAware设置Map类型的应用程序领域属性
PrincipalAware设置Principal对象(安全相关)
- fileUpload拦截器(defaultStack)。该拦截器将文件和元数据从多重请求转换为常规的请求参数。
4.3.3 工作流拦截器
- workflow拦截器(defaultStack)
- validation拦截器(defaultStack),提供了声明性的方式验证你的数据。
- prepare拦截器(defaultStack),提供了一种向Action追加额外的工作流处理的通用入口点。
- modelDriven拦截器(defaultStack)
4.3.4 其他拦截器
- exception拦截器(defaultStack)。它出现在defaultStack中第一位,也应在在任何你创建的自定义拦截器栈中出现在第一位。当exception拦截器在后加工阶段处理时,它会捕获被抛出的任何异常,并且把结它映射到一个结果页面。在将控制转交给结果之前,exception拦截器会创建一个ExceptionHolder对象,并且把它放在ValueStack的最顶端。ExceptionHolder是一个异常的包装器,它把跟踪栈和异常作为JavaBean属性公开出来,可以在错误页面通过标签访问这些属性。
- token拦截器和token-session拦截器。可以作为避免表单重复提交系统的一部分。
- scoped-modelDriven拦截器(defaultStack)。这个拦截器为Action的模型对象提供跨请求的向导式的持久性。
- execAndWait拦截器。当一个请求需要执行很长时间时,最好能给用户一些反馈。
4.4 声明拦截器
此时XML是声明拦截器的唯一选择。注解机制现在还不支持声明拦截器。
只要Action声明了自己的拦截器,它就失去了自动的默认值。
4.5 构建自定义拦截器
拦截器实例在Action之间共享。虽然每个请求都会创建动作的一个新实例,但是拦截器会重用。拦截器是无状态的,不要在拦截器中存储与当前正在处理的请求相关的数据。
相关推荐
Struts拦截器是Java Web开发中的一个重要概念,尤其在基于Struts2框架的应用中,它扮演着处理请求、验证输入、记录日志等关键角色。在这个"Struts拦截器案例——登陆"中,我们将深入探讨如何利用Struts拦截器实现...
拦截器是Struts2的核心组件之一,它基于AOP(面向切面编程)的概念,为框架提供了高度的灵活性和可扩展性。以下是关于Struts2拦截器的基础知识的详细说明: 1. **拦截器的定义与作用**: - 拦截器是Struts2框架中...
**Struts2实战——《Struts2 In Action中文版》** 《Struts2 In Action》是一本专为Java开发者设计的实战指南,旨在深入解析Struts2框架的使用与实践。Struts2作为一款强大的MVC(Model-View-Controller)框架,极...
根据提供的信息,我们可以推断出这是一本关于Struts 2框架的书籍——《Struts 2实战 Struts 2 in action 的中文版》。本书主要介绍了Struts 2框架的相关概念、工作原理以及实际应用案例等内容。接下来,我们将根据...
首先,Struts2的核心在于它的拦截器(Interceptor)机制。拦截器是Struts2的一个强大特性,它们在Action调用前后执行,可以处理诸如验证、日志、事务管理等通用任务。通过灵活配置,开发者可以构建出满足各种需求的...
《Struts 2实战 Struts2 in Action》这本书不仅介绍了Struts 2的基本概念和技术细节,更重要的是,它通过丰富的实战案例帮助读者深入理解框架的工作原理,并掌握了如何高效地利用Struts 2来解决实际问题。...
在Struts1中,拦截器是框架的核心组件之一,它们提供了扩展功能和处理请求的能力,而无需修改Action类本身。本文将深入探讨在Struts1中如何使用拦截器,并以saif-0.1.jar为例,解释其在实际项目中的应用。 首先,...
"Struts2 in Action" 是一本深入探讨Struts2框架的专业书籍,旨在帮助开发者掌握这一框架的核心概念和实践技巧。这本书的中文版不仅提供了理论知识,还附带有配套的源代码,方便读者进行实践操作,加深理解。 ...
本文将深入探讨Struts2的核心概念,包括Action、Result、配置文件、OGNL与ValueStack、Tags以及项目中的关键实践。 **一、Action** Action是Struts2中处理业务逻辑的核心组件,它是实现了`...
通过阅读《Struts2 in action》这本书,你可以深入学习Struts2的各个方面,包括最佳实践、高级特性和案例分析,从而在实际项目中更加熟练地运用这个框架。无论你是初学者还是经验丰富的开发者,这本书都将为你的Java...
第二部分 核心概念:动作、拦截器和类型转换 第3章 使用Struts 2动作 36 3.1 Struts 2动作简介 36 3.2 打包动作 39 3.2.1 Struts 2公文包示例应用程序 39 3.2.2 组织你的包 39 3.2.3 使用struts-default包中的组件 ...
总结,Struts2拦截器是其核心机制之一,它允许开发者以模块化的方式添加额外的功能,提高代码的可复用性和可维护性。通过自定义拦截器和合理配置,我们可以实现诸如日志记录、事务管理、权限验证等多种业务需求,...
在Struts2中,拦截器工作在Action和结果(Result)之间,形成一个拦截器栈,每个拦截器按照配置的顺序依次执行。 Struts2的拦截器执行流程如下: 1. **初始化拦截器栈**:当Struts2框架启动时,会根据配置文件...
要深入学习和掌握Struts2,建议阅读官方文档,参与实际项目实践,也可以参考相关的技术书籍和教程,例如《Struts2技术内幕——深入解析Struts2架构设计与实现原理》等资源,来提升对Struts2框架的全面理解。
### 一、Struts2 拦截器概念 1. **拦截器是什么**:拦截器是一种动态拦截Action调用的对象,它可以理解为一个过滤器,它在Action被调用之前和之后执行特定的逻辑。Struts2的拦截器是基于Java的Servlet Filter机制...
MVC设计模式是Struts2的核心概念之一。模型(Model)负责处理数据和业务逻辑;视图(View)负责展示数据,即用户界面;控制器(Controller)则作为模型和视图之间的桥梁,处理用户请求并将请求分发给适当的模型组件...
2. **前端控制器拦截**:所有请求首先被Struts2的前端控制器(FilterDispatcher)拦截。 3. **查找并执行Action**:根据请求中的参数找到对应的Action并执行。 4. **返回结果**:Action执行完成后返回一个结果。 5. ...