nkjmkzk.net

powered by Kazuki Nakajima

Archive for the ‘transloadit’ tag

Transloaditを使ってSalesforceから透過的にファイルをAmazon S3にアップロードする

SalesforceにはAttachmentやFilesといったファイル格納機構があります。ただ、そのファイルを外部公開する(認証不要でアクセス可とする)のは少し厄介です。そういう要件がある場合は素直にAmazon S3等にアップした方がよいケースもあるでしょう。

そんなアーキテクチャーでも、ユーザーにはSalesforceを使いながら意識させずにS3にアップロードするような実装をしたいものです。また、アップロードのコードも出来る限りさぼって書きたいですよね。

アップローダーとして使えそうなツールやサービスをいろいろ見ていると、UploadifyPluploadなどがあるなー、と。結果的に私はTransloaditというサービスを使ってみました。

Transloaditは単なるアップロードツールやWidgetという域にとどまらず、画像や動画のエンコーディングという中間処理を得意とするサービスです。そしてもちろんアップロードのためのUIもjQuery Pluginとして提供してくれています。使用感はこちらの動画で確認してみてください。

実際、クロスブラウザ対応などを含め、ファイルのアップロードというのはなにかと問題が発生する意外に難しい処理です。Transloaditはそのあたりのクライアント側の制御をjQuery Pluginを提供することで開発者から解放しつつ、その後の処理もクライアントとファイル格納先(S3等)の中間に入って動作することでお任せすることができるというサービスです。

S3にファイルをアップロードするときにTransloaditはリバースプロキシのような位置づけで機能します。クライアントはjQuery Pluginを使ってファイルをTransloaditにアップロードし、アップロードされたファイルは事前に定義されたTemplateに従って処理されます。最終格納場所(S3)にファイルが保存された後にクライアントはTransloaditからJSONレスポンスでファイルのメタデータを受け取ります。上のデモ動画では、このメタデータからファイルのURLを取得してSalesforceのフィールドに保存しています。

Transloaditのサイトにもこのアップローダーの構築方法が書かれていますが、ここでも簡単に解説しておきます。

まずアカウントを作成します。Transloaditは従量課金の有料サービスですが、100MB/月までは無料で利用できます。

次にTemplateを作成します。Templateはアップロードするファイルをどの順番で、どんな処理をおこなうかを記述したファイルです。これはTransloaditの管理画面から作成することができます。上のデモ動画で定義しているTemplateは下記の通りです。

{
  "steps": {
    "store": {
      "robot": "/s3/store",
      "key": "あなたのAWS KEY",
      "secret": "あなたのAWS SECRET",
      "bucket": "nkjm-sfdc-tokyo"
    }
  }
}

次にアップロードフォームを作成します。これはVisualforceで作成することになります。

<form id="MyForm" action="http://api2.transloadit.com/assemblies" enctype="multipart/form-data" method="POST">
    <input type="hidden" name="params" value='{"auth":{"key":"あなたのAPI KEY"},"template_id":"あなたのTemplate ID","redirect_url":"{!$CurrentPage.URL}"}'></input>
    <input type="file" name="my_file"></input>
    <input type="submit" value="Upload"></input>
</form>

次に同じVisulaforceページにアップローダーとなるjQuery Pluginを追加します。

<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" />
<apex:includeScript value="https://assets.transloadit.com/js/jquery.transloadit2.js" />

<script type="text/javascript">
   // We call .transloadit() after the DOM is initialized:
   j$ = jQuery.noConflict();
   j$(document).ready(function() {
     j$('#MyForm').transloadit({
        wait: true
     });
   });
</script>

次にファイルのアップロードが完了した際にJSONレスポンスを解析して必要な情報をデータベースに保存するApexクラスを作成します。

public class transloadit_uploader {
    public final product__c product;

    public transloadit_uploader(ApexPages.StandardController controller){
      product__c p = (product__c)controller.getRecord();
      if (p.id != null){
          this.product = [select id, name, price__c, code__c, discount_rate__c, photo_url__c, url_to_buy__c, description__c from product__c where id = :p.id];
      }
    }

    public void update_photo_url(){
        string s3_url;
        if (ApexPages.currentPage().getParameters().get('transloadit') != null){
            string result_json = ApexPages.currentPage().getParameters().get('transloadit');
            JSONParser parser = JSON.createParser(result_json);
            while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'url')) {
                    parser.nextToken();
                    if (parser.getText().contains('s3.amazonaws.com')){
                        s3_url = parser.getText();
                    }
                }
            }
        }
        if (s3_url != null){
            this.product.photo_url__c = s3_url;
            update this.product;
        }
    }
}

最後に、先ほどのVisualforceページに、上記のApexクラスのupdate_photo_url()を最初にキックするように<apex:page>タグにaction=”{!update_photo_url}”を追加します。

<apex:page standardController="sugoidiscount__product__c" extensions="sugoidiscount.transloadit_uploader" action="{!update_photo_url}">

最終的にデモのVisualforceページは下記のようになります。

<apex:page standardController="sugoidiscount__product__c" extensions="sugoidiscount.transloadit_uploader" action="{!update_photo_url}">
<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" />
<apex:includeScript value="https://assets.transloadit.com/js/jquery.transloadit2.js" />

<script type="text/javascript">
   // We call .transloadit() after the DOM is initialized:
   j$ = jQuery.noConflict();
   j$(document).ready(function() {
     j$('#MyForm').transloadit({
        wait: true
     });
   });
</script>

<apex:detail />

<apex:pageBlock title="{!$Label.sugoidiscount__upload_photo}" mode="edit">
    <apex:pageBlockSection >
        <form id="MyForm" action="http://api2.transloadit.com/assemblies" enctype="multipart/form-data" method="POST">
            <input type="hidden" name="params" value='{"auth":{"key":"あなたのAPI KEY"},"template_id":"あなたのTemplate ID","redirect_url":"{!$CurrentPage.URL}"}'></input>
            <input type="file" name="my_file"></input>
            <input type="submit" value="Upload"></input>
        </form>
    </apex:pageBlockSection>
    <apex:pageBlockSection >
        <apex:outputpanel id="product_photo" rendered="{! !ISNULL(photo_url)}">
            <img height="200px" src="{!sugoidiscount__product__c.sugoidiscount__photo_url__c}" />
        </apex:outputpanel>
    </apex:pageBlockSection>
</apex:pageBlock>
</apex:page>

エンジョイ。

without comments

Written by 中嶋 一樹

10月 11th, 2012 at 11:58 am