分类:
2010-07-15 20:28:14
这是在互联网鲜见的中文文档了,不容易给找到了,呵呵. Catalyst 指南 - Catalyst 介绍 本文简单的介绍了为何要用 Catalyst 以及如何使用它。文中解释了 Catalyst 的工作原理并通过一个简单应用的快速建立来加以验证。 Catalyst 是一个优雅的 Web 应用框架,极为灵活又特别简单。它类似于 Ruby on Rails、Java 的 Spring 和 (原来就基于 建立)。 Catalyst 遵循模型-视图-控制(MVC)设计模式,它擅长将内容处理、表示和流程控制方面的工作区分开来交给独立的模块来做。这种区分允许你为某一方面的问题修改代码而不影响解决其它问题的代码。这样 Catalyst 提升了原有的解决 Web 应用方面的问题的模块的重用程度。 下面就是 M、V、C 分别解决的问题,每个方面都有著名的 Perl 模块的可用。
如果你不熟悉 MVC 和设计模式,你得查看一下这方面的原始资料:Gamma、Helm、Johson、Vlissides 写的 Design Patterns,也叫 Gang of Four 或 GoF。你也可以 google 一下。有很多很多的 Web 应用框架都是基于 MVC 的,如前面提到的那些。 Catalyst 比起其他的框架来说灵活很多。我们会慢慢的解释,很快就会看到那些你喜爱的 Perl 模块在 Catalyst 里面的应用。
Catalyst 最棒的地方在于它如此简单的实现了这样的灵活性。
快速起步 下面就是安装 Catalyst 并创建简单的可运行的应用的过程。这里用到了上面说到的辅助脚本。 $ perl -MCPAN -e 'install Bundle::Catalyst' $ catalyst.pl MyApp # output omitted $ cd MyApp $ script/myapp_create.pl controller Library::Login $ script/myapp_server.pl 现在可以用你喜欢的浏览器或者代理程序来访问下面的地址来检查 Catalyst 的运行状况: 太简单了! 我们来看看 Catalyst 如何工作,下面就开始仔细查看 Catalyst 组件和应用的其它部分。 应用类 在模板、视图和控制组件以外还有一个代表你的应用的类。在这个类里面可以配置应用、加载插件、定义应用级的动作、扩展 Catalyst。 package MyApp; use strict; use Catalyst qw/-Debug/; MyApp->config( name => 'My Application', root => '/home/joeuser/myapp/root', # You can put anything else you want in here: my_configuration_variable => 'something', ); sub default : Private { my ( $self, $context ) = @_; $context->response->output('Catalyst rockz!'); } 1; 对大多数应用来说,Catalyst 只要求你定义两个配置参数:
然而,你还可以定义传给插件或者其他东西的参数。可以在应用的任何位置用 Catalyst 自动把 Context 对象“赐”给你的应用类,这样整个应用里都能访问。Context 不但用来和 Catalyst 打交道,也能把应用的 Components 联系起来。比如想要在 Template Toolkit 模板里面使用 Context,只要这样:
好像前面的从 URL 派发动作的例子所展示的,Context 总是方法的第二个参数。它前面的参数是 Component 对象的引用或类名。我们以前为了清晰叫它 sub hello : Global { my ( $self, $c ) = @_; $c->res->output('Hello World!'); } The Context contains several important objects: Context 包含了几个重要的对象:
最后的那个 stash 是特别设立出来在应用的各组件之间共享数据的哈希表。例如我们可以这样回应 hello 动作: sub hello : Global { my ( $self, $c ) = @_; $c->stash->{message} = 'Hello World!'; $c->forward('show_message'); } sub show_message : Private { my ( $self, $c ) = @_; $c->res->output( $c->stash->{message} ); } 注意 stash 只能在每次请求周期内传递数据,对新的请求它会被清空。如果你需要更加持久的数据,请使用 session。 Catalyst 控制器是由动作来定义的。动作是一个带有属性的子程序。你已经在本文里面看到了几个动作的例子。URL(例如 )可分为两部分:基础部分(这个例子里面是 )和路径部分(foo/bar)。请注意 hostname[:port] 后面的正斜杠是属于基础部分而非路径部分的。 Catalyst 支持几类动作:
注意:看了这些例子后,你可能在想给正则和路径动作定义名字的目的何在。实际上任何公共的动作同时也是私有的,因此在组件间统一的调用方法是 为了响应某些特殊的应用需要,Catalyst 会自动调用你的应用类里面的某些内建私有动作。
Package MyApp::C::Foo; sub begin : Private { } sub default : Private { } 还可以在控制里面定义内建私有动作。它会覆盖高抽象级别的控制(或是应用类)的动作。换句话说在单个请求周期内,所有前面提到的三类内建私有动作,都只有一个能运行。好比 在普通的内建动作以外,还可以用 这是用来验证各种内建动作调用顺序的例子:
对于
这个例子在鉴权的动作来说很有用:你可以用应用类里面 注意: 换个角度看, 可以把 URL 路径的一部分作为可变参数来传递。为此得在定义动作键(下面 sub foo : Regex('^foo$') { my ($self, $context, $bar, $baz) = @_; } 但是如果同时还给 sub boo : Path('foo/boo') { .. } sub hoo : Path('foo/boo/hoo') { .. } Catalyst 会按照细节到抽象的顺序来匹配动作: /foo/boo/hoo /foo/boo /foo # might be /foo/bar/baz but won't be /foo/boo/hoo 这样 Catalyst 永远不会错误派发前面两个 URL 到 ^foo$ 动作。 在 URL 查询串里面传递的参数用 类的方法来处理。它的 # my $category = $c->req->param(’category’); my $current_page = $c->req->param(’page’) || 1; # multiple values for single parameter name my @values = $c->req->param('scrolling_list'); # DFV requires a CGI.pm-like input hash my $results = Data::FormValidator->check($c->req->params, \%dfv_profile); 用 看起来 sub hello : Global { my ( $self, $c ) = @_; $c->stash->{message} = 'Hello World!'; $c->forward('check_message'); # $c is automatically included } sub check_message : Private { my ( $self, $c ) = @_; return unless $c->stash->{message}; $c->forward('show_message'); } sub show_message : Private { my ( $self, $c ) = @_; $c->res->output( $c->stash->{message} ); }
可以用匿名数组给 sub hello : Global { my ( $self, $c ) = @_; $c->stash->{message} = 'Hello World!'; $c->forward('check_message',[qw/test1/]); # now $c->req->args is back to what it was before } sub check_message : Private { my ( $self, $c ) = @_; my $first_argument = $c->req->args[0]; # now = 'test1' # do something... } 在此可以看到,如果只想调用同一个控制里面的方法就可以单单用方法名字作为参数。如果想要调用不同控制(或主应用)里面的动作就得用绝对路径。 $c->forward('/my/controller/action'); $c->forward('/default'); # calls default in main application 下面是用类名和方法名来调用的例子。 sub hello : Global { my ( $self, $c ) = @_; $c->forward(qw/MyApp::M::Hello say_hello/); } sub bye : Global { my ( $self, $c ) = @_; $c->forward('MyApp::M::Hello'); # no method: will try 'process' } package MyApp::M::Hello; sub say_hello { my ( $self, $c ) = @_; $c->res->output('Hello World!'); } sub process { my ( $self, $c ) = @_; $c->res->output('Goodbye World!'); } 注意 Catalyst 有个非同寻常的灵活的组件系统。你可以自由的定义任意数量的 Models、Views、Controllers。 所有的组件都必须继承于 ,它提供简单的类结构和通用类方法如 package MyApp::C::Catalog; use strict; use base 'Catalyst::Base'; __PACKAGE__->config( foo => 'bar' ); 1; 你不必
视图 为要展示如何定义视图,我们要用代表 的基类 。我们需要做的只是继承这个类: package MyApp::V::TT; use strict; use base 'Catalyst::View::TT'; 1; (还可以用辅助脚本来自动生成这个: script/myapp_create.pl view TT TT 这里第一个 这就产生了一个 sub hello : Global { my ( $self, $c ) = @_; $c->stash->{template} = 'hello.tt'; } sub end : Private { my ( $self, $c ) = @_; $c->forward('MyApp::V::TT'); } 通常总是在请求的末尾来套用模板,因此使用全局的 还得记住把模板放在 模型 为了展示模型的定义,我们还是使用现存的基类。这次是 代表的 。 但是我们得先有个数据库。 -- myapp.sql CREATE TABLE foo ( id INTEGER PRIMARY KEY, data TEXT ); CREATE TABLE bar ( id INTEGER PRIMARY KEY, foo INTEGER REFERENCES foo, data TEXT ); INSERT INTO foo (data) VALUES ('TEST!'); % sqlite /tmp/myapp.db < myapp.sql 现在来给这个数据库创建一个 CDBI 组件。 package MyApp::M::CDBI; use strict; use base 'Catalyst::Model::CDBI'; __PACKAGE__->config( dsn => 'dbi:SQLite:/tmp/myapp.db', relationships => 1 ); 1; Catalyst 会自动载入表结构和关系。用 stash 来传递数据给模板。 package MyApp; use strict; use Catalyst '-Debug'; __PACKAGE__->config( name => 'My Application', root => '/home/joeuser/myapp/root' ); __PACKAGE__->setup; sub end : Private { my ( $self, $c ) = @_; $c->stash->{template} ||= 'index.tt'; $c->forward('MyApp::V::TT'); } sub view : Global { my ( $self, $c, $id ) = @_; $c->stash->{item} = MyApp::M::CDBI::Foo->retrieve($id); } 1; The id is [% item.data %] 多个控制器分工可以很好的将应用分割成不同的逻辑功能域。 package MyApp::C::Login; sign-in : Local { } new-password : Local { } sign-out : Local { } package MyApp::C::Catalog; sub view : Local { } sub list : Local { } package MyApp::C::Cart; sub add : Local { } sub update : Local { } sub order : Local { } 测试 Catalyst 有一个内建的 http server 用于测试!(当然可以用更强大的服务器如 Apache/mod_perl 来满足生产环境的需要。) 在命令行来启动程序 …… script/myapp_server.pl 然后用浏览器访问 来查看输出。 还可以完全从命令行完成: script/myapp_test.pl 好好享受吧! |