javaのバッチプログラムから、外部のサーバにアクセスして、Getメソッドでzipファイルをダウンロードすることになったので、調査したことを書いておきます。
javaプログラムからHttpでサーバにアクセスして情報取得するライブラリはいくつかあるのですが、「Apache HttpComponents」プロジェクトの「HttpClient」が使いやすかったです。
以前は「The Commons HttpClient」プロジェクトだったようですが、それがこちらに置き換わったようですね。
このプロジェクトは
「java.net」等のパッケージを使って頑張ってプログラムを書くのもいいんだけど、もう少し利用しやすい形でHTTPをハンドリングするアプリから利用できないか
という理念に基づいて運営されていて、通常のGET、POSTはもちろん、proxy経由でのWebアクセスや、BASIC認証、SSLでのアクセスなど、一般的に利用する方法のほとんどを網羅しています。
今回、以下に簡単なサンプルを載せておきます。
サンプルソースの下の方に簡単に説明(ポイント)を付けておきますので、ぜひ読んでください。
まずは、ライブラリを用意する必要がありますね。
HttpClientパッケージを用意
Apache HttpComponentsプロジェクトのページから必要なjarをダウンロードしてきましょう。今回は、「httpcomponents-client-4.1.3-bin.zip」にしました。
次に、eclipseか何かでサンプルのプロジェクトを作成し、上記zipを解凍して出来るjar
・commons-codec-1.4.jar ・commons-logging-1.1.1.jar ・httpclient-4.1.3.jar ・httpclient-cache-4.1.3.jar ・httpcore-4.1.4.jar ・httpmime-4.1.3.jar
をプロジェクトのBuildPathに追加しておきます。
サンプルソースとポイント
では、サンプルのソースです。
package com.koji;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
public class HttpConnect {
private static final String PROXY_HOST = "xxxxxxxxx.co.jp";
private static final int PROXY_PORT = 8080;
private static final String TARGET_HOST = "xxxxxxxxxxx.jp";
private static final int TARGET_PORT = 80;
private static final String BASIC_USER= "sampleUser";
private static final String BASIC_PASS= "samplePassword";
private static final String GET_PARAM= "/xxxxxxxxx/xxxxxx?ID=yyyyy&2ID2=wwwww";
public final static void main(String[] args) throws Exception {
DefaultHttpClient httpclient = null;
HttpHost proxy = null;
HttpHost targetHost = null;
InputStream is = null;
FileOutputStream out = null;
HttpEntity entity = null;
try {
httpclient = new DefaultHttpClient();
proxy = new HttpHost(PROXY_HOST, PROXY_PORT, "http");
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
targetHost = new HttpHost(TARGET_HOST, TARGET_PORT, "http");
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new UsernamePasswordCredentials(BASIC_USER, BASIC_PASS));
AuthCache authCache = new BasicAuthCache();
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
HttpGet httpget = new HttpGet(GET_PARAM);
HttpResponse response = httpclient.execute(targetHost, httpget, localcontext);
entity = response.getEntity();
System.out.println("response=" + response.getAllHeaders());
// レスポンスヘッダーの取得(ファイルが無かった場合などは404)
System.out.println("StatusCode=" + response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() != 200 ){
System.out.println("StatusCode:" + response.getStatusLine().getStatusCode());
return;
}
Header[] headers = response.getAllHeaders();
for (Header header : headers) {
System.out.println(header.getName() + ": " + header.getValue());
}
// entityが取れなかった場合は、Connectionのことは心配しないでもOK
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
is = entity.getContent();
System.out.println("length: " + entity.getContentLength());
File file = new File("C:tttt.zip"); // 保存先
out = new FileOutputStream(file, false);
int b;
while((b = is.read()) != -1){
out.write(b);
}
out.close();
is.close();
EntityUtils.consume(entity);
//depriciated
entity.consumeContent();
}
System.out.println("ダウンロードしました。");
}catch (FileNotFoundException e) {
// Fileオブジェクト生成時の例外捕捉
e.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}finally {
httpclient.getConnectionManager().shutdown();
try {
if(out != null){
out.close();
}
if(is != null){
is.close();
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
proxy = new HttpHost(PROXY_HOST, PROXY_PORT, “http”);
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
この2行を追加するだけです。proxyを経由しない場合はコメントアウトしてください。
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new UsernamePasswordCredentials(BASIC_USER, BASIC_PASS));
を設定します。UsernamePasswordCredentialはCredentialsインタフェースを実装したクラスで、どの認証情報を使用するかで異なります。
BASIC認証の場合はこのクラスですが、他にNT認証用、Digest認証用などを利用できます。
AuthScopeは意図したサーバ以外に誤って認証情報を送信しないように範囲を指定します。気にしないのであれば「AuthScope.ANY」でも良いですが。。。
AuthCache authCache = new BasicAuthCache();
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
一度認証にクリアしてしまえば、同じコンテキスト内なら、再度認証する必要はなくなります。
はdepriciatedになっています。EntityUtilsクラスのconsumeメソッドを利用しましょう。