IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    PerlDancer 框架笔记

    陈子 (rao.chenlin@gmail.com)发表于 2014-06-12 00:00:00
    love 0

    Dancer 是 Perl 的 web 开发框架,在 metacpan 上有 100 多个 like。其语法结构都起源自 Ruby 的 sinatra 框架,sinatra 曾经在自己官网上悬挂“perldancer is good”标语以示对 perldancer 的支持。Dancer 官网见: http://perldancer.org/ 本文系本人在部门 Wiki 上稍微写的几行介绍性质的笔记。

    简单示例

    Dancer 作为微框架,可以直接单文件快速运行简单的 web 功能。示例如下:

        use Dancer;
        get '/' => sub {
            return "hello world";
        };
        dance;
    

    然后直接通过 perl test.pl 命令既可以在 localhost:3000 运行起来一个 hello world 页面了。

    目录结构

    完整的 Dancer 应用,可以通过 dancer -a MyApp 命令创建,目录结构如下:

    MyApp/
    ├── bin
    │   └── app.pl                    # 程序运行入口,可以直接通过./app.pl运行,也可以通过plackup -s Starman app.pl来切换其他高性能服务器
    ├── config.yml                     # 主配置文件
    ├── environments
    │   ├── development.yml
    │   └── production.yml
    ├── lib
    │   └── MyApp.pm                  # Perl代码入口,route、controller、ORM 等都在 lib 下
    ├── Makefile.PL
    ├── MANIFEST
    ├── MANIFEST.SKIP
    ├── public                         # public/ 下的文件会直接作为静态文件发布,相当于 DocumentRoot
    │   ├── 404.html
    │   ├── 500.html
    │   ├── css
    │   │   ├── error.css
    │   │   └── style.css
    │   ├── dispatch.cgi
    │   ├── dispatch.fcgi
    │   ├── favicon.ico
    │   ├── images
    │   │   ├── perldancer-bg.jpg
    │   │   └── perldancer.jpg
    │   └── javascripts
    │       └── jquery.js
    ├── t
    │   ├── 001_base.t
    │   └── 002_index_route.t
    └── views                           # views/ 下的文件是页面模板,在 lib 里通过 template('index') 方式调用
        ├── index.tt
        └── layouts
            └── main.tt                 # layouts 是页面模板的底层模板,主底层模板可以在 config.yml 里指定
    

    常用插件

    目前用 Dancer 写的 CdnManage 平台,用到的插件包括:

    • Dancer::Template::Xslate

    采用 Text::Xslate 作为模板引擎。xslate 引擎是用 XS 写的类 Perl6 语法模板引擎,性能很好。语法示例如下:

    <: $object.accessor :>
    <: $str :>
    <: $array.0 :>
    <: $hash.key :>
    : for $arrayref -> $item {
        index: <: $~item :> value: <: $item :>
    : }
    : if ( $var == nil ) {
    : } else if ( $val == "text" ) {
    : } else {
    :     while $dbh.fetch() -> $item {
    :     }
    : }
    

    注意,CdnManage 中,因为是从 TT2 模板迁移到 xslate 里的,所以单独配置了 config.yml,没有用 : 号而是沿用了 % 号。

    • Dancer::Session::YAML

    采用 YAML 存储 session,这个作为内部应用足够了,升级的话应该用 mysql、mongo、elasticsearch之类的存储,都有现成插件。

    • Plack::Middleware::Deflater
    • Plack::Middleware::ETag

    上面两个作为给 public/ 下文件加缓存和压缩的优化。在 config.yml 里添加如下配置即可使用:

    plack_middlewares:
      -
        - Plack::Middleware::Deflater
        - Plack::Middleware::ETag
    
    • Dancer::Plugin::Auth::Extensible

    给 route 加认证功能,有 require_role 和 require_user 两种形式,示例如下:

        get '/admin' => require_user 'admin' => sub {};
        post '/purge' => require_role qr/^purge_\w+/ => sub {};
    
    • Dancer::Plugin::Email

    发邮件

    • Dancer::Plugin::GearmanXS

    将需要较长时间运行完的任务通过 gearman 分发到其他后台任务脚本上去完成。

    • Dancer::Plugin::Datebase

    数据库插件,可以直接按照 DBI 操作,也提供了简单的 quick_select/insert 等指令。示例如下:

        get '/users/:id' => sub {
            template 'display_user', {
                person => database->quick_select('users', { id => params->{id} }),
            };
        };
    

    如果在 config.yml 定义了多个库,则通过 database('name') 的方式来调用。

      Database:
        connections:
          puppet:
            driver: "SQLite"
            database: "/etc/puppet/webui/node_info.db"
          cdnmanage:
            driver: "mysql"
            database: "cdnmanage"
            host: "127.0.0.1"
            port: 3306
            username: "user"
            password: "pass"
            connection_check_threshold: 10
            on_connect_do: ["SET NAMES 'utf8'", "SET CHARACTER SET 'utf8'" ]
    

    更完善的 ORM 使用,见 Dancer::Plugin::DBIC 插件,他使用的是 DBIx::Class 框架做 ORM,示例如下:

        get '/users/:user_id' => sub {
            my $user = schema('default')->resultset('User')->find(param 'user_id');
            # 如果只有一个默认的schema在config.yml里那么上面这行可以简写成下行
            $user = rset('User')->find(param 'user_id');
            template user_profile => {
                user => $user
            };
        };
    
    • Dancer::Plugin::ElasticSearch

    elasticsearch 插件,类似 Dancer::Plugin::Database;所以同理,也有更偏 ORM 一点的 Dancer::Plugin::ElasticModel 插件。

    • Dancer::Plugin::Deferred

    页面消息提示插件。使用示例:

        hook before => sub {
            if (    request->uri =~ m#^/puppetdb/#
                and request->uri !~ m#^/puppetdb/api/#
                and !user_has_role('SOM') )
            {
                deferred error => 'no permission';
                redirect '/';
            }
        };
    

    然后在底层模板layouts/main.tt 中:

    %% if $deferred.error {
      <div class="alert alert-success"> [% $deferred.error %] </div>
    %% }
    
    • Dancer::Plugin::Ajax

    扩展默认的 get/post/delete/put 指令,提供 ajax 指令。

    • Dancer::Plugin::SimpleCRUD

    提供简便的数据库 CRUD 操作表单。目前 Puppet 的 SQLite 操作实例如下:

      simple_crud(
        db_connection_name => 'puppet',
        db_table           => 'node_info',
        key_column         => 'id',
        prefix             => 'node_info',
        record_title       => 'Puppet Node',
        deleteable         => 1,
        paginate           => 50,
        validation         => {
            classes     => '/^(\w,?)+$/',
            role        => '/^\w+$/',
            environment => '/^\w+$/',
        },
        message => {
            classes => 'enter like "puppetd,repos"',
            role    => 'an english word only',
        },
        display_columns => [qw(node_fqdn environment role)],
        custom_columns  => {
            include_classes => {
                raw_column => 'classes',
                transform  => sub {
                    my @classes = split( /,/, shift );
                    my $self    = shift;
                    my $role    = $self->{'role'};
                    my $env     = $self->{'environment'};
                    my @lines;
                    push @lines, "<a href='/puppetdb/$env/$_/$role/view'>$_</a>"
                      for @classes;
                    return join( " / ", @lines );
                },
            },
        },
      );
    


沪ICP备19023445号-2号
友情链接