2011年8月9日火曜日

GAE 画像データのアップロード2 FileUpload編 (圧縮必要ですけど・・)

GAE 画像データのアップロード1 Blobstore編では、結局課金する必要があったため他の方法をしらべた。

どうやら昔からあるjakartaのcommonで提供されているFileUploadを使う方法が一般的みたいなのでそれを実装。これなら昔strutsやってた時にやったことあり。


以下のサイトがほぼやりたいことだったので、そのサイトの内容をほぼそのまま実装。


[Java][Google App EngineGAEで作るサムネイル画像作成サービス



うーむ、やっぱりこの方法しかないか、、とおもったけどそういやslim3どうなんだ!?とおもって調べたら標準でサポートしていたは、はっはっは。。

やっぱslim3使うか。。

GAE 画像データのアップロード1 Blobstore編 (お金かかりますけど・・)

GAE(Google App Engine)で画像ファイルをアップロードできないか!?ということでいろいろ調べたことを記載。

GAEではデータ保存用にBlob(Binary Large Object)という型を推奨している。
さらにアップロードようにgae-sdk-1.3 から BlobStoreというBlob専用のデータストアーが使用可能。
これは通常のBigtableで使用されるDataStoreとは別もののよう。

ちなみにサイズ制限は以下のよう。

  • Blob      1M
  • Blobstore  2G
画像データなので大きいほうがいいでしょう、ということでBlobstoreをつかったアップロードについて記載。


方法

以下のGoogleサイト参照。

流れは以下
  1. ファイルアップロード処理記載(BlobstoreServiceFactory使用)
  2. サーバ側でのファイルデータ取得処理

■ファイルアップロード処理記載(BlobstoreServiceFactory使用)
ファイルをアップロードする処理のポイント

  • BlobstoreServiceFactoryでblobstore用のURL生成
  • アップロードformの属性にenctype="multipart/form-data"指定
まずはBlobStoreはDataStoreとは別管理のデータベース、と捉えると当然その保存先のURLを取得する必要がある訳で、そういう意味でURLを生成する必要あり。

後はそのURLを指定してファイルアップロードに必要なmultipart属性を指定すればOK。

<%@ page import="com.google.appengine.api.blobstore.BlobstoreServiceFactory" %>
<%@ page import="com.google.appengine.api.blobstore.BlobstoreService" %>

  
<%
    BlobstoreService blobstoreService
         = BlobstoreServiceFactory.getBlobstoreService();
    String uploadUrl
         = blobstoreService.createUploadUrl("/upload");
%>
    

■サーバ側でのファイルデータ取得処理
サーバ側でのファイルデータ処理のポイント

  • BlobstoreServiceでrequestからBlobKey取得
  • BlobKeyを使ってresponseにserve
サーバ側の処理としては、requestデータから格納されたはずのBlobStoreにアクセスするためのBlobKeyを取得し、そのキーでを用いてBlobStoreに格納されたデータにアクセスする。
responseデータに画像を表示するにはBlobstoreServiceのserveというメソッドを使用すれば可能。

@SuppressWarnings("serial")
public class UploadServlet extends HttpServlet {
	private BlobstoreService blobstoreService
		= BlobstoreServiceFactory.getBlobstoreService();


	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {

		Map blobs	= blobstoreService.getUploadedBlobs(req);
		BlobKey blobKey = blobs.get("file1");

		if (blobKey == null) {
			resp.sendRedirect("/");
		} else {
			resp.sendRedirect("/get?blob-key=" + blobKey.getKeyString());
		}
	}

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {

		BlobKey blobKey = new BlobKey(req.getParameter("blob-key"));
		blobstoreService.serve(blobKey, resp);
	}
}



    以下はweb.xmlの抜粋
    	
    		UploadServlet
    		com.kekenzy.gae.test.UploadServlet
    	
    	
    		UploadServlet
    		/upload
    	
    	
    		GetServlet
    		com.kekenzy.gae.test.UploadServlet
    	
    	
    		GetServlet
    		/get
    	
    



    問題発生!!

    とりあえず、ローカルで確認し選択したファイルがアップロードされ表示されることは確認
    で、GAEにデプロイしたあといざアクセスすると、画面に以下のエラーが表示。。

    Uncaught exception from servlet
    com.google.apphosting.api.ApiProxy$FeatureNotEnabledException: The Blobstore API will be enabled for this application once billing has been enabled in the admin console.
    
    billingってことは課金!?ってので、一応検索するとやはり課金設定して「金はらえ」ってことみたい。。。
    なんてこった・・・
    まー確かに画像データをガンガン上げられればサーバ圧迫するから仕方ないか。。
    とりあえずお金かけない方式!でサービス作りたいのでBlobstore方式は断念だな。。

    GAE Bigtableの状態確認

    ローカル環境

    http://localhost:8888/_ah/admin



    クラウド環境

    googleにログインして

    https://appengine.google.com/

    からデプロイ先のプロジェクト選択しDataStore Viewerを選択

    GAE Bigtable基礎


    GAEでデータベースを扱うにはBigtableしか使えない、ということでBigtableについてまとめてみた。

    説明
    Bigtableとは、Google App Engine(GAE)のデータストアーのこと。
    主な特徴としては以下。
    • RDB(リレーショナルデータベース)と異なるキーバリュー型データベース
    • 呼び出し方法には、SQL系とメソッド系の2種類あり
    • RDBほどトランザクション制御に長けてない

    またRDBとの主な違いは以下。
    • テーブル ⇒ カインド
    • レコード ⇒ エンティティ
    • データフィールド ⇒ プロパティ
    • 1レコードに「Key」「Value」の1組を格納
    • スキーマ定義は行わない(代わりにデータクラス定義を作成)
    実装
    説明はこのぐらいで次は実装について。
    Bigtableにアクセスするのに必要となるクラスファイルは以下の2つ。
    • データクラス定義ファイル
    • 永続化マネージャクラスファイル

    データクラス定義ファイル=RDBでいうTable定義。このクラスを作ることでスキーマ定義とかを行わなくてもBigtableにデータを格納することが可能(なんと便利!!)。
    また実際のデータをBigtableに格納したり取り出したりするのに永続化マネージャクラスを介して行うのでそれを作る。

    ■ データ定義ファイル記載ルール
    • データ項目には@Persistentアノテーションをつける
    • プライマリキーは@PrimaryKeyアノテーションをつける
    • コンストラクタでメンバ変数に値を設定する
    • データ項目にアクセッサを作成する
    @PersistenceCapable(identityType = IdentityType.APPLICATION)
    public class Greeting {
    	@PrimaryKey
    	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    	private Long id;
    	@Persistent
    	private String content;
    
    	public Greeting(String content){
    		this.content = content;
    	}
    
    	public String getContent() {
    		return content;
    	}
    
    	public void setContent(String content) {
    		this.content = content;
    	}
    	public Long getId() {
    		return id;
    	}
    }
    

    ■ 永続化マネージャ
    • PersistenceManagerクラスをインスタンス生成するためのFactoryクラスとして生成する
    • 一度だけでよいのでSingletoneで実装する
    public class PMF {
    	private static final PersistenceManagerFactory pmfInstance =
    		JDOHelper.getPersistenceManagerFactory("transactions-optional");
    
    	private PMF(){}
    	public static PersistenceManagerFactory get(){
    		return pmfInstance;
    	}
    }
    


    あとはこれらを使用するところの修正
    • データ定義ファイルインスタンス生成
    • 永続化マネージャファクトリでマネージャクラス生成
    • makePersistentで永続化実行
    • 永続化マネージャclose
    		String content = req.getParameter("content");
    
    		// データクラス生成
    		Greeting greeting = new Greeting(content);
    
    		PersistenceManager pm = PMF.get().getPersistenceManager();
    		try{
    			pm.makePersistent(greeting);
    
    		} finally {
    			pm.close();
    		}
    
    なれれば簡単!?
    今度は画像ファイルの扱いをやってみよ。