GAE/Jのデータストアに入れた画像データを表示する

なんというか、ブログに乗せるのもみっともないのだが、小1時間ほど悩んでしまったので、メモとして残しておく。

先のログで、Struts1.3をつかって「GAE/Jのデータストアにあるバイナリーをダウンロード」してみた。
これでは「つまらない」し、「用途が限られている」ので、「データストアに入れた画像を表示しましょう」と思ったのが発端。習慣というか摺りこみというかは恐ろしい。「画像はファイルシステムにおいて、そこにリンクをする」という先入観がある。だが、GAE/Jでは(ファイルシステムへの書き出しが禁止されているので)、これはできない。ちなみに、昔懐かしいAppletも使えない仕様になっている。それで「さてさて」となってしまった。

あらら、imgのsrcにアクションを指定すればいいんだね」と気がつくまでに小一時間。先入観は怖い。だが、簡単にできることがわかってよかった。以下は、そうやって表示した画面。サンプルプログラムは、先のログから少しだけ変更して、2つのイメージを表示してみた。2つの画像ファイルのアップロードは、以前作成した「GAE/Jのデータストアにファイルをアップロードする」のサンプルプログラムで行う。


以下の作業は、GAE/JのプラグインがインストールされたEclipse3.4(Ganymede)で行った。Galileo版のプラグインが出ているので早く移行しなくちゃ。

プロジェクトの作成

ファイルダウンロードのサンプルを少しだけ変更するので、前回のプロジェクトをコピーして新規にプロジェクト作成をする。

Actionクラスの変更

リクエストパラメータとして、id(整数)を受け取るように変更する。このidを、Pictureエンティティーのnumber(keyとも同値になっている)に対応させる。

PictureDownloadAction.java

package test;

import java.io.IOException;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.BaseAction;

import test.entities.Picture;

public class PictureDownloadAction extends BaseAction {

    @Override
    public ActionForward execute(
                ActionMapping mapping, 
                ActionForm form,
                HttpServletRequest req, 
                HttpServletResponse res) 
            throws IOException
    {
        
        String  strId   = req.getParameter("id");
        int     id      = Integer.parseInt(strId);
        
        PictureDao  pdao = new PictureDao();
        Picture     pic = pdao.getPictureById(id);
        String      contentType = pic.getContenttype();
        String      filename = pic.getName();
        int         filesize = pic.getSize();
        
        res.setContentType(contentType); 
        res.setContentLength(filesize); 
        res.setHeader("Content-Disposition", "attachment;filename=" + filename);
        ServletOutputStream outputStream;
        outputStream = res.getOutputStream();
        outputStream.write(pic.getPicture().getBytes());
        outputStream.flush();

        return null;
    }
}

index.htmlの作成

表示用画面は以下。なんの「取り柄もない」サンプルだが、できることが示せれば目的は果たせる。

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>Test of Displaying Image</title>
  </head>

  <body>
    <h1>Test of Displaying Image</h1>
	
    <table border="1">
      <tr>
        <td><img src="/downloadPicture.do?id=1"/>
        <td><img src="/downloadPicture.do?id=2"/>
      </tr>
    </table>
  </body>
</html>

web.xmlの変更

welcome-fileを変更したので、war/WEB-INF/web.xmlのその部分を修正する(以下は変更点のみ)。

  <!-- The Usual Welcome File List -->
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>

テストとデプロイ

ローカルサーバーでテストをしたのち(このサンプルではqueryを使わないので、必ずしも必要ないが、すぐに忘れちゃうので習慣づけておく)、GAE/Jにデプロイする。
上でも述べたが、画像ファイルを抱え込んだ2つのPictureエンティティがデータ・ストアに存在することを仮定している。
それらをuploadした後、このサンプルを動かせば、イメージが表示される。