top / index / prev / next / target / source

2005-03-15 diary: シンプルなダウンロードサーブレットの雛形 , Jakarta POIのExcel書き出しの挙動不安定に苦しめられる

いがぴょんの日記 日記形式でつづる いがぴょんコラム ウェブページです。

old-v2

シンプルなダウンロードサーブレットの雛形 , Jakarta POIのExcel書き出しの挙動不安定に苦しめられる

シンプルな ダウンロードJava Servletの雛形を作りました , Jakarta POI の現行バージョンでは Excel書きだしの挙動が微妙なようです。

シンプルなダウンロードサーブレットの雛形

とってもシンプルなダウンロードサーブレットの雛形を作成しました。これをメモしておきます。 SimpleDownloadServlet.java

/*
 * すごく単純な Java Servletによるダウンロード
 * Copyright (C) 2005 いがぴょん
 */

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * すごく簡単な Java Servletによるダウンロード <br>
 * 参考: http://www.ietf.org/rfc/rfc2616.txt
 * 
 * @author t.iga
 * @version 2005.03.04
 */
public class SimpleDownloadServlet extends HttpServlet {
        public static final String HOME_DIRECTORY = "C:\\";

        /**
         * <code>ENCODING</code> HTMLで扱う文字コードを与えます。
         */
        public static final String ENCODING = "ISO-2022-JP";

        /**
         * HTMLのタイトル
         */
        public static final String HTML_TITLE = "ダウンロード中...";

        /**
         * Java Servletのエントリポイントです。
         * 
         * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest,
         *      javax.servlet.http.HttpServletResponse)
         */
        public final void service(final HttpServletRequest request,
                        final HttpServletResponse response) throws ServletException,
                        IOException {

                // JavaServletにおいて、responseから取得したwriter, outStreamはクローズしません。
                PrintWriter writer = null;
                OutputStream outStream = null;

                String filename = request.getParameter("filename");
                File fileCheck = new File(HOME_DIRECTORY + filename);

                if (filename == null) {
                        setResponseHeader(response, "noname.html", -1);
                        writer = response.getWriter();
                        writer.write("<HEAD><TITLE>" + HTML_TITLE + "</TITLE></HEAD>"
                                        + "<BODY><P>'filename'パラメータ指定を行ってください.</P></BODY>");
                } else if (fileCheck.exists() == false) {
                        setResponseHeader(response, "notfound.html", -1);
                        writer = response.getWriter();
                        writer.write("<HEAD><TITLE>" + HTML_TITLE + "</TITLE></HEAD>"
                                        + "<BODY><P>指定のファイル[" + fileCheck.getAbsolutePath()
                                        + "]が見つかりません</P></BODY>");
                } else if (fileCheck.isDirectory()) {
                        setResponseHeader(response, "notfound.html", -1);
                        writer = response.getWriter();
                        writer.write("<HEAD><TITLE>" + HTML_TITLE + "</TITLE></HEAD>"
                                        + "<BODY><P>ディレクトリ[" + fileCheck.getAbsolutePath()
                                        + "]が指定されていますが、このプログラムはファイルしかダウンロードできません.</P></BODY>");
                } else if (fileCheck.canRead() == false) {
                        setResponseHeader(response, "notfound.html", -1);
                        writer = response.getWriter();
                        writer.write("<HEAD><TITLE>" + HTML_TITLE + "</TITLE></HEAD>"
                                        + "<BODY><P>指定のファイル[" + fileCheck.getAbsolutePath()
                                        + "]は読み込みできません</P></BODY>");
                } else {
                        setResponseHeader(response, filename, (int) fileCheck.length());

                        // バッファリング無しで出力ストリームを取得します.
                        outStream = response.getOutputStream();

                        InputStream inStream = null;
                        try {
                                inStream = new BufferedInputStream(new FileInputStream(
                                                fileCheck));
                                byte[] byteBuf = new byte[8192];
                                for (;;) {
                                        int iRead = inStream.read(byteBuf, 0, byteBuf.length);
                                        if (iRead < 0) {
                                                break;
                                        }
                                        outStream.write(byteBuf, 0, iRead);
                                }
                        } finally {
                                if (inStream != null) {
                                        inStream.close();
                                }
                        }
                }
        }

        /**
         * 基本的なレスポンスヘッダー情報を付与します。
         * 
         * @param response
         *            レスポンスオブジェクトを与えます。
         * @param filename
         *            ファイル名
         * @param fileLength
         *            ファイルの長さ
         */
        private void setResponseHeader(final HttpServletResponse response,
                        String filename, final int fileLength) {
                if (filename.endsWith(".pdf")) {
                        // ブラウザに PDFと認識させます。
                        response.setContentType("application/pdf");
                } else if (filename.endsWith(".xls")) {
                        // Excelと認識させます。
                        response.setContentType("application/vnd.ms-excel");
                } else if (filename.endsWith(".xml")) {
                        // XMLと認識させます。
                        response.setContentType("text/xml");
                } else if (filename.endsWith(".html")) {
                        // htmlと認識させます。
                        response.setContentType("text/html; charset=" + ENCODING);
                        response.addHeader("charset", ENCODING);
                } else if (filename.endsWith(".txt")) {
                        // テキストと認識させます。
                        response.setContentType("text/plain");
                        response.addHeader("charset", ENCODING);
                } else {
                        // それ以外の場合はバイナリストリームとして送出します。
                        response.setContentType("application/octet-stream");
                }

                // TODO 試験的に埋め込み
                filename = filename.replaceAll("/", "");
                response.addHeader("Content-Disposition ", "attachment; filename=\""
                                + filename + "\"");
                System.out.println("ファイル名[" + filename + "]");

                // Accept-Rangesとしてnoneを表明する。
                // AdobeReader 7.0は これが無いと正常に動作しない。
                response.addHeader("Accept-Ranges", "none");

                if (fileLength > 0) {
                        // コンテンツの長さをセットします。
                        response.setContentLength(fileLength);
                }

                // キャッシュを無効化します。
                response.addHeader("Cache-Control", "no-cache");
                response.addHeader("Pragma", "no-cache");
                response.addHeader("Expires", "0");
        }
}

関連する日記

Jakarta POI (HSSF) のExcel書き出しの挙動に苦しめられる

Jakarta POI の現行バージョン (2.5.1) では Excel書きだしの挙動が微妙であることが 改めて良く分かりました。Excelシートに画像が貼り付いたものをいろいろ処理するのですが、処理している間に Excelでは開くことが出来ないファイルが出来上がってしまう場合がありました (T_T) Excelファイル形式の気持ちになって、画像データをクリップボードに一旦ため込んで Excelを再起動して 張り付けて、などを行ってうまくやると、Jakarta POIによる変更処理後でも Excelで開くことが出来る xlsデータファイルが作成可能な、そんな不思議な挙動に直面しました。Excelのファイルフォーマットって不思議な感じがあるようで、セルとか罫線とかも、ひとつのスタイルを複写してセルに貼り付けているような作りになっていて、POIを使うひとはその都合に合わせた利用手順に乗らないとまずいようです。特に画像データは 元ネタ+リンクの形式であるようなので、操作している過程で へんなことになるようです。…私の Jakarta POIを扱うスキルに問題がある可能性も 多分に ありますけれどもね。

とりあえず今後は、OpenOffice.org SDK の APIに突っ走っていく予定です。OpenOffice.org SDK の APIは とっつきがサイアクなのですが、まあ ちゃんと呼び出しさへすればちゃんと動くので、これはちょっと気合いを入れて OpenOffice.org SDK と真っ向勝負してみたいです。、、、まあ、時間があればの話ですが…。


この日記について