m-namikiの日記

おもしろき こともなき世を おもしろく

HttpComponentsでファイルダウンロード

ブラウザからファイルダウンロードを行うのはよくある話ですが、今回はクライアントプログラムからファイルのダウンロードを行う方法をメモしておきます。その前に、ファイルダウンロードを行うサーバ側の処理は以下のような感じです。SAStrutsならResponseUtil#download()が利用できるので簡単ですが、今回はSpring-MVCを使っているので自前実装です。

/**
 * 指定されたファイルをダウンロード処理を行います。
 * 
 * @param response
 *            HTTPレスポンス
 * @param file
 *            ダウンロードファイル
 */
protected void download(HttpServletResponse response, File file) {
    try {
        byte[] byteArray = FileUtils.readFileToByteArray(file);
        response.setContentType("application/octet-stream");
        response.setContentLength(byteArray.length);
        response.setHeader("Content-disposition", "attachment; filename=\""
                + file.getName() + "\"");
        FileCopyUtils.copy(byteArray, response.getOutputStream());
    } catch (IOException cause) {
        throw new IORuntimeException(cause);
    }
}

FileUtilsはorg.apache.commons.ioパッケージ、FileCopyUtilsはorg.springframework.utilパッケージに含まれるクラスです。
次に実際にダウンロードを行うクライアントプログラムです。JSONのリクエストを投げて、ファイルをダウンロードします。HTTP通信にはApacheのHttpComponentsを利用しています。

public static void main(String[] args) throws Exception {
    JsonRequest request = new JsonRequest();
    request.setId(1);

    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpPost httpRequest = new HttpPost(TARGET_URL);

    StringEntity se = new StringEntity(JSON.encode(request));
    httpRequest.setEntity(se);
    httpRequest.setHeader("Accept", "application/json");
    httpRequest
            .setHeader("Content-type", "application/json; charset=UTF-8");

    HttpResponse httpResponse = (HttpResponse) httpclient
            .execute(httpRequest);

    HttpEntity entity = httpResponse.getEntity();
    OutputStream out = null;
    try {
        if (null != entity) {
            Header[] header = httpResponse
                    .getHeaders("Content-disposition");
            HeaderElement[] elements = header[0].getElements();
            NameValuePair pair = elements[0]
                    .getParameterByName("filename");
            out = new FileOutputStream(new File(DOWNLOAD_DIR, pair
                    .getValue()));
            IOUtils.copy(entity.getContent(), out);
            out.flush();
        }
    } finally {
        IOUtils.closeQuietly(out);
    }
}

JsonRequestはプロパティを1つだけ持つPOJOです。エンコード部分はJSONICを利用しているので、実際のリクエストは以下のような感じとなります。

{“id”:1}

また、リクエストのHTTPヘッダに「Accept」がありますが、以前調査した時に、これを追加してやらないとSpring-MVC側でJSONリクエストとして認識してくれなかったので追加しています。どのクラスで指定してたかは失念。思い出したら追記します。