質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • Java

    15831questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

poiにおいて、Excelダウンロード処理を関数内で実行すると、ダウンロード後のタブが自動で閉じられない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,771

tera1

score 72

PoiでExcelのダウンロードを行っているのですが、

以下のようにサーブレット側、サーブレットから呼び出される関数を作ると、
ダウンロード処理完了後に自動でタブが閉じられません。

protected void doDownload(HttpServletResponse response) {

        response.setContentType("application/octet-stream");
        String fileName = null;
        try {
            fileName = new String(getExcelFileName().getBytes("Windows-31J"), "ISO-8859-1");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        response.setHeader("Content-Disposition", "attachments; filename=\"" + fileName + "\"");
        response.setHeader("Cache-Control", "public");
        response.setHeader("Pragma", "public");

        try {
            OutputStream out = new BufferedOutputStream(response.getOutputStream());
            wb.write(out);
        } catch (IOException e) {
                              e.printstactrace();
        } finally {
            try {
                wb.close();
            } catch (IOException e) {
                              e.printstactrace();
            }
        }
    }
protected void doUpdateExcel(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

              --- エクセルを生成する処理 ---

              doDownload(); // ここで上記のエクセルダウンロードを呼び出すと、タブが自動で閉じられない

}

一方、関数を使わずに、関数の処理をそっくりそのまま、サーブレットで実行すれば、
タブは自動で閉じられます。

おそらく原因は、関数内で、wb.write(out)を行うと、この内部処理でreturnするような処理になっていると思うのですが、
関数でそれを実行すると、まだ、サーブレット側の処理がのこっていることになり、
一方、サーブレットでwb.write(out)とすれば、内部処理でreturn後、サーブレットがおわることになり、
タブが自動に閉じられるような挙動になっているのではと思っています。

同じコードをサーブレット単位で書くのは面倒なので、
関数内で実行したいですが、なにかよい方法はございませんでしょうか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • argius

    2016/06/14 00:02

    すみません、「wb.outを関数内でコードを組むと」とありますが、掲載いただいたコードには実際にダウンロードデータを出力する部分が書かれていないため、問題となる処理がどう書かれているのかが分かりません。できれば、「servlet側でwb.out」「wb.outを関数内で」の違いが分かるように記載していだたけないでしょうか。

    キャンセル

回答 1

checkベストアンサー

+1

記載されているコードが完全に動作するものでないので、推測になってしまいますが、
普通に書いていれば、特にメソッドに分けたところでタブが閉じないという現象は
発生しないと思います。
実際に書いてみて確認しています。

new XSSFWorkbook()の処理が登場していないので、
メソッドに分けたときとそうでないときでXSSFWorkbookの処理の仕方が
違っている疑いもありますが、実際に見てみないと分かりません。

あとは、エラーが発生した場合に動作が変わる可能性もあるかも知れません。
printStackTrace()の情報が何かログかコンソールに出ていませんか?

ブラウザーの種類やHTML側の処理にもよるかもしれません。
ChromeとFirefoxでaタグのtarget="_blank"にしてタブを開いてダウンロードさせてみましたが、
タブが閉じないというのは確認できませんでした。


(追記)

検証したコードです。

アプリケーションサーバーはTomcat8です。

// import省略

@WebServlet("/servlet1")
public final class Servlet1 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
        doUpdateExcel(req, response);
        System.out.println("end of doGet"); // ダウンロード後に出力される
    }

    protected void doDownload(HttpServletResponse response) throws IOException {
        response.setContentType("application/octet-stream");
        String fileName = null;
        try {
            fileName = new String(getExcelFileName().getBytes("Windows-31J"), "ISO-8859-1");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        response.setHeader("Content-Disposition", "attachments; filename=\"" + fileName + "\"");
        response.setHeader("Cache-Control", "public");
        response.setHeader("Pragma", "public");

        // どうやって作っているか分からないのでとりあえずローカルのファイルを開く
        Workbook wb = new XSSFWorkbook("../" + getExcelFileName());
        try {
            OutputStream out = new BufferedOutputStream(response.getOutputStream());
            wb.write(out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                wb.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    protected void doUpdateExcel(HttpServletRequest request, HttpServletResponse response) throws ServletException,
                                                                                          IOException {
        // --- エクセルを生成する処理 ---

        doDownload(response); // ここで上記のエクセルダウンロードを呼び出すと、タブが自動で閉じられない

    }

    private String getExcelFileName() {
        return "dltest.xlsx";
    }

}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/14 13:23

    お言葉を返すようですが、関数化してしまうと、wb.writeのリターンを関数で拾ってしまうのが、普通と思います。

    ちなみに、関数にして、タブが閉じたコードを記載いただいてもよいでしょうか。

    キャンセル

  • 2016/06/14 14:42

    回答欄に追記しました。

    キャンセル

  • 2016/06/14 17:42

    ご回答ありがとうございました。

    おかげ様で無事解決できました。

    原因は、new XSSFWorkbook()の際の引数をString型のパスに変更したところ、
    関数内でも動作するようになりました。

    具体的には以下のようにです。
    ```
    InputStream is = getServletContext().getResourceAsStream(getExcelFileName());
    wb = new XSSFWorkbook(is);
    ```

    ご提示いただいた以下に変更しまして、出力されました。
    ```
    Workbook wb = new XSSFWorkbook("../" + getExcelFileName());
    ```

    ご対応感謝致します。

    キャンセル

  • 2016/06/14 18:11

    "../"にしたのは記載が無かったためとりあえず書いたものなので、
    そのまま採用しない方が良いかも知れません。

    ファイルの相対位置が分かっていれば、
    元のgetServletContext().getResourceAsStreamでも取得は可能です。
    この場合はコンテキストルートからの相対位置になります。

    どこにExcelファイルがあるのか分からないのであれば、
    ファイルの位置については確認しておいたほうが良いと思います。
    下記のコードをどこでも良いですがnew XSSFWorkbookの前あたりにでも
    書いて実行すると分かります。

    System.out.println("カレントディレクトリー: " + new java.io.File("./").getAbsolutePath());

    相対パスにした場合、環境の違いによって、
    「テスト環境では上手く行くけれど、本番環境では上手く行かない」
    のようなことが起こる可能性があるので注意が必要です。
    (書き込み許可が無いかも知れない、など)

    キャンセル

  • 2016/06/15 13:36

    ご回答ありがとうございます。
    勉強になります。

    キャンセル

同じタグがついた質問を見る

  • Java

    15831questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • トップ
  • Javaに関する質問
  • poiにおいて、Excelダウンロード処理を関数内で実行すると、ダウンロード後のタブが自動で閉じられない