기본 콘텐츠로 건너뛰기

perl catalyst jquery file upload

perl catalyst 를 사용해 jquery file upload 를 구현.

html - angularjs.tx

<!DOCTYPE HTML>

<html lang="en">
<head>

<meta charset="utf-8">
<title>jQuery File Upload Demo - AngularJS version</title>

<!-- Bootstrap styles -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/style.css">
<!-- blueimp Gallery styles -->
<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
<link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/jquery.fileupload.css">
<link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/jquery.fileupload-ui.css">
<!-- CSS adjustments for browsers with JavaScript disabled -->
<noscript><link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/jquery.fileupload-noscript.css"></noscript>
<noscript><link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/jquery.fileupload-ui-noscript.css"></noscript>
<style>
/* Hide Angular JS elements before initializing */
.ng-cloak {
    display: none;
}
</style>
</head>
<body>
<div class="container">
    <!-- The file upload form used as target for the file upload widget -->
    <form id="fileupload" action="/jqueryupload/upload" method="POST" enctype="multipart/form-data" data-ng-app="demo" data-ng-controller="DemoFileUploadController" data-file-upload="options" data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
        <!-- Redirect browsers with JavaScript disabled to the origin page -->
        <noscript><input type="hidden" name="redirect" value="/jqueryupload/upload"></noscript>
        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
        <div class="row fileupload-buttonbar">
            <div class="col-lg-7">
                <!-- The fileinput-button span is used to style the file input field as button -->
                <span class="btn btn-success fileinput-button" ng-class="{disabled: disabled}">
                    <i class="glyphicon glyphicon-plus"></i>
                    <span>Add files...</span>
                    <input type="file" name="files[]" multiple ng-disabled="disabled">
                </span>
                <button type="button" class="btn btn-primary start" data-ng-click="submit()">
                    <i class="glyphicon glyphicon-upload"></i>
                    <span>Start upload</span>
                </button>
                <button type="button" class="btn btn-warning cancel" data-ng-click="cancel()">
                    <i class="glyphicon glyphicon-ban-circle"></i>
                    <span>Cancel upload</span>
                </button>
                <!-- The global file processing state -->
                <span class="fileupload-process"></span>
            </div>
            <!-- The global progress state -->
            <div class="col-lg-5 fade" data-ng-class="{in: active()}">
                <!-- The global progress bar -->
                <div class="progress progress-striped active" data-file-upload-progress="progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
                <!-- The extended global progress state -->
                <div class="progress-extended">&nbsp;</div>
            </div>
        </div>
        <!-- The table listing the files available for upload/download -->
        <table class="table table-striped files ng-cloak">
            <tr data-ng-repeat="file in queue" data-ng-class="{'processing': file.$processing()}">
                <td data-ng-switch data-on="!!file.thumbnailUrl">
                    <div class="preview" data-ng-switch-when="true">
                        <a data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery><img data-ng-src="{{file.thumbnailUrl}}" alt=""></a>
                    </div>
                    <div class="preview" data-ng-switch-default data-file-upload-preview="file"></div>
                </td>
                <td>
                    <p class="name" data-ng-switch data-on="!!file.url">
                        <span data-ng-switch-when="true" data-ng-switch data-on="!!file.thumbnailUrl">
                            <a data-ng-switch-when="true" data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery>{{file.name}}</a>
                            <a data-ng-switch-default data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}">{{file.name}}</a>
                        </span>
                        <span data-ng-switch-default>{{file.name}}</span>
                    </p>
                    <strong data-ng-show="file.error" class="error text-danger">{{file.error}}</strong>
                </td>
                <td>
                    <p class="size">{{file.size | formatFileSize}}</p>
                    <div class="progress progress-striped active fade" data-ng-class="{pending: 'in'}[file.$state()]" data-file-upload-progress="file.$progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
                </td>
                <td>
                    <button type="button" class="btn btn-primary start" data-ng-click="file.$submit()" data-ng-hide="!file.$submit || options.autoUpload" data-ng-disabled="file.$state() == 'pending' || file.$state() == 'rejected'">
                        <i class="glyphicon glyphicon-upload"></i>
                        <span>Start</span>
                    </button>
                    <button type="button" class="btn btn-warning cancel" data-ng-click="file.$cancel()" data-ng-hide="!file.$cancel">
                        <i class="glyphicon glyphicon-ban-circle"></i>
                        <span>Cancel</span>
                    </button>
                    <button data-ng-controller="FileDestroyController" type="button" class="btn btn-danger destroy" data-ng-click="file.$destroy()" data-ng-hide="!file.$destroy">
                        <i class="glyphicon glyphicon-trash"></i>
                        <span>Delete</span>
                    </button>
                </td>
            </tr>
        </table>
    </form>
    <br>
  
</div>
<!-- The blueimp Gallery widget -->
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
    <div class="slides"></div>
    <h3 class="title"></h3>
    <a class="prev">‹</a>
    <a class="next">›</a>
    <a class="close">×</a>
    <a class="play-pause"></a>
    <ol class="indicator"></ol>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/vendor/jquery.ui.widget.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<!-- blueimp Gallery script -->
<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload.js"></script>
<!-- The File Upload processing plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-process.js"></script>
<!-- The File Upload image preview & resize plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-image.js"></script>
<!-- The File Upload audio preview plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-audio.js"></script>
<!-- The File Upload video preview plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-video.js"></script>
<!-- The File Upload validation plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-validate.js"></script>
<!-- The File Upload Angular JS module -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-angular.js"></script>
<!-- The main application script -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/app.js"></script>
</body>
</html>




controller - Jqueryupload.pm

package Lars::Web::Controller::Jqueryupload;
use Moose;
use namespace::autoclean;
use utf8;
use JSON::XS;

BEGIN { extends 'Catalyst::Controller' }

sub index :Path :Args(0) {
    my ($self, $c) = @_;

    $c->stash->{template} = 'jqueryupload.tx';

sub jqueryui :Path("angularjs") :Args(0) {
    my ($self, $c) = @_;

    $c->stash->{template} = 'angularjs.tx';
}

# 업로드 구현
sub upload :Path("upload") :Args(0) :POST{
    my ($self, $c) = @_;

    my $file_upload = $c->req->upload('files[]');

    my $files;
    if ($file_upload) {
        $files = Lars::Util::Forum::image_path($file_upload->filename);
        $c->model('FsStore')->put_from_file($files, $file_upload->fh);
    }

    my $file = $c->model('DB::Attachment')->create(
        {
            create_date => \'now()',
            name => $file_upload->filename,
            path => $files,
        },
    );

    my $new_list = [
        { 
            url=>$files,
            thumbnail_url=>$files,
            name=>$file_upload->filename,
            size=>$file_upload->size,
            delete_url=>'http://url.to/delete /file/',
            delete_type=> 'DELETE'
        }
    ];

  
    $c->stash->{files} = $new_list;
    
    $c->forward('JSON');
    return;

}

util - Forum.pm 
package Lars::Util::Forum;
use strict;
use warnings;
use Data::Random qw/rand_chars/;

use Exporter 'import';
our @EXPORT_OK = qw/image_path/;

sub image_path {
    my $filename = shift;

    my $dt = DateTime->now;

    if ($filename =~ /\.(jpe?g|gif|png)$/i) {
        my $ext = lc $1;
        my $root = join '', '/image/', $dt->year, '/', $dt->month, '/', $dt->day;
        # my $name = Encode::encode('utf8', $filename);
        my $name = join '', time, rand_chars(size => 8, set => 'alphanumeric');
        # return $root.'/'.$name;
        return $root.'/'.$name . '.' . $ext;
    }
    return undef;
}

JSON Response 때문에 고생을 좀 했음. -_-... 굉장히 쓸데없는 고생었음.



{ 
  files:
    [
      {
        url: "http://url.to/file/or/page",
        thumbnail_url: "http://url.to/thumnail.jpg ",
        name: "thumb2.jpg",
        type: "image/jpeg",
        size: 46353,
        delete_url: "http://url.to/delete /file/",
        delete_type: "DELETE"
      }
    ]
}
이런 모양으로 받으면 됨.
빨간줄친모양으로 리턴 받으면 잘 됨. 

댓글

이 블로그의 인기 게시물

mac os + perl catalyst

맥 엘... 머를 사용하고 있다. 펄은 최신버전이 설치 되어 있다. cpan 모듈부터 설치한다. $ cpan App::cpanminus 바로 스마트시디 설치한다. $ https://github.com/cxreg/smartcd 그런데 zsh 쓰고 있어서 source 하면 터미널이 튕겨 버린다. 이렇게 하면 됨. $ source $HOME/.smartcd/lib/core/smartcd ( https://github.com/cxreg/smartcd/issues/25) 깃에 연동해야 하니까 ssh 키도 만든다. $ ssh-keygen 그런데 문제가 생기기는 한다... ivalid version format (version required) at /perl5/lib/perl5/Module/Runtime.pm line 386. BEGIN failed--compilation aborted at /perl5/lib/perl5/Catalyst/ScriptRunner.pm line 2. Compilation failed in require at Web/script/web_server.pl line 7. BEGIN failed--compilation aborted at Web/script/web_server.pl line 7. 뭐 대충 이런건데..... Moose 업데이트 하면 된다. cpanm Moose 이 때 PATH 경로안에  Moose 가 포함 되어 있어야 한다. 그냥 cpan 설치 할 때 moose도 포함 시켜서 한번에 인스톨하면 편함. 이제 맥에 포스트그래스만 설치하면 되는데...

전자정부 이클립스 스프링 부트

  1. 전자정부 이클립스 IDE 다운로드 2. 압축 해제후 실행.  Template Project 만들기. (아직은 Single 뿐이다.)

중 상급자가되기위한 JavaScript 【지식 편]

qiita : http://qiita.com/KENJU/items/c7fad62a12cc2809b507?utm_source=Qiita%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&utm_campaign=a25a5e9683-Qiita_newsletter_166_07_22_2015&utm_medium=email&utm_term=0_e44feaa081-a25a5e9683-32972029 그대로 복붙 해도 상관 없지만 나도 좀 보면서 정리 해야 되니까 조금씩 정리. 1. Basic Tips Index 1-1. 글로벌 변수를 남용하지 않는다. 1-2. for 루프 1-3. 암시 적 변환을 피하기 1-1. 글로벌 변수를 남용하지 않는다. , 타사 플러그인을 읽을 때 변수의 충돌 팀 구성원이 작성한 코드와 이름 충돌 옛날 쓴 자신의 코드에서 사용한 변수와 충돌 대책 : var JavaScript 는 var  없이 정의된 변수는 전역 변수로 스켄된다. function speakOut () { // global variable global = "Hello from global" ; // local variable var local = "Hello from local" ; console . log ( global ); console . log ( local ); } speakOut (); console . log ( global ); console . log ( local ); 대책 : 네임 스페이스를 사용 // Object for name space var myApp = {}; myApp . name = "My First JavaScript App" ; 대책 : 클로저를 이용. ( function (){ maybe_global = "...