読者です 読者をやめる 読者になる 読者になる

astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

Play Framework 2.5でPostリクエストを処理してみる

Play Framework Scala Framework

https://www.playframework.com/assets/images/logos/play_full_color.png

アスタミューゼ 開発部のYanagitaです。

今回は前回執筆したPlay Frameworkの続きで、 Play Frameworkを使用してPost送信したデータを受け取るところを書きます。

事前準備

Play Frameworkの実行環境の設定がまだの方はこちらを参照

Postデータを受け取って表示する

まず、リクエストで受け取ったデータを格納するためのFormクラスとそのFormクラスにリクエストデータを格納するためのルールを記述します。

格納するためのFormクラス
/sample-app/app/forms/RequestForm.scala

import play.api.data._
import play.api.data.Forms._

case class RequestForm(
                      name: String, // 名前
                      sex: String, // 性別
                      birthday: Date // 性別
                      height: Int, // 身長
                      bloodType: String // 血液型
                    )

リクエストデータを上のFormクラスに格納するルール
今回はサンプルのためControllerクラス内にルールを記述します。
他のリクエスト(Controllerクラス)でも使用する場合はルールを切り出してください。 /sample-app/app/controllers/SampleController.scala

package controllers

import javax.inject.Inject

import forms.RequestData
import play.api.data.Form
import play.api.data.Forms._
import play.api.mvc._
import play.api.i18n.Messages.Implicits._
import play.api.Play._

class SampleController @Inject() extends Controller {
 // ここからが格納ルール
 val form = Form(
   mapping(
     "name" -> text,
     "sex" -> text,
     "birthday" -> date,
     "height" -> number,
     "bloodType" -> text
   )(RequestData.apply)(RequestData.unapply)
 )
 // ここまでが格納ルール
}

格納ルールの定義は、リクエストのパラメータ名とplay.api.data.Forms配下の型をマッピングしていきます。
以下はマッピングの組わせ

*Form内の型 *マッピング
scala.String play.api.data.Forms.text
scala.Int play.api.data.Forms.number
scala.Long play.api.data.Forms.longNumber
java.util.Date play.api.data.Forms.date
java.sql.Date play.api.data.Forms.sqlDate
org.joda.time.DateTime play.api.data.Forms.jodaDate
org.joda.time.LocalDate play.api.data.Forms.jodaLocalDate
scala.String play.api.data.Forms.email
scala.Boolean play.api.data.Forms.boolean
scala.Boolean play.api.data.Forms.checked
scala.Option play.api.data.Forms.optional

次に、入力ページと結果ページを表示するActionを上のControllerクラスに追記します。
前回はOkメソッドでただの文字列を返却するだけでしたが、今回はHTMLを返却したいのでHTMLを記述するテンプレートを指定します。
指定の際、テンプレート内で動的に変わるデータを扱う場合はテンプレートの引数に設定してます。
今回はリクエストデータをそのまま表示するため、Formクラスを設定します。
/sample-app/app/controllers/SampleController.scala

  // 入力ページを表示するAction
  def input = Action {
    Ok(views.html.sample.input(form))
  }
  // 結果ページを表示するAction
  def result = Action {
    Ok(views.html.sample.input(form.get))
  }

※ この時点ではテンプレートが未作成のためIDEだとエラーとなります。

次に、テンプレートを作成します。
テンプレートは"/プロジェクトディレクトリ/app/views"配下に配置し、拡張子は".scala.html"となります。
入力ページのテンプレート
/sample-app/app/views/sample/input.scala.html

@import helper._
@import forms.RequestForm
@(requestForm: Form[RequestForm])(implicit messages: Messages)
<!DOCTYPE html>
<html>
   <head>
       <title>Sample page.</title>
   </head>
   <body>
       <h2>Sample page(input).</h2>
       <hr>
       Sample form.
       @form(action = routes.SampleController.result()) {
           <!-- name -->
           @inputText(requestForm("name"))
           <!-- sex -->
           @inputRadioGroup(
               requestForm("sex"),
               options = Seq("M"->"Male","F"->"Female"))
           <!--  birthday -->
           @inputDate(field = requestForm("birthday"))
           <!-- height -->
           @inputText(requestForm("height"))
           <!-- bloodType -->
           @select(
               field = requestForm("bloodType"),
               options = Seq(
                   "A" -> "A",
                   "B" -> "B",
                   "O" -> "O",
                   "AB" -> "AB"
               )
           )
           <input type="submit" >
       }
   </body>
</html>

結果ページのテンプレート
/sample-app/app/views/sample/result.scala.html

@import forms.RequestForm
@(requestForm: Form[RequestForm])(implicit messages: Me[f:id:astamuse:20160823234850p:plain]ssages)
<!DOCTYPE html>
<html>
    <head>
        <title>Sample page.</title>
    </head>
    <body>
        <h2>Sample page(result).</h2>
        <hr>
        result <br>
        <table border="1">
            <tr>
                <th>name</th><td>@(requestForm("name").value)</td>
            </tr>
            <tr>
                <th>sex</th><td>@(requestForm("sex").value)</td>
            </tr>
            <tr>
                <th>birthday</th><td>@(requestForm("birthday").value)</td>
            </tr>
            <tr>
                <th>height</th><td>@(requestForm("height").value)</td>
            </tr>
            <tr>
                <th>bloodType</th><td>>@(requestForm("bloodType").value)</td>
            </tr>
        </table>
    </body>
</html>

記述の内容は、JSPのPlay Framework版のようなもので、 表示に関するところはJSP同様にHTMLタグを使用して記述し、JSPのディレクティブやスクリプトレットに当たるものを"@〜〜"で記述していきます。
※ Play Frameworkのテンプレートでは、変数を参照したり、ロジックを書く場合は「@」を先頭についけるというルールがあります。
もう少し解説を入れると、

  • 入力ページの1行目〜2行目は、テンプレート内で必要なクラスをインポートしています。
    これは、JSPで言うところのpageタグのimportと同じ役割と果たしていて、Play Frameworkでは「@import クラスパス」で指定します。
  • 入力ページの3行目、メソッド作成時に引数を指定するのと一緒で、テンプレート内で使用するデータを引数として指定します。
    今回、Actionでテンプレートに値を渡す記述を行ったので、テンプレートではplay.api.data.Form[格納するためのFormクラス]を受け取る記述をしています。

また少し特殊なところで、Play FrameworkにはForm template helpersと呼ばれる機能がビルドインされています。
Form template helpersとは、テンプレート内でフォームや入力フィールドを自動生成してくれる機能で、 HTMLタグの自動生成のほか、エラーメッセージの出力などもしてれます。
今回は、Form template helpersの機能を使用して、Formタグ(@form)、テキストボックス(@inputText、@inputDate)、ラジオボタン(@inputRadioGroup)、セレクトボックス(@select)を表示するサンプルにしています。
サンプルで使用した以外には、

  • パスワード ・・・ @inputPassword
  • ファイル ・・・ @inputFile
  • テキストエリア ・・・ @textarea
  • チェックボックス ・・・ @checkbox

があります。
Form template helpersの細かい設定は別で執筆を予定しているのでここではこれ以上深くは触れません。

ちなみに、テンプレートファイルは一度Scalaコードに変換された後、classファイルとなります。
そのため、Actionから指定する場合は、テンプレートを配置したはパッケージとロジック上のパッケージが異なるので注意が必要です。

テンプレートファイルのパス → views/sample/input.scala.html
Action上で指定する場合 → views.html.sample.input
※ viewsパッケージの下にhtmlパッケージを入れます。

Formクラス、ページを表示するAction、ページのテンプレートができたところで、 routeファイルにURIとActionのひも付けを追記しブラウザで確認します。
/sample-app/conf/routes

# 入力ページを表示する
GET     /sample/input               controllers.SampleController.input
# 結果ページを表示する
POST  /sample/input                controllers.SampleController.result

ブラウザに表示される入力ページ
f:id:astamuse:20160823212323p:plain:h566

もしエラーが発生する場合は、テンプレートファイルの変換が終わっていない可能性があります。
一度、cleanを実施して、再度compileを実行してください。

activator clean
activator compile

当然ですが、ここまででは結果画面に移れても入力した内容は表示されません。
結果ページを表示するActionでリクエストをFormクラスにバインドする処理が抜けているからです。
最後にリクエストのデータをFormクラスにバインドする処理を追記します。
Formクラスへのバインド方法は、FormクラスのbindFromRequest#foldメソッドを使用し、 バインド結果毎に処理を記述します。
/sample-app/app/controllers/SampleController.scala

  // 結果ページを表示するAction
  def result = Action { implicit request => // リクエストオブジェクトを宣言
    form.bindFromRequest().fold(
      errorForm => { // バインドエラー = 入力エラーが発生した場合
        Ok(views.html.sample.input(errorForm)) // 入力画面を再表示します。
      },
      requestForm => { // バインド成功 = 入力エラーがない場合
        Ok(views.html.sample.result(form.fill(requestForm))) // 結果画面を表示します。
      }
    )
  }

前述の通り、バインド結果で実行される処理が別れます。
バインドに失敗した(入力エラーが発生した)場合は、一つ目の引数で渡した処理が実行され、 バインドに成功した(入力エラーが発生しない)場合は、二つ目の引数で渡した処理が実行されます。 この時、それぞれの処理で渡ってくる変数の型が異なるので注意が必要です。
バインドに失敗した場合は、 play.api.data.Form[格納するためのFormクラス]になります。これはエラーメッセージを含むために play.api.data.Formクラスでラップされています。 バインドに成功した場合は、格納するためのFormクラスとなります。

ブラウザに表示される結果ページ
f:id:astamuse:20160823234850p:plain:h336

Play FrameworkでのPost処理はいかがだったでしょうか?
コード量も少なく簡単だったと思います。
次回は初期値の設定と入力チェックについて執筆したいと思います。

最後に

アスタミューゼでは現在、エンジニア・デザイナーを募集中です。 興味のある方はぜひ 採用サイト からご応募ください。

そうだAsta4dでWebアプリケーションを作ろう(第2回)

Asta4D Java

定期外ですが、月1くらいで書いて連載を終わらせようとしているnkgwです(ルール的に問題なし)。

前回は静的なページを表示することでAsta4Dのプロジェクトを作って表示するところまでをやりました。
第2回目は静的なページだけではWebアプリケーションとしては不完全です。
そんなわけで動的ページを表示させれるようにします。

動的ページを作る手順

動的ページを実際に作りながら説明します。

プロパティファイル書き込み

URLルールと同じようにSnippetクラスを置くパッケージ名を書きます。
ついでにcache機能をoffにしたいので、cacheの設定も書き込む事にします。
cache設定については開発中はoffにしておかないと直してもすぐに反映してくれないので、開発環境ではoffがおすすめです!(忘れたこと数知れず)

cacheEnable=false
snippetResolver.searchPathList=com.astamuse.blog_sample.snippet

cacheの設定はcacheEnabletrue falseのどちらかを設定します。
設定してない時はtrue扱いされるらしいです。

Snippetの場所はsnippetResolver.searchPathListにパッケージ名を入れます。
書かなくてもよいのですが、Snippetを大量に書くようになった時に面倒になるので設定を追加した方が良いと思います。
複数のパッケージに分ける場合は一番上のパッケージまでを書くようにすればオッケーです。
com.astamuse.blog_sample.snippet.patent com.astamuse.blog_sample.snippet.keywordみたいな構成ならcom.astamuse.blog_sample.snippetまでという意味です。

HTMLテンプレート作成

HTMLがないと話になりませんので、元となるHTMLファイルを作成します。
今回はサンプルなので、簡単なHTMLファイルを用意しました。

<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<p class="text"></p>
</body>
</html>

今回はこのpタグにSnippetで何か書く事を目標にします。

HTMLテンプレートにSnippetを埋め込む

サーバーでレンダリングする際は、Snippetの概念的に分割したレンダリングをするべきとの考えなので、bodyタグ全体を一気にレンダリングさせずに必要な場所だけレンダリングするように印を埋め込みます。
埋め込み方については先に説明するのが難しいので、先にコードを見てから説明したいと思います。

<html>
<head>
</head>
<body>
<p afd:render="IndexSnippet:showRenderer" class="text"></p>
</body>
</html>
<html>
<head>
</head>
<body>
<afd:snippet render="IndexSnippet:showRenderer">
<p class="text"></p>
</afd:snippet>
</body>
</html>

埋め込み方的には大体この2パターンです。
afd:snippetタグで埋め込むか普通のhtmlタグ内に属性として埋め込むかですね。
必要な場所に埋め込むということで、両方とも今回対象となるpタグに対して効果がおよぶような記述としました。

埋め込む時のルールとしてはSnippetクラス名:メソッド名という形で書きます。
クラス名は省略不可で、プロパティファイルに記載したパッケージ名とここに書いた内容でクラス名が特定出来るようにしなければなりません。 なので、プロパティファイルにSnippetのベースパッケージを指定しない場合は以下のように書いてください。

render="com.astamuse.blog_sample.snippet.IndexSnippet:showRenderer"

上で面倒と書いたのは、com.astamuse.blog_sample.snippetの部分を毎回書くのは面倒ってことです。
本格的なWebアプリケーションになると沢山これを書くことになるので、さすがに毎回大量に書くのは思ったより骨です。
なんかしらの理由でパッケージ移動なんて起きた日には見るも無残なことになることうけあい。

メソッド名については省略可能ですが、省略してもあんまりよいことがないので個々で付けてください。

Snippetの実装

HTMLに書いたSnippetをjavaで書いていきます。 今回はIndexSnippetクラスをcom.astamuse.blog_sample.snippet配下に作り、showRendererメソッドで書き込む事としまたので、その通りに実装していきます。

package com.astamuse.blog_sample.snippet;

import com.astamuse.asta4d.render.Renderer;

public class IndexSnippet {

    public Renderer showRenderer() {
        Renderer renderer = Renderer.create();
        renderer.add(".text", "Snippetで書いたテキストです");
        return renderer;
    }
}

実装しました。
メソッドの戻り値はRendererクラスでここにDOM対してのレンダリング処理を入れ込みます。
第一引数にselectorを指定(指定の仕方はjqueryなんかと同じです)、第二引数にvalueを指定です。
他にも指定の仕方が色々ありますが(これは次回で説明)、基本形としてはこのような指定をします。

1つのRendererで複数個所レンダリングしたい場合は、次々とaddしていけばオッケーです。
ただ、何回か書いているように分割したレンダリングとするべきなので、ある程度の粒度で

起動

http://localhost:8080/に接続すると、指定したvalueが表示されていると思います。

補足

今回、class名でレンダリングしましたが、class名でレンダリングする場合はプレフィックスルールを決めると良いです。 せっかくHTMLとレンダリングロジックが分離されているのに、競合してしまうと意味がありません。

次回予告

次回はもう少しSnippetについて深堀していきます。

関連URL

第1回:環境構築して静的ページを表示するまで
第2回:Snippetを使って動的ページを作ろう(今ここ)
第3回:少し複雑なSnippet
第4回:Handlerの役割と使い方
第5回:Global Handlerとattribute
第6回:Form Flowを使おう

プロトタイピングツールでデザインの作業効率を上げる

デザイン 業務効率化 webデザイナー

アスタミューゼデザイン部のMatsumotoです。
ここ最近astamuse.comastaIDのスマホ最適化の取り組みに合わせて、プロトタイピングツールを実験的に使い始めました。 ツールを使い始めてからまだあまり月日が経っていませんが、とにかく便利!
ストレスなく今までのデザインプロセスが改善しそう!
ということで、今回はプロトタイピングツールを使う利点や、実際のサービス開発において、どう作業効率がUPしたのかについて紹介させていただきます。

 目次

プロトタイピングツール概要

そもそもプロトタイピングとは何?

プロトタイピング(Prototyping)とは、実働するモデル(プロトタイプ)を早期に製作する手法およびその過程を意味する。その目的は、設計を様々な観点から検証する、機能やアイデアを形にすることでユーザーから早めにフィードバックを得るなど、様々である。

プロトタイピング - Wikipediaより

Webデザインで使うプロトタイピングツールとは、Webやスマホサイト・アプリを設計する際、チームで共有しながら、コードなしで、デザイン画面の画像のみでプロトタイプを効率的に作れるWebサービスのことです。
年々多くの便利なツールが登場してきているので、現在知っているだけでもすごい数ありますが、その中でもデザイナーの評価が高くて、多数の企業が使っているツールを試験的に使ってみました。

ツールを使用するようになった経緯

冒頭でふれましたが、astamuse/astaIDでは、現在スマホ最適化を進めています。
モバイルでの実機確認を手軽にしたかったので、ツールを使用し始めました。
リリース当初のターゲットユーザー像は、オフィスで仕事時間中に使うことを前提としていましたが、現在はスマホ・タブレットの普及やユーザー層の変化もあり、段階的にいくつかのコンテンツのスマホ対応を進めています。

f:id:astamuse:20160809174727p:plain
現在制作中 / marvelの画面

ツールを使う目的

私が主にツールを使い始めた目的は、以下4つです。

  1. モバイルでの実機確認したい
  2. ワイヤーフレームや画面遷移・トランジションの確認をしたい
  3. ボタンタップ後の動きインタラクション検討したい
  4. デザイナー・エンジニア間での共有&認識の相違をなくしたい

f:id:astamuse:20160809182003p:plain
現在制作中 / Prottのプレゼン用画面 ※背景画像、端末設定が細かく設定できるのが楽しい

使ってみた3つのサービス比較

基本機能はほとんど同じです。

  • プロトタイピング
  • モバイルでの実機確認
  • デザインレビュー
  • 複数メンバーとのプロジェクト共有
  • Slackとの連携
  • コメント付与

ただ、それぞれのサービスごとに、わずかですが機能の違いはあります。(下記表まとめ参照)

サービス inVision
f:id:astamuse:20160809105559p:plain:w120
marvel
f:id:astamuse:20160809105603p:plain:w120
Prott
f:id:astamuse:20160809105607p:plain:w120
会社場所 ニューヨーク ロンドン 東京
主な利用企業 twitter
UBER
Linkedin
salesforce
Evernote
sony
ustwo
M&S
DigitasLBi
GA
TransferWise
DICE
Yahoo!Japan
DeNA
RECRUIT
cookpad
GREE
IDEO
同期 Dropbox
Googledrive
Slack
Basecamp
Dropbox
Googledrive
Slack
Basecamp
Dropbox(自動更新なし)
Slack
ワイヤーフレーム作成機能 なし あり(無料) あり(有料)
インポートファイル形式 JPEG
GIF
PNG
PSD
ai
Sketch
JPEG
GIF
PNG
PSD
PDF
Sketch
JPEG
GIF
PNG
PSD
Sketch
シェア URL
Email
SMS
Embed
URL
Email
SMS
Embed
URL
Email
Embed
料金(月額) 無料(FREE)
$15(Starter)
$25(Professional)
$99(Team)
応相談(Enterprize)
無料(FREE)
$15(Pro)
$19(Plus)
$45(Company)
応相談(Enterprize)
※年間契約20%OFF
無料(Free)
1,900円(Starter)
3,900円(Pro)
7,400円(Team)
応相談(Enterprize)
※年間契約10%OFF 
その他特徴 -バージョン管理機能
-画面単位での進捗管理機能
-ユーザーテスト機能
-無料版でプロジェクト2つまで作成可能
-ユーザーテスト機能
-プレゼン機能(背景画像、端末設定)が細かく設定可
-日本語対応

2016/08/17時点まとめ

どのツールもUIが美しくて、直感的に操作できて、各種ツールの使い方もほとんど同じなので学習コストも低く、ほんと使いやすい!
こんな素晴らしいツールを提供してくれるなんて、制作&開発者に感謝です。

私個人的には、marvelのUIが好きです。UIのアニメーションの動きの気持ちよさや、色使い、アイコン、イラスト等、ポップな感じが使っていてとても楽しいです。ただ、今後デザインメンバーが増えてプロジェクト数が増えていくと、inVisionが使いやすいかなと思っています。(バージョン管理や進捗管理機能など充実)
どのツールを有料プランに切り替えて使い続けるかは、もう少し様子みて検討(+他メンバー&上司と相談)しようかなと思います。

何が変わった?

使い始めてからあまり月日が経っていないので、まだ使いこなせていない感はありますが、改善しはじめている点はいくつかあります。

デザインに対してエンジニアからのフィードバックが増えた

ツールを使う目的の1つである「デザイナー・エンジニア間での共有&認識の相違をなくしたい」と言う事が、プロトタイプを作って共有することで、エンジニアからの意見をもらいやすくなり、デザインラフの段階から、そのフィードバックを反映しやすくなった。

デザインレビューの回数&時間が短くなった

今まで1画面づつデザインの確認をしていましたが、画面遷移する複数ページをすべてまとめてレビューしてもらえるようになったので、レビューの回数&時間が総合的に短くなった。

フィードバックからのデザイン修正、共有のフローが楽になった

下図で詳細を記載していますが、これが一番うれしい。
今まで、4ステップだったのが、1ステップになった。かなりの効率アップ!

f:id:astamuse:20160810162726p:plain

まとめ

色々使っていて楽しいプロトタイピングツールですが、今現在に限っては、スマホ化対応のためだけに使用しています。通常のwebサイトの開発&改善の際は、今まで通り上記で述べているようなフロー(プロトタイピングツールを使用しないフロー)で進めている状態です。 プロトタイピングツールと言っても、ただ単にデザインレビューやデザインチェックツールとして、メンバーからの意見を反映しやすかったりと重宝しそうなので、積極的に使って、より効率的にプロジェクトを進めていきたいです。

アスタミューゼではサービスをより良くしていくため、一緒に働いてくれるデザイナー・エンジニアを募集しています。ご応募おまちしております!

参考サイト

Copyright © astamuse company, ltd. all rights reserved.