Play FrameworkはJavaとScalaに対応したWebアプリケーションフレームワークです。軽量でMVCでRESTfulで、、、といった概要については公式ドキュメントをご確認いただくとして、今回はPlay Framework 2.2.0(JAVA)で動作する「WS(WebService)とOAuthライブラリを利用してOAuth1.0認証を行う」「APIを叩いて取得したJSONをTwitter BootStrapを使って表示する」の2点についてまとめました。

WS(WebService)とOAuthライブラリを利用してOAuth1.0認証を行う
WS(WebService)は非同期通信でPlayアプリから外部Webサービスを呼び出す際に利用するライブラリです。また、PlayframeworkはOAuth1.0のみをサポートしたOAuthライブラリが用意されており、今回は主にこの2つを使って実装します。
準備
- TwitterDevelopersから開発アプリの登録を行い、API KeyとAPI secretを取得しておく
- ローカルで動作させるので、アプリ管理(Application Management)の「Callback URL」は「http://127.0.0.1:9000/auth」で設定しておく
- Play Framework+Eclipseでの開発環境を整えてプロジェクト作成しておく(Getting started参照)
- HTTPルーティングを以下のように設定しておく。conf/routesは、HTTPメソッド+URIパターン+呼び出されるアクションメソッドの設定。
conf/routes
# GETでhttp://127.0.0.1/にアクセスすると、controllers.Applicationクラスのindex()を呼び出す GET / controllers.Application.index() # GETでhttp://127.0.0.1/authにアクセスすると、controllers.Twitterクラスのauth()を呼び出す GET /auth controllers.Twitter.auth() # 静的リソースのパス指定 GET /assets/*file controllers.Assets.at(path="/public", file) |
まず、最初に実行するアクション:app/controllers/Application.java
public static Promise index() { //session(cookie)からToken情報を取得 Option sessionTokenPair = Twitter.getSessionTokenPair(); //Tokenがsessionに保存されているか。なければ、[0]の処理へ。 あれば[5]の処理へ if (sessionTokenPair.isDefined()) { //利用したいTwitter API String feedUrl= "https://api.twitter.com/1.1/statuses/user_timeline.json"; //WSの署名用クラス OAuthCalculator calc = new OAuthCalculator(Twitter.KEY, sessionTokenPair.get()); //[5]認証情報をsign()にセットして、APIにアクセスする return WS.url(feedUrl). sign(calc). get(). map(new Function<Response, Result>() { //レスポンスから取得した情報をブラウザに表示 public Result apply(Response response) {if(response.getStatus() == 200) {//正常レスポンスを受け取ったらJSONを表示return ok(result.asJson());} else{//ステータスコード200以外の場合は、エラーとして表示return badRequest("error:"+response.getStatus());}}})});} //[0]OAuth認証ページ (http://127.0.0.1/auth) にリダイレクト return Promise.promise(new Function0() {@Overridepublic Result apply() throws Throwable {return redirect(routes.Twitter.auth());}});} |
次に、リダイレクト先のアクション:app/controllers/Twitter.java
//発行されたKEYとSECRET
private static final String CONSUMER_KEY = “”;
private static final String CONSUMER_SECRET = “”;
//上記2つをペアとする
static final ConsumerKey KEY = new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET);
//プロバイダを識別する為のサービス情報
private static final ServiceInfo SERVICE_INFO = new ServiceInfo(
“https://api.twitter.com/oauth/request_token”,
“https://api.twitter.com/oauth/access_token”,
“https://api.twitter.com/oauth/authorize”,
KEY);
private static final OAuth PROVIDER = new OAuth(SERVICE_INFO);
public static Result auth() {
//oauth_verifierの有無を確認。なければ、[1]の処理へ。あれば[3]の処理へ
String verifier = request().getQueryString(“oauth_verifier”);
if (Strings.isNullOrEmpty(verifier)) {
//[1]RequestToken取得
String url = routes.Twitter.auth().absoluteURL(request());
RequestToken retrieveRequestToken = PROVIDER.retrieveRequestToken(url);
saveSessionTokenPair(retrieveRequestToken);
//[2]Twitterの認証画面にリダイレクト->[3]へ
return redirect(PROVIDER.redirectUrl(retrieveRequestToken.token));
} else {
//[3]CallbackURLにリダイレクトされた後、AccessToken取得
RequestToken requestToken = getSessionTokenPair().get();
RequestToken retrieveAccessToken = PROVIDER.retrieveAccessToken(requestToken, verifier);
saveSessionTokenPair(retrieveAccessToken);
//[4]Indexページ(http://127.0.0.1/)にリダイレクト
return redirect(routes.Application.index());
}
}
//session(cookie)にTokenを保存
private static void saveSessionTokenPair(RequestToken requestToken) {
session(“token”, requestToken.token);
session(“secret”, requestToken.secret);
}
//sessionに保存されたTokenを渡す
static Option getSessionTokenPair() {
if(session().containsKey(“token”)) {
return Option.Some(new RequestToken(session(“token”), session(“secret”)));
}
return Option.None();
参考:JavaOAuth(2.3-SNAPSHOT)
参考:OAuth Core 1.0
[play run]コマンドで実行して127.0.0.1:9000にアクセスすると、 user_timelineのJSONがそのままブラウザ上にレンダリングされます。

APIを叩いて取得したJSONをTwitter BootStrapを使って表示する
先程は取得したJSONをそのまま表示しましたが、もう少しデータを加工してからブラウザに表示したいと思います。Play frameworkにはEbean(O/Rマッピング)とH2データベースが同梱されいるので、これらを使って取得したTweetデータをDBに保存しながら、その情報をBootstrapを使って表示します。
EbeanとH2データベースを利用する準備
conf/application.confで下記を設定
#ドライバの設定
db.default.driver=org.h2.Driver
db.default.url=”jdbc:h2:mem:play”
models以下をebeanのエンティティクラスとして扱う
ebean.default=”models.*”
Entityクラスの作成
app/models/Tweet.java
//クラスがエンティティであることを示すEntityアノテーション
@Entity
public class Tweet extends Model {
@Id
public Long id;
@Required
public String screenName;
public String text;
public String profileImageUrl;
//Fiderクラスは全件検索や条件検索のメソッドが用意されている
public static Finder<Long, Tweet> find = new Finder<Long, Tweet>(
Long.class, Tweet.class
);
}
app/controllers/Application.javaを修正
public static Promise index() {
・・・
//下記に修正
//return ok(result.asJson());
createEntity(response.asJson());
return ok(views.html.index.render(Tweet.find.all()));
・・・
}
//取得したTweetをDBに保存
private static void createEntity(JsonNode rootNode) {
JsonNode current;
for (int i = 0; (current = rootNode.get(i)) != null; i++) {
Tweet tweet = new Tweet();
tweet.id = current.findPath(“id”).asLong();
tweet.text = current.findPath(“text”).textValue();
tweet.screenName = current.findPath(“screen_name”).textValue();
tweet.profileImageUrl = current.findPath(“profile_image_url”).textValue();
tweet.save();
}
}
ScalaでView Templateの設定(Bootstrap)
app/views/index.scala.htmlを修正
@**************************************
Controllerから渡されるの値*************************************@@
(tweets:List[Tweet])
@************************************** main.scala.htmlに渡す値
(titleの文字列と、HTML)*************************************
@@main("Test to Play Twitter"){<divclass="container"><divclass="page-header">
<h1> @tweets.size() Tweet(s)
</h1>
</div>
@for(tweet <- tweets){<divclass="media">
<aclass="pull-left"href="#">
<imgclass="media-object"src="@tweet.profileImageUrl"alt=""/>
</a><divclass="media-body">
<h4class="media-heading">@tweet.screenName
(@tweet.id)
</h4>
@tweet.text
</div>
</div>}
</div>}
app/views/main.scala.htmlにbootstrap.cssのパス追加
@************************************** index.scala.htmlから渡されるの値 *************************************@@ (title: String)(content: Html = null) <!DOCTYPE html> <head> <title>@title</title> ・・・ @************************************** BootstrapのCSSファイルを public/stylesheets以下に配置* routes.Assetsはconf/ routeファイルで設定済*************************************@ <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/bootstrap.css")">・・・</head> <body> @content </body> |
[play run]コマンドで実行して127.0.0.1:9000にアクセスすると、 BootstrapのMedia objectを利用した表示が確認できます。
