(Java) Play FrameWork入門! Twitter のつぶやき検索アプリを作ってみたよ
どうも!もっこりmokkoです。
日付も変わろうとしていますが、Hamee Advent Calendar 2016の10日目の記事です!
初アドカレにドキがムネムネなわけですが、最初書こうと思っていた内容(スクレイピングと置換)は自分自身納得ができなかったのでまた次回に。
というわけで、今日はScalaのフレームワークとして有名な「Play Framework」のJava版入門を1つ。
簡単なTwitterのエゴサアプリを作ってみました。
デモ
※herokuのFreeの使用時間超えて止まっちゃいました。(12月11日追記)
この記事から分かること
- PlayFrameWorkの導入方法
- 簡単なアプリケーションのつくりかた
- 開発環境 & 本番環境での動かし方
(組み込みのNetty と Tomacatの2手法を紹介)
Play FrameWorkとは
公式ドキュメントより引用
https://www.playframework.com/
Ruby on Rails感覚で扱えるJavaのフレームワーク。
Scala界ではかなり有名だそう。
導入方法
公式ページよりactivatorというツールをインストール。
▼こちらからどぞ
Typesafe Activator(https://www.lightbend.com/activator/download)
コマンドラインを通して、コマンドを叩けばすぐ使える。
▼ちょっとサボるけど、詳しくはこちらを参照
Installing - 2.4.x
プロジェクトを作成するコマンドはこれ。
$ activator new
対話式でアプリ名など色々聞かれるので答えると必要なファイルが生成される。
Browse the list of templates: http://lightbend.com/activator/templates Choose from these featured templates or enter a template name: 1) minimal-akka-java-seed 2) minimal-akka-scala-seed 3) minimal-java 4) minimal-scala 5) play-java 6) play-scala (hit tab to see a list of all templates)
簡単なアプリケーションを作ってみた
機能はtwitterでエゴサしてそれを引っ張ってくるだけ。
※Play Frameworkのバージョンは2.4.8を使用。現時点での最新バージョンは2.5.10。
▼画面はこんなの
コマンドでプロジェクトを作成すると既に Model 、View、Controllerのクラスが作成されている。
このMVCの仕様はjava初めての私でもとても分かりやすかった。
▼Modelクラスはこんな感じ。
package models; public class SearchWord { public String word; public String getWord() { return word; } public void setWord(String word) { this.word = word; } }
今回はPOSTされた文字列をtwitterでエゴサするだけなのでシンプルに。
DBに繋がないのでORMも使用しない。
Ebeanを使用した時はebeanのModelクラスを継承して使った。
▼そして、conf/routesにルーティングを書く。
#アプリのルーティングを設定するファイル #HTTPリクエスト URL 呼び出すメソッド名 の順に記載 GET / controllers.ApplicationController.index() POST /search controllers.ApplicationController.search() # 静的ファイルのルーティング viewの呼び出しに使用する GET /assets/*file controllers.Assets.at(path="/public", file)
こんな感じで、アクセスしたURLに応じて呼び出すControllerを指定する。
分かりやすい。
▼Controllerクラス
package controllers; import models.SearchWord; import play.data.Form; import play.mvc.Controller; import play.mvc.Result; import twitter4j.TwitterException; import utils.TwitterSearch; import java.util.List; import java.util.Map; public class ApplicationController extends Controller { /** POSTされた文字を元にtwitterでエゴサをかけるよ*/ public Result search() throws TwitterException { Map<String, String> postData = new Form(SearchWord.class).bindFromRequest().data(); List<twitter4j.Status> searchResult = TwitterSearch.searchTweet( postData.get("searchWord")) .getTweets(); return ok(views.html.listTweet.render(searchResult)); } /** viewを表示するだけだよ */ public Result index() { return ok(views.html.index.render()); } }
Resultクラスで受け取ってviewへレンダリング。
POSTされた値を受け取る時はFormクラスを使えばMAP型で受け取れる。
▼twitterのAPIを叩くライブラリはTwitter4Jを使わせて頂きます。
package utils; import play.Play; import twitter4j.*; import twitter4j.conf.ConfigurationBuilder; public class TwitterSearch { public static QueryResult searchTweet(String searchWord) throws TwitterException { ConfigurationBuilder configInfo = new ConfigurationBuilder(); //application.confからTwitterの設定を読み込むよ configInfo.setDebugEnabled(true) .setOAuthConsumerKey(Play.application().configuration().getString("twitter.authKey")) .setOAuthConsumerSecret(Play.application().configuration().getString("twitter.authSecret")) .setOAuthAccessToken(Play.application().configuration().getString("twitter.authToken")) .setOAuthAccessTokenSecret(Play.application().configuration().getString("twitter.authSecretToken")); TwitterFactory tf = new TwitterFactory(configInfo.build()); Twitter twitter = tf.getInstance(); Query query = new Query(); query.setQuery(searchWord); QueryResult result = twitter.search(query); return result; } }
twitterの認証に使う情報はconf/application.confという設定ファイルに外出し。
このapplication.confという設定ファイルは環境変数から読み込めるのでおすすめ。
#twitterの認証情報を環境変数から取得 twitter.authKey=${?AUTH_KEY} twitter.authSecret=${?AUTH_SECRET} twitter.authToken=${?AUTH_AUTHTOKEN} twitter.authSecretToken=${?AUTH_SECRET_TOKEN} #アプリの言語 play.i18n.langs = [ "ja" ]
▼他クラスでapplication.confの変数を呼ぶ時はこれ
(※Playのバージョンによって使うクラスが絶妙に違う。2.4はこれでいける)
Play.application().configuration().getString("twitter.authKey")
▼Viewクラス
@import b3.vertical.fieldConstructor @main("ツイッターくん") { @b3.form(routes.ApplicationController.search, 'class -> "form-group") { <div class="col-sm-offset-0 col-sm-6"> <label for="searchWord">#つぶやき検索</label> <input type="text" name="searchWord"> @b3.submit('class -> "btn btn-default"){ <span class="glyphicon glyphicon-globe"></span> 検索} </div> } }
Play Framewokのviewテンプレート。
ヘルパーでhtml生成はもちろん、素書きでもOKなので扱いやすい。
bootstrapにも対応しており、公式のPlay Bootstrapがあるのであまり手をかけず整ったページを作れる。
viewテンプレートの記法はScalaを使う。
@以降がScalaとして認識されてるのでせ、ループ処理もこのように書ける。
@(searchResult: List[twitter4j.Status]) @main("ツイッターくん") { @for(tweet <- searchResult) { <li>@tweet.getText()</li> } }
分かりづらいのが、@main()なるもの。
これは要するに変数で、viewの共通ファイルになっているmain.scala.htmlというファイルに渡すhtml要素を定義している。
▼main.scala.htmlはこんな感じ
最上部に@()で定義されているのが、このファイルに渡ってくる引数。
他のviewの@main("ツイッターくん"){ hogehoge }の"ツイッターくん"がmain.scala.htmlのtitleとして、そして{hogehoge}がhtmlとして渡されている。
@(title: String)(content: Html) <!DOCTYPE html> <html> <head> <title>@title</title> <link href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")"> <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")"> <script src="@routes.Assets.at("javascripts/jquery-1.9.0.min.js")" type="text/javascript"></script> </head> <body> <div class="page-header"> <a class="navbar-brand logo" href="/"> <img src="@routes.Assets.at("images/medjed.png")" /> </a> <h1>Play Frameworkのテストだよ <br> <small>つぶやきを検索するよ</small> </h1> </div> @content </body> </html>
ささ、これだけでつぶやき取得アプリが完成!
テストと入力すると...
つぶやきを取得する。
デプロイしてみる
組み込みサーバーで動かすのはactivatorのコマンドで
$ activator start
application.confでsecret key(クライアントセッションの暗号化に使う)を指定していない場合はstartの引数に
$activator start -Dapplication.secret=abcdefghijk
だけでOK。
▼組み込みサーバーでデプロイ時のコマンドについて。こちら参照
Production - 2.4.x
Tomcatでデプロイする場合はwarファイルを作成する必要があるので、 play2warというプラグインを入れてコマンド1つでサクッと。
project/plugin.sbtに
addSbtPlugin("com.github.play2war" % "play2-war-plugin" % "1.4-beta1")
と build.sbtに
import com.github.play2war.plugin._ libraryDependencies ++= Seq( cache, jdbc, "mysql" % "mysql-connector-java" % "5.1.40", "com.adrianhurt" %% "play-bootstrap" % "1.1-P24-B3", "org.twitter4j" % "twitter4j-core" % "4.0.5" )
このように依存関係を追加すればコマンドからwarファイルを作成できる。
コマンドは
$activator war
使っているplay frameworkのバージョンによってバージョンの指定が異なるので注意! 2016年12月時点で2.5以降は非対応。
後はこのwarファイルをTomcat直下のwebapps内に置いてTomcatを立ち上げればデプロイ完了。
使ってみた感想
java初心者にとってとっつきやすかった。
ハマりどころも多いが嫌いじゃないし、むしろ好きかも。
PS.
▼ライブラリ探しはmaven repositoryでどうぞ。
https://mvnrepository.com/