[Perl] Catalyst Tutorial 最佳实践

“最佳实践”这个词似乎很 HOT,我也手痒痒想写一个自己亲笔写的~“最佳实践”,最近重回 Perl 的怀抱,正在 Catalyst MVC 的海洋里面自由航行,一方面也考虑到国内还鲜有这方面的资料,于是乎就记下了这篇《Catalyst Tutorial 最佳实践》,希望喜欢 Perl 的朋友们会喜欢,由于是开发笔记,所以记录的比较随意,如果大家在阅读的过程中遇到什么问题,欢迎直接与我联系:)

首先介绍一下Catalyst:引用用官方网站的话来说,Catalyst 是一个“优雅”的 MVC 框架,一直以来在我所接触的 WEB 开发框架中,我认为能称得上“优雅”的的确不多,而既优雅又敏捷的更是屈指可数了。回首从 ROR 的出现以来,网络应用开发界掀起了无休止的敏捷开发的风暴,而在商业应用领域 spring 和 maven 的出现让 J2EE 真正的优雅了起来,以上提及的这些都不失为我认为的成功框架的典范,直到我遇到 Catalyst,心中 NO.1 的位置渐渐被它所征服 ... 最令人兴奋的是不仅背后有强大的 CPAN 类库支持,还有可以让 Apache 成为“私家容器”的 mod_perl 的辅佐,另外 Makefile.PL 的代码管理让他自成一体,让我实在找不出不用他的理由。废话不说了,下面就让我们开始 Catalyst 的最佳实践吧。


Catalyst Best Tutorial

[linux environment]

>遇到问题 LWP not available

>解决方法
cpan > o conf init
cpan > o conf urllist shift
cpan > o conf urllist push ftp://ftp-mirror.internap.com/pub/CPAN/ (ftp://www.perl87.cn/CPAN/ for china)
cpan > o conf urllist
cpan > o conf commit (永久保存以上设置)
cpan > install LWP::UserAgent (use LWP to download)
cpan > reload cpan (update CPAN module)
cpan > install Bundle::CPAN

[windows environment]

>安装 ActivePerl
download from http://www.activestate.com/

>安装 mod_perl
ppm-shell (我在 5.10 下遇到 ppm install failed: the ppd does not provide code to install for this platform 必须把 perl 的版本降到 5.8.x)
ppm > gui (打开 GUI 界面,然后加入新的 Repo : http://theoryx5.uwinnipeg.ca/ppms/package.xml)
ppm > search mod_perl (这里注意 mod_perl 的 package 可能有多个,默认是 Apache2.2.x 版本,如果你安装的是 Apache2.0.x 则必须安装 mod_perl-2.0 模块,shell 控制台可能找不到 mod_perl-2.0 但是可以从 GUI 中找到)
ppm > install mod_perl-2.0 --force (强制安装才可以)
然后设置 Apache 配置文件即可 :
...
LoadFile "C:/Perl/bin/perl58.dll"
LoadModule perl_module modules/mod_perl.so
...

>安装 Eclipse Plugin
eclipse plugin update url - http://e-p-i-c.sf.net/updates

[tutorial begin]

>安装基础包
#cpan -fi Task::Catalyst (includes Catalyst::Devel)
#cpan -fi Catalyst::Devel

>建立骨架
#cd /path/to/webroot
#catalyst.pl Hello
#cd Hello
#script/hello_server.pl (下面步骤都要重启,建议写个 console 命令来简化操作)
访问 http://127.0.0.1:3000 你就会看到 Catalyst 的欢迎页面了

>建立 View
#script/hello_create.pl view TT TT (创建继承自 Catalyst::View::TT 的 lib/Hello/View/TT.pm)
这里插如介绍一下模板的设置选项 (可在 lib/Hello/View/TT.pm 设置):
__PACKAGE__->config(
    TEMPLATE_EXTENSION => '.html', #设置默认的模板扩展名
    INCLUDE_PATH => [
        MyApp->path_to( 'root', 'src' ), #设置模板根路径为 root/src/
    ],
);
#vi root/hello.tt
+1 line
This is a TT view template, called '[% template.name %]'.
#vi lib/Hello/Controller/Root.pm
+4 lines
sub hello : Global {
    my ( $self, $c ) = @_;
    $c->stash->{template} = 'hello.tt';
}
重启/访问 http://127.0.0.1:3000/hello 看到结果:This is a TT view template, called 'hello.tt'.

>建立 Controller
#script/hello_create.pl controller Site
#vi lib/Hello/Controller/Site.pm
+5 lines
sub test : Local {
    my ( $self, $c ) = @_;
    $c->stash->{username} = "James";
    $c->stash->{template} = 'site/test.tt';
}
这里注意几个方法的属性:
:Private    - 不会被 dispatch 的方法
:Path        - 可以通过 Path('/url/path') 动态设置方法的 url
:Local        - 等同于 Path('_name_of_method_')
:Global        - 等同于 Path('/_name_of_method_')
:Chained    - 最新的属性,服务器自动 dispatch
#vi root/site/test.tt
+1 line
<p>Hello, [% username %]!</p>
重启/访问 http://192.168.100.69:3000/site/test 看到结果:Hello, James!

>建立 DB / Model
建立 misc 目录,用于保存一些杂项
#cd misc
#vi hello01.sql
--
-- Create a very simple database to hold book and author information
--
CREATE TABLE books (
        id          INTEGER PRIMARY KEY,
        title       TEXT ,
        rating      INTEGER
);
-- 'book_authors' is a many-to-many join table between books & authors
CREATE TABLE book_authors (
        book_id     INTEGER,
        author_id   INTEGER,
        PRIMARY KEY (book_id, author_id)
);
CREATE TABLE authors (
        id          INTEGER PRIMARY KEY,
        first_name  TEXT,
        last_name   TEXT
);
---
--- Load some sample data
---
INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
INSERT INTO authors VALUES (3, 'Christian', 'Degu');
INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
INSERT INTO authors VALUES (7, 'Nathan', 'Torkington');
INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
INSERT INTO book_authors VALUES (1, 1);
INSERT INTO book_authors VALUES (1, 2);
INSERT INTO book_authors VALUES (1, 3);
INSERT INTO book_authors VALUES (2, 4);
INSERT INTO book_authors VALUES (3, 5);
INSERT INTO book_authors VALUES (4, 6);
INSERT INTO book_authors VALUES (4, 7);
INSERT INTO book_authors VALUES (5, 8);
#sqlite3 hello.db < hello01.sql
#script/hello_create.pl model DB DBIC::Schema Hello::Schema create=dynamic dbi:SQLite:misc/hello.db
注意这里的 dbi:SQLite:misc/hello.db 中的 SQLite 不可以小写,否则 DBIC 会报错如下 DBI Connection failed: install_driver(sqlite) failed ...
#script/hello_create.pl controller Book
#vi lib/Hello/Controller/Book.pm
+8 lines
=head2 list
Fetch all book objects and pass to books/list.tt in stash to be displayed
=cut
sub list : Local {
    my ($self, $c) = @_;
    $c->stash->{books} = [$c->model('DB::Books')->all];
    $c->stash->{template} = 'book/list.tt';
}
#vi root/book/list.tt
[% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
[% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
[% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
[%- # optional, but both the beginning and the ending TT tags support chomping. -%]
[% # Provide a title -%]
[% META title = 'Book List' -%]
<table>
<tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
[% # Display each book in a table row %]
[% FOREACH book IN books -%]
  <tr>
    <td>[% book.title %]</td>
    <td>[% book.rating %]</td>
    <td>
      [% # First initialize a TT variable to hold a list.  Then use a TT FOREACH -%]
      [% # loop in 'side effect notation' to load just the last names of the     -%]
      [% # authors into the list. Note that the 'push' TT vmethod does not print -%]
      [% # a value, so nothing will be printed here.  But, if you have something -%]
      [% # in TT that does return a method and you don't want it printed, you    -%]
      [% # can: 1) assign it to a bogus value, or 2) use the CALL keyword to     -%]
      [% # call it and discard the return value.                                 -%]
      [% tt_authors = [ ];
         tt_authors.push(author.last_name) FOREACH author = book.authors %]
      [% # Now use a TT 'virtual method' to display the author count in parens   -%]
      [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
      ([% tt_authors.size | html %])
      [% # Use another TT vmethod to join & print the names & comma separators   -%]
      [% tt_authors.join(', ') | html %]
    </td>
  </tr>
[% END -%]
</table>
重启/访问 http://192.168.100.69:3000/book/list 看到结果:
Title    Rating    Author(s)
CCSP SNRS Exam Certification Guide     5     (0)
TCP/IP Illustrated, Volume 1     5     (0)
Internetworking with TCP/IP Vol.1     4     (0)
Perl Cookbook     5     (0)
Designing with Web Standards     5     (0)

>建立 Table Mapping
上面提到的 #script/hello_create.pl model DB DBIC::Schema Hello::Schema create=dynamic dbi:SQLite:misc/hello.db 命令中的 create=dynamic 代表的是 Table Schema 是动态载入的,如果我们要获得更多的功能 (比如设置表映射等) 则我们需要用 create=static 代替,但是要注意重新运行命令前要先删除 lib/Hello/Schema.pm 文件,否则会报错。
#script/hello_create.pl model DB DBIC::Schema Hello::Schema create=static dbi:SQLite:misc/hello.db
#vi lib/Hello/Schema/Result/Books.pm
+ 3 lines
# Set relationships:
__PACKAGE__->has_many(book_authors => 'Hello::Schema::Result::BookAuthors', 'book_id');
__PACKAGE__->many_to_many(authors => 'book_authors', 'author');
#vi lib/Hello/Schema/Result/Authors.pm
+ 3 lines
# Set relationships:
__PACKAGE__->has_many(book_author => 'Hello::Schema::Result::BookAuthors', 'author_id');
__PACKAGE__->many_to_many(books => 'book_author', 'book');
+ 3 lines
#vi lib/Hello/Schema/Result/BookAuthors.pm
# Set relationships:
__PACKAGE__->belongs_to(book => 'Hello::Schema::Result::Books', 'book_id');
__PACKAGE__->belongs_to(author => 'Hello::Schema::Result::Authors', 'author_id');
重启/访问 http://192.168.100.69:3000/book/list 看到结果:
Title    Rating    Author(s)
CCSP SNRS Exam Certification Guide     5     (3) Bastien, Nasseh, Degu
TCP/IP Illustrated, Volume 1     5     (1) Stevens
Internetworking with TCP/IP Vol.1     4     (1) Comer
Perl Cookbook     5     (2) Christiansen, Torkington
Designing with Web Standards     5     (1) Zeldman

>发布项目
首先应该保证 mod_perl 被正确安装了,然后准备打包
#perl Makefile.PL
#make
#make install
#vi /path/to/apache/vhost.conf
+5 lines
PerlModule Hello
<Location />
    SetHandler          modperl
    PerlResponseHandler Hello
</Location>
当然我们也可以用Apache进行调试,这样要在@INC加入开发路径:
#vi /path/to/apache/vhost.conf
+2line
PerlOptions +Parent
PerlSwitches -I/path/to/Hello/lib
然后重启 Apache 并访问 http://192.168.100.69/book/list 看到正常页面,那么恭喜你发布成功,这里重提一下由于 mod_perl 会预先把要用的模块载入内存,所以这个应用的速度会非常快~ 太酷了~

[Summary]
我们在这里介绍了 Catalyst 的环境安装、基本命令、常用操作和一些基本代码编写方面的经验,涵盖了 Catalyst::Manual::Tutorial 前三章的内容,基本已经让大家入门了,如果大家想要进一步的学习可以到 CPAN 上参考 Catalyst::Manual::Tutorial 余下的内容,源码大家可以通过 svn co http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/ CatalystTutorial 直接下载,本篇内容我还会继续补充,希望大家会喜欢:)


原文链接: http://blog.csdn.net/shagoo/article/details/4043511

你可能感兴趣的:([Perl] Catalyst Tutorial 最佳实践)