【過去Blogからの移行記事】Javaで他所様のURLを叩く処理をコマンドラインからサクッと試す手順
昨日、初めてconnpass経由でイベントに参加した。
対象イベントはこちら→ https://hfs.connpass.com/event/72340/ プログラミング勉強部屋
主催 : eLV(engineer's Learning・Vesper)
javascriptに明るい方に聞こうと思って持っていった自分の課題は前半で自己解決してしまったので、後半は人にちょっかい出して過ごしてしまった。
犠牲になった方ごめんなさい。
本日の記事の前フリ
そうして私のちょっかいの犠牲となった方が抱えていた課題は
だいたい次のようなものだった。
- NetBeansを使って、Webベースで動作するJavaのプログラムを書く。
- そのプログラムの提供する画面にある検索窓への入力で、Yahoo!ショッピングのAPIから検索結果を持ってきて表示する。
暇を持て余して聞き耳を立てていると、NetBeansで書いたJavaのコードは glassfish がWebサーバとして処理する環境であるもよう。
首を突っ込んでみると、HTTPリクエストを送る役割を担うクラスに doRequestメソッドの処理内容をどう実装したら良いのか、という段階であった。
課題によって試されていることは「他所のAPIから決まったフォーマットのデータを得て、うまく処理して表示できるかどうか」ということなのだが、Javaというものに不慣れであることから、HTTPクライアントライブラリとはなんぞやとか、書いたコードがエラーとなった時や画面遷移がうまくいかない時のトラブルシュート等に苦心していて、肝心のコーディングに注力できずにいる状況だった。
こういう時、多少Javaをかじったことがあると、
やりようとしてはAPIに対する送受信処理だけを切り出して次のような手段で簡易に試すことができるということを思いつく。
-
mainメソッドのみの Hello!worldプログラムをひとまず用意する。
-
HTTPリクエストの処理をするためのライブラリをネットから持ってくる。
-
そのライブラリを使って「HTTPリクエスト送信をさせてレスポンスのHTMLを標準出力へ吐く」というコードを、上記で用意したmainメソッドのみのプログラムに書いていく。
-
コマンドライン実行環境から上記のコードをコンパイルして、コマンドライン上から実行して、結果を見る。
勉強部屋イベントを終えて家に帰った後、せっかくなので上記を実践してみたので、
イベントレポート替わりに手順を公開することにした。
本題:実践した手順
※以下の記事は、Javaを実行する環境のセットアップは済んでいる前提で書いています。
1. まずは mainメソッドのみの Hello!Worldプログラム。
例えばこんなん。
Hoge.java
public class Hoge {
public static void main(String[] args) {
System.out.println("Hello, world.");
}
}
この状態でいっぺんコマンドラインからコンパイル・実行してみる。
※WindwosならコマンドプロンプトやPowerShell、Macならターミナルなどから。
$ javac Hoge.java
$ java Hoge
Hello, world.
$
「Hello, world.」と表示されてプロンプトが返ってくればここまでOK。
2. 次にHTTPクライアントライブラリをネットから取得。
ここらあたりを参考に。
正直、お試しのコードの書き方とか全部上記の記事だけで十分説明されきっています。
が、今回の私の記事の主題は「コマンドラインからサクッと試す」なので、その観点から説明を続けます。
https://hc.apache.org/downloads.cgi から、
使いたいバイナリファイルのアーカイブを取得します。
そして上述の Hoge.java の同階層に lib/ ディレクトリを作って、
取得したアーカイブファイルを展開して中身を放り込み、
次のようなツリー構成にします。
javaTest/
|--Hoge.class
|--Hoge.java
|--lib
|--commons-codec-1.9.jar
|--commons-logging-1.2.jar
|--httpclient-4.5.3.jar
|--httpclient-cache-4.5.3.jar
|--httpcore-4.4.6.jar
|--httpmime-4.5.3.jar
この説明では、上述したコンテンツをすべてとあるパスに作った javaTest/ という名のディレクトリに放り込んで、コマンドライン実行環境のカレントディレクトリを javaTest/ へ cd しています。
3. Hello!Worldにコードを追加
上述の参考記事に倣いつつURLだけ変えて、Hoge.java を次のように書き換えます。
※ここに直書きしてあるリクエスト先URLは私の管理下にあるサイトです。
Hoge.java
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class Hoge {
public static void main(String[] args) throws Exception
{
// System.out.println("Hello, world.");
String url = "http://www.chimdon.com/hoge.php";
try {
CloseableHttpClient client = HttpClients.createDefault();
HttpGet get = new HttpGet( url );
CloseableHttpResponse response = client.execute( get );
int sc = response.getStatusLine().getStatusCode(); //. 200 の想定
HttpEntity entity = response.getEntity();
String html = EntityUtils.toString( entity, "UTF-8" );
//. 取得結果をコンソールへ
System.out.println( html );
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
4. コマンドラインでコンパイル・実行
今日の本題中の本題です。
コマンドラインから上述したツリーのように配置されたライブラリを取り込んでコンパイルするには、javac コマンドに -cpオプションを付けてクラスパスを指定しなければなりません。
Java6あたりからワイルドカード指定ができるようになったようなので、最近のJavaを使っていれば次のようにして6つの.jarファイルを取り込みコンパイルできます。
$ javac -cp 'lib/*' Hoge.java
$
これでもコンパイルは通るのですが、
実はこのクラスパス指定だと java に実行させる時に次のようなエラーが起きます。
(環境によっては起きないかもしれない)
$ java -cp 'lib/*' Hoge
エラー: メイン・クラスHogeが見つからなかったかロードできませんでした
このエラーを回避するには、
クラスパス指定時にカレントディレクトリを含めると良いようです。
※下記記述中の「'.:lib/*'」のことなのですが、Windows環境の場合、左記表記ではパスのセパレータが「:」となっているところを「;」に置き換える必要があります)
$ javac -cp '.:lib/*' Hoge.java
$ java -cp '.:./lib/*' Hoge
<!DOCTYPE html><html>
<head>
<meta charset=utf-8>
<title>hoge</title>
</head>
<body>
hogeTest
</body>
</html>
$
まとめ
こうして、
コマンドラインからのコンパイルおよび実行時に任意の.jarファイル等のライブラリを取り込むように指定して、javaの単体クラスの処理を試行することができました。
「フレームワークの作法の内部でコーディング中のクラスや処理がどうもうまく動かないんだけど、フレームワークの使い方が間違ってるのか自分のコードが間違ってるのか区別がつかない」というような時は、コーディング中の処理に必要なライブラリだけちょろっと取り出して単体クラスで適当に動かしてみるのも、一つの確認手段です。
本日の記事は以上になります。
※ホントは、上記Javaプログラムのリクエスト先をPHPにしたのには目論見があって、
GETクエリによって返すコンテンツを変えたりして「APIを叩いて結果を処理する」という課題にも応える内容にしようかと思っていましたが、
ちょっと手間なので今回はこれで終わりにします。
Discussion