`
jbf034
  • 浏览: 153156 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

“过滤器”(before,after,around)

阅读更多
“过滤器”可以让你在你的“控制器”内写代码来包装由“动作”完成的处理—你可以
写个代码块,并在你的控制器(或你的“控制器”的子类)内的任何数量的“动作”之前或之
后来调用它。这是个强大功能。使用“过滤器”,我们可以实现检验计划,日志,response
compression,甚至是定制的“应答”。

Rails 支持三种类型的“过滤器”:before,after,和around。“过滤器”可以在“动
作”运行之前,或之后被调用。这依赖于你如何定义它们,它们即可做为“控制器”内的方
法来运行,也可以在它们运行时传递“控制器”对象。不论哪种方式,它们都可以访问request的细节和response 对象,还有其它的“控制器”属性。
Before 和After “过滤器”
就像它们名字所暗示的,before 和after“过滤器”在一个“动作”之前或之后被调用。
Rails 会维护每个“控制器”内的两种过滤器的链。当一个“控制器”运行一个“动作”时,它执行所有的before 链中“过滤器”。在after 链中它在执行“动作”后运行“过滤器”。“过滤器”是被动的,它由一个“控制器”激活。它们在请求处理中也可有更多的活动
部分。如果一个before“过滤器”返回false,“过滤器”链被中止并且“动作”不会运行。
“过滤器”也可能提交输出或重定向请求,在这种情况下原有的“动作”则从不会得到调用。
我们看一下125 页中我们商店的管理功能中用于授权时使用“过滤器”的例子。我们定
义一个授权方法,如果当前的“会话”中没有登录用户,则它重定向到一个登录屏幕。
def authorize
unless session[:user_id]
flash[:notice] = "Please log in"
redirect_to(:controller => "login", :action => "login")
end
end
那么在管理者“控制器”内的所有“动作”都要使用这个before“过滤器”方法。
class AdminController < ApplicationController
before_filter :authorize
# ...
这儿有个例子,它有个方法行为类似于一个“过滤器”;我们以符号方式传递方法的名
字给before_filter。filter 也声明接受块和类名字。如果指定了一个块,它将用当前“控制器”做为一参数来被调用。如果给出类,它的filter()类方法将带有做为参数的“控制器”被调用。
class AuditFilter
def self.filter(controller)
AuditLog.create(:action => controller.action_name)
end
end
# ...
class SomeController < ApplicationController
before_filter do |controller|
logger.info("Processing #{controller.action_name}")
end
after_filter AuditFilter
# ...
end
缺省地,“过滤器”被应用于一个“控制器”(和这个“控制器”的所有子类)内的所有
“动作”。你可以修改它用选项:only,它接受一个或多个要被过滤的“动作”,:except 选项,则列出被“过滤器”排除的“动作”。
class BlogController < ApplicationController
before_filter :authorize,nly => [ :delete, :edit_comment ]
after_filter :log_access, :except => :rss
# ...
before_filter 和after_filter 声明被附加给“控制器”的“过滤器”链。使用各种
prepend_before_filter()和prepend_after_filter()方法来在链的头部放置“过滤器”。

After Filters and Response Munging
如果需要话,after“过滤器”可以被用于修改外部“应答”,修改“头”和内容。一些
应用程序使用这个技术来完成对“控制器”的模板创建的内容全局的置换(例如,在“应答”
体内用字符串<customer/>置换一个客户的名字)。另一种用法是如果用户的浏览器支持的话,
可以压缩“应答”。
下面的代码是如何用它来工作的例子。[这个代码没有个完整的压缩实现。特别地,它没
有使用send_file()压缩下载的数据流。]“控制器”声明了compress()方法为一个after“过滤器”。方法查看“请求头”,看浏览器是否接受被压缩的请求。如果接受,它使用Zlib 库来压缩“应答”体到一个字符串内。[注意,Zlib Ruby 扩展可以在你的平台上无效—它依赖于基础libzlib.a 库的表现。] 如果结果比原有的体小,它替换压缩版本并更新“应答”编码类型。
require 'zlib'
require 'stringio'
class CompressController < ApplicationController
after_filter :compress
def index
render(:text => "<pre>" + File.read("/etc/motd") + "</pre>")
end
protected
def compress
accepts = request.env['HTTP_ACCEPT_ENCODING']
return unless accepts && accepts =~ /(x-gzip|gzip)/
encoding = $1
output = StringIO.new
def output.close # Zlib does a close. Bad Zlib...
rewind
end
gz = Zlib::GzipWriter.new(output)
gz.write(response.body)
gz.close
if output.length < response.body.length
response.body = output.string
response.headers['Content-encoding'] = encoding
end
end
end

Around “过滤器”
除了单独的before和after过滤器之外,也可以指定一个能处理before和after两者调用的单个对象。这对在你需要在before和after之间保持状态特别有用。如下面的benchmark过滤器例子。
class WeblogController < ActionController::Base
around_filter BenchmarkingFilter.new
# 这个动作完成之前,BenchmarkingFilter#before(controller) 被执行。
def index
end
# 在这个动作已经完成之后,BenchmarkingFilter#after(controller) 执行。
end
class BenchmarkingFilter
def initialize
@runtime
end
def before
start_timer
end
def after
stop_timer
report_result
end
end
不像before 和after“过滤器”,around“过滤器”不接受:only 或:except 参数。
around“过滤器”添加不同的“过滤器”链。Around 对象的before()方法被附加到链上,
而after()方法被优先于after 链。这意味着那个around 对象将可正确地嵌套。如果你写
around_filter A.new, B.new
则“过滤器”的调用次序将是:
A#before()
B#before
action...
B#after
A#after
继承“过滤器”
如果你子类化包含“过滤器”的“控制器”,则“过滤器”就像在父对象上一样将在子
对象上运行。但是,“过滤器”若定义在子类内则就不能在父对象上运行。

A、Filter inheritance --- 过滤器继承
控制器继承层次向下共享过滤器,但子类也可以添加新的过滤器,而不会影响到超类。例如:
class BankController < ActionController::Base
before_filter :audit
private
def audit
# record the action and parameters in an audit log
end
end

class VaultController < BankController
before_filter :verify_credentials
private
def verify_credentials
# make sure the user is allowed into the vault
end
end
现在BankController内的任何动作在完成前必须调用audit方法。在VaultController内,首先audit方法被调用,然后是verify_credetials方法被调用。如果audit方法返回false,那么verify_credentials和目标动作都会被中止。
B、Filter types --- 过滤器类型
过滤器可以接受三种模式中的一个:方法引用(符号),外部类,或内联方法(proc)。第一个是最常用的,它使用一个符号来引用控制器继承体系内某处的protected或private方法来工作。在上面的bank例子中,BankController和VaultController两者都使用了种格式。
使用外部类可轻易地重复使用通用过滤器,例如输出压缩。外部过滤器类由一个含有静态的filter方法的任意类实现,然后传递这个类给filter方法。例如:
class OutputCompressionFilter
def self.filter(controller) #静态的filter方法。
controller.response.body = compress(controller.response.body)
end
end
class NewspaperController < ActionController::Base
after_filter OutputCompressionFilter
end
这个filter方法被传递一个控制器实例,因此它可以访问控制器内的所有东西,并可以操纵它们。
内联方法(使用一个proc)可以用于快速地完成一些不需要太多的解释的小巧事情。或者是做为一个快速测试。它像这样工作:
class WeblogController < ActionController::Base
before_filter { |controller| false if controller.params["stop_action"] }
end
像你看到的,块被传递控制器后,它赋值请求给内部变量。这意味着可以访问request和response两者提供的方便的params,session,template,和assigns方法。注意:内联方法不是严格要求必须有一个块的;任何对应答返回1或-1的对象都可以(如Proc或一个Method对象)。
C、Filter chain ordering --- 过滤器链的次序
before_filter和after_filter被附加给现在链的指定过滤器。这用起来很好,胆有时候你可能想调整被运行过滤器的次序,这种情况下,你可以使用prepend_before_filter和prepend_after_filter。由这些方法添加的过滤器会被放到它们各自链的开始处,并会其它过滤器之前运行。例如:
class ShoppingController
before_filter :verify_open_shop
class CheckoutController
prepend_before_filter :ensure_items_in_cart, :ensure_items_in_stock
现在用于CheckoutController的过滤器链是 :ensure_items_in_cart, :ensure_items_in_stock, :verify_open_shop。所以如果ensure过滤器返回false,我们就不需要查看其它过滤器了。
你可以传递每种类型过滤器的多个参数做为一个过滤器块。如果给出一个这样的块,它会被视为大参数。
分享到:
评论

相关推荐

    基于springboot的过滤器。拦截器,Aspect,定时器

    创建一个切面需要定义一个带有`@Aspect`注解的类,并使用`@Before`、`@After`、`@Around`等注解定义通知(advice)。例如: ```java @Component @Aspect public class LoggingAspect { @Before("execution(* ...

    SpringBoot实现过滤器、拦截器与切片的实现和区别

    SpringBoot实现过滤器、拦截器与切片的实现和区别 过滤器(Filter)是J2EE中来的,可以看做是Servlet的一种“加强版”,它主要用于对用户请求进行预处理和后处理,拥有一个典型的处理链。Filter也可以对用户请求...

    注解敏感词过滤.rar

    Spring框架提供了`@Before`、`@After`、`@Around`等注解,可以与自定义的切面(Aspect)配合使用,以在方法调用前后执行特定逻辑。在这个场景下,我们可以创建一个名为`@SensitiveWordCheck`的自定义注解,将其添加...

    Spring注解 - 52注解 - 原稿笔记

    注解包含: 拦截器 , 过滤器 , 序列化 , @After , @AfterReturning , @AfterThrowing , @annotation , @Around , @Aspect , @Autowired , @Bean , @Before , @Component , @ComponentScan , @ComponentScans , @...

    Spring拦截器示例

    而Spring拦截器则是实现AOP的一种方式,它类似于Java的Servlet过滤器,可以在方法调用前后执行自定义的操作。 AOP拦截器在Spring中主要通过`HandlerInterceptor`接口或者`@AspectJ`注解来实现。下面我们将详细探讨...

    spring aop

    Spring支持五种类型的通知:前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)和环绕通知(Around)。 - **连接点(Join Point)**:程序执行过程中的某个特定点,...

    servlet api帮助文档,Junit api,spring 2.5api

    Servlet API还包括过滤器(Filter)和监听器(Listener)机制,用于实现请求拦截、资源初始化和销毁等功能。 2. JUnit API: JUnit是Java编程语言中最常用的单元测试框架,它的API设计简洁且功能强大。在JUnit API...

    springboot demo

    通过@Aspect注解定义切面,@Before、@After、@Around等注解定义切面的行为。 【Redis集成】 Redis是一个高性能的键值存储系统,常用于缓存、消息队列等场景。SpringBoot提供了对Redis的简单集成,通过配置可以轻松...

    利用AOP来变更工作线程的名字,来快速过滤出一次请求的所有日志.docx

    在给定的代码中,开发者使用AOP来改变工作线程的名字,以便于在大量日志中快速定位和过滤出特定请求的所有相关日志条目。这样做是因为线程名通常是唯一的,当每个请求到来时,为该请求的工作线程赋予一个唯一的标识...

    Spring入门书籍

    - 通知类型:学习Before、After、AfterReturning、Around、AfterThrowing五种通知类型及其应用场景。 5. **Spring MVC** - MVC架构:了解Spring MVC的基本结构和工作流程。 - Controller:编写Controller类处理...

    SSH框架部分常见面试题.pdf

    Spring 的通知类型有 Before、After、AfterReturning、AfterThrowing、Around 五种。 面向过程的编程、面向对象的编程、面向接口的编程、面向切面的编程 面向过程的编程是编程的基本方式,面向对象的编程是使用...

    SpringBoot+AOP日志服务

    这个类通常会包含一个或多个`@Before`、`@After`、`@Around`、`@AfterReturning`或`@AfterThrowing`注解的方法,这些方法定义了不同类型的通知。 3. **定义切点表达式**: 切点表达式使用XPath-like语法定义,用于...

    Spring攻略源代码 Spring Recipes

    在`Chapter05`和`Chapter09`中,可能会详细讲解如何定义和使用Aspect,以及通知类型(Before、After、Around等)的应用。 3. **数据访问**:Spring提供了对各种数据库的支持,包括JDBC、ORM(对象关系映射)框架如...

    struts2整合Spring和hibernate案例

    Spring还提供了AOP注解,如@After、@Before和@Around,用于定义切面。 4. **整合流程**: - 配置Struts2的struts.xml,设置过滤器,指定Action配置的包。 - 配置Spring的applicationContext.xml,定义bean,使用...

    spring 4.11源码

    在Spring 4.11中,`Aspect`接口和`@Aspect`注解用于定义切面,`@Before`、`@After`、`@Around`等注解用于定义通知(advice),这些通知会在特定的连接点(join point,如方法调用)执行。`Pointcut`表达式用于定义...

    企业级信息系统开发教学PPT(3.1)

    Spring AOP支持多种类型的Advice,如before、after、around等,定义Pointcut来指定何时执行Advice。Spring还提供了声明式事务管理,如TransactionProxyFactoryBean、BeanNameAutoProxyCreator(常用)和...

    AspectJ 文档

    AspectJ定义了不同类型的通知,包括前置通知(@Before)、后置通知(@After)、环绕通知(@Around)和引介通知(@DeclareParents)。这些通知分别定义了在连接点执行之前、之后、环绕执行或者在运行时引入新的接口...

    史上最全70道Spring面试题!.zip

    - 前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)、环绕通知(Around)。 6. **Spring MVC**: - MVC模式在Spring中的实现,处理HTTP请求和响应。 - ...

    jsp编程技术复习题

    `struts.xml`用于配置应用程序的行为和组件,而`web.xml`是Web应用程序级别的配置文件,用于配置如过滤器、监听器等。 - **EL表达式的用法**:EL (Expression Language) 是一种简单的脚本语言,用于在JSP页面中访问...

    spring 所有功能详解

    **Spring Web**模块提供了对Web开发的支持,包括对Servlet API、过滤器、监听器等的支持。 #### 七、Spring Web MVC框架 **Spring Web MVC**是Spring框架中的一个模块,专门用于Web应用程序的模型-视图-控制器...

Global site tag (gtag.js) - Google Analytics