スポンサーサイト

-------- --:--:-- --

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

【GoogleAppEngine】BlobstoreServiceとImageService

2012-01-08 16:30:45 Sun

※ダイナミックに嘘を書いてしまっておりましたので修正しました。
修正箇所はBlobstoreへのファイルアップロード処理です。(2012/01/11 01:43:00 修正)
※※サーブレット内のデータをBlobstoreへ出力したいときはこちら。

■GoogleAppEngineでBlobstoreを使う



単にクライアントがバイナリファイル(多くの場合は画像ファイル)をアップロードして、
GAE側ではリクエストを受け取りそのままBlobstoreサービスにリクエストを渡せば
バイナリデータはBlobstoreに格納されます。

※環境
JDK1.6.24
GAE SDK1.6.1
GAE API v1.0
ライブラリにslim3とVelocityとJsonicを利用

簡単に書くと次のようなコード。

1.サーバ側でBlobstoreServiceからファイルのアップロード先URLを取得

BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
String uploadUrl = service.createUploadUrl("/test/Upload"); // Blobstoreへのアップロード成功時のコールバックURL
requestScope('uploadUrl', uploadUrl);




2.クライアント側HTMLでformに1のアップロード先URLをformタグのaction属性に指定

<form action=${uploadUrl} method="POST" enctype="multipart/form-data">
<input type="file" name="myFile">
<input type="hidden" name="param1" value="value1">
<input type="submit" value="Submit">
</form>


アップロード処理はこれだけの記述で成功します。
BlobstoreへのファイルアップロードはサーブレットやCGIを介さずに直接行えるという点がメリットになります。

ただし、サーブレットやCGI内で作成したデータを出力するためには、ひと手間必要となります。

■リサイズ



Blobstoreに格納されている画像ファイルをリサイズして表示したい、
というときに使えるのがImageService.
一覧画面で画像サムネイルを表示するときとかに非常に便利。

実装は簡単。


private byte[] createImage(BlobKey blobKey, int width, int height){
ImagesService imagesService = ImagesServiceFactory.getImagesService();

Image oldImage = ImagesServiceFactory.makeImageFromBlob(blobKey);
Transform resize = ImagesServiceFactory.makeResize(width, height);

Image newImage = imagesService.applyTransform(resize, oldImage);

return newImage.getImageData();
}


ImageServiceを使用して上述の処理で得られるBlobkeyを使用してImageインスタンスを取得。(oldImage)
次にImagesServiceFactory.makeResize(width, height)でTransformインスタンスを取得。
最後にImageService#applyTransformでリサイズ後のImageインスタンスを取得。
あとは適当にレスポンスする。

サーブレットを使っているのならばimgタグのsrc属性で指定したサーブレット処理で次のようにすることでバイナリデータをレスポンスできる。

response.setContentType("image/jpeg");
ServletOutputStream os = response.getOutputStream();
os.write(createImage(blobKey, width, height));



■サンプル



適当に動作するサンプルを。
Viewを伴う処理はDataManagerControllerのみ。
あとはアップロード処理のUploadController、
オリジナル画像を返すFileServerController、
リサイズしたバイナリデータを返すGetResizeImageController.
画面はDataManager.vm

●DataManagerController

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

import com.google.appengine.api.blobstore.BlobInfo;
import com.google.appengine.api.blobstore.BlobInfoFactory;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

public class DataManagerController extends Controller {

@Override
public Navigation run() throws Exception {
BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
String uploadUrl = service.createUploadUrl("/test/Upload");
BlobInfoFactory factory = new BlobInfoFactory();
List blobs = new ArrayList();
Iterator ite = factory.queryBlobInfos();
while(ite.hasNext()){
blobs.add(ite.next());
}
requestScope("upload_url", uploadUrl);
requestScope("blobs", blobs);
return forward("DataManager.vm");
}
}


●UploadController

import java.util.Map;
import java.util.logging.Logger;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

public class UploadController extends Controller {

private BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
Logger logger = Logger.getLogger(this.getClass().getName());
@Override
public Navigation run() throws Exception {
Map blobs = service.getUploadedBlobs(request);
for(String fileTag : blobs.keySet()){
logger.info(String.format("uploaded: %s, key = %s", fileTag, blobs.get(fileTag).getKeyString()));
}
return redirect("/test/DataManager");
}
}


●FileServerController

import java.util.logging.Logger;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;

public class FileServerController extends Controller {

private BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
Logger logger = Logger.getLogger(this.getClass().getName());
@Override
public Navigation run() throws Exception {
BlobKey blobKey = new BlobKey(request.getParameter("blob-key"));
String delete = request.getParameter("delete");
if(delete != null && delete.equals("true")){
service.delete(blobKey);
return redirect("/test/DataManager");
} else {

// 以下はどちらでも画像データをレスポンスすることができます。
// BlobstoreServiceでレスポンスする方法
// service.serve(blobKey, response);
// return null;

// ImageServiceでレスポンス(リダイレクト)する方法
ImagesService imagesService = ImagesServiceFactory.getImagesService();
String url = imagesService.getServingUrl(blobKey);
return redirect(url);
}
}
}



●GetResizeImageController

import javax.servlet.ServletOutputStream;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.Transform;

public class GetResizeImageController extends Controller {

@Override
public Navigation run() throws Exception {
BlobKey blobKey = new BlobKey(request.getParameter("blob-key"));
int width = Integer.valueOf(request.getParameter("width"));
int height = Integer.valueOf(request.getParameter("height"));
super.response.setContentType("image/jpeg");
ServletOutputStream os = super.response.getOutputStream();
os.write(createThumb(blobKey, width, height));
return null;
}

private byte[] createThumb(BlobKey blobKey, int width, int height){
ImagesService imagesService = ImagesServiceFactory.getImagesService();

Image oldImage = ImagesServiceFactory.makeImageFromBlob(blobKey);
Transform resize = ImagesServiceFactory.makeResize(width, height);

Image newImage = imagesService.applyTransform(resize, oldImage);

return newImage.getImageData();
}

}


●DataMangaer.vm

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset=utf-8 />
<title>Test</title>
<script type="text/javascript" src="/common/js/jquery.js"></script>
<script type="text/javascript">
</script>
</head>
<body>
<span style="font-size: 200%"> Uploaded Blobs </span>
<table summary="" rules="all" cellpadding="5">
<tr align="center" bgcolor="lightgray">
<th width="100"></th>
<th width="200">ファイル名</th>
<th width="140">Content Type</th>
<th width="80">サイズ</th>
<th width="200">アップロード時刻</th>
<th width="50">削除</th>
</tr>
#foreach(${blob} in ${blobs})
<tr align="right">
<td><img src="/test/GetResizeImage?blob-key=${blob.getBlobKey().getKeyString()}&width=120&height=90" alt="thumbnail"></td>
<td><a href="/test/FileServer?blob-key=${blob.getBlobKey().getKeyString()}">${blob.filename}</a></td>
<td>${blob.contentType}</td>
<td>${blob.size}</td>
<td>${_datetimeFormat.format(${blob.creation})}</td>
<td><a href="/test/FileServer?blob-key=${blob.getBlobKey().getKeyString()}&delete=true">DEL</a></td>
</tr>
#end
</table>
<hr>
<form action="${upload_url}" method="POST" enctype="multipart/form-data">
<input type="file" name="myFile">
<input type="hidden" name="param1" value="value1">
<input type="submit" value="Submit">
</form>
<p><a href="/">トップに戻る</a></p>
</body>
</html>


スポンサーサイト

⇒comment

Secret

名言集
全記事(数)表示
全タイトルを表示
ブログ内検索
Loading
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。