unhurried

コンピュータ関連ネタがほとんど、ときどき趣味も…

Bootstrap3 フォームレイアウト

Bootstrap3でフォームを作ろうとして結構はまってしまったので、 ポイントとサンプルコードをメモしておきます。

ポイント

  • 基本はlabel.control-labelとinput.form-controlをdiv.form-groupで囲む。
  • inputの幅は100%になるので、制限したい場合はstyleを指定する。
  • labelとinputを横並びにするには、labelとinputの親となるdivを用意し、col-xx-xを指定する。
  • 複数のinputを横並びにするには、inputの親となるdivを用意し、form-inlineを指定する。

サンプルコード

f:id:unhurried:20160215194708p:plain

   <form class="form-horizontal">
        <div class="form-group">
            <label class="control-label col-xs-2">aaa</label>
            <div class="col-xs-10">
                <input type="text" placeholder="aaa" class="form-control"  style="width:200px">
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-xs-2">bbb ccc</label>
            <div class="form-inline col-xs-10">
                <input type="text" placeholder="bbb" class="form-control"   style="width:200px;margin-right:10px;">
                <input type="text" placeholder="ccc" class="form-control"   style="width:200px">
            </div>
        </div>
        <div class="form-group">
            <div class="col-xs-offset-2 col-xs-10">
                <input type="submit" value="Submit" class="btn btn-primary">
            </div>
        </div>
    </form>

参考

AngularJS + Gulp の開発環境を作る

最近はGrantよりGulpの方が人気らしいので、試してみました。
最初は一からこつこつ作っていましたが、Yeomanにgeneratorがありました…。

構築手順(というほどのものでもないけれど…)

  • 最新のNode.jsを公式サイト(https://nodejs.org/)からダウンロードしてインストールする。
  • npmを最新版にアップデートする。
  npm install -g npm
  • generator-gulp-angularをインストールする。
    ※ 従来のgenerator-angular でもGulpが選択できるのですが、一部正常に動作しませんでした。
  npm install -g yo gulp bower
  npm install -g generator-gulp-angular
  • プロジェクトを作成する。
  yo gulp-angular

REST API テストツール

最近はREST APIを使うこと、作ることが多いので、テストに利用できるツールを調べてみました。

比較した機能

  • シナリオ登録
    • 複数のAPIを登録して連続で呼び出す機能
  • 変数定義
    • 変数(定数)を定義し、API呼び出しで利用する機能
  • レスポンス抽出
    • API呼び出し時のレスポンスから値を抜き出して以後の呼び出しで利用する機能
  • エクスポート
    • API呼び出し設定をファイル等にエクスポート/インポートする機能

一覧

名称 シナリオ登録 変数定義 レスポンス抽出 エクスポート
Advanced REST client × × × △※1
Apache Jmeter ※2
DHC × × ×
Insomnia REST Client × × ×
RESTClient × × ×
restclient-tool × × × ×
Postman

※1 全てのプロジェクト一括でのエクスポート/インポートのみできる
※2 Apache JMeterは本来負荷テスト用のツール

まとめ

別のAPIの結果を使って呼びだすといった複雑なAPIもあるため、シナリオ登録とレスポンス抽出機能は欲しいところです。
調べてみたところでは、動作確認のために手軽に使いたいのであれば、Postmanが使いやすく、良い感じです。
テスト自動化などゴリゴリ作り込むとすると、Apache JMeterの方がDB呼び出しなどもできて便利です。(もしくは、この手のGUIツールで管理しきれないくらい複雑なテストケースについては、何かしらのテストフレームワークを使ってテストプログラムを作成する方がよいかもしれません。)

MEANスタックでログイン機能を実装する

MEANスタックでCRUDアプリを実装するにて作成したTODOリストにログイン機能を追加しました。

github.com

API側の実装は Node.js OAuth 2.0 + JWT でご紹介した通りです。 クライアント側は、AngularJSでOAuth2 ROPCGに対応したライブラリを見つけられなかったので、ngResourceを使ってヘッダにアクセストークンをしているのみです。

Node.js OAuth 2.0 + JWT

Node.jsで実装したWeb APIにユーザー認証機能を追加するために使えそうなライブラリを探しました。
必要な機能はシンプルで2つのみです。

  • OAuth 2.0 Resource Owner Password Credentials Grantに対応する。
  • JWT形式のアクセストークンの発行・検証ができる。

使用したライブラリ

node-oauth20-providerのトークン発行機能をカスタマイズして、node-jsonwebtokenを利用してJWTを生成するようにすればOKです。

accessToken.js

var jwt = require('jsonwebtoken'), fs = require('fs');

module.exports.getToken = function(accessToken) {
    return accessToken.token;
};

module.exports.create = function(userId, clientId, scope, ttl, cb) {

    var private_key = fs.readFileSync('./resource/private_key.pem');
    var accessToken = {
        userId : userId,
        clientId : clientId,
        scope : scope,
        ttl : new Date().getTime() + ttl * 1000
    };
    var token = jwt.sign(accessToken, private_key);

    cb(null, token);
};

module.exports.fetchByToken = function(token, cb) {

    var publicKey = fs.readFileSync('./resource/public_key.pem');
    jwt.verify(token, publicKey, function(error, decoded) {
        if (error) {
            cb();

        } else {
            var accessToken = decoded;
            accessToken.token = token;
            cb(error, accessToken);
        }
    });
};

module.exports.checkTTL = function(accessToken) {
    return (accessToken.ttl > new Date().getTime());
};

感想

  • 既存のライブラリを組み合わせることで簡単に実装ができた。
  • node-oauth20-providerは発展途上という感じで、今回は使った範囲では下記の機能が欲しいところです。
    • ClientごとにRefresh Token発行するか切り替える機能。
    • Refresh Tokenをユーザーとクライアントの組み合わせに対して複数保持する機能。

スクラム実践入門

私の会社でもスクラム開発を導入したという話をちらほら聞くようになりました。なんとなくのイメージはあるのですが、具体的にどんなプロセスとなるのかを理解しようと、入門書を読んでみました。

スクラム実践入門 ── 成果を生み出すアジャイルな開発プロセス (WEB+DB PRESS plus)

スクラム実践入門 ── 成果を生み出すアジャイルな開発プロセス (WEB+DB PRESS plus)

本書ではスクラム開発のポイントとなる、役割(プロダクトオーナー、スクラムマスター、…)、イベント(スプリントプランニング、スプリントレビュー、…)、成果物(プロダクトバックログ、インクリメント、…)について、前提知識がなくても理解できるように説明されています。 また、スクラム開発で使えるテクニック(ユーザーストーリ、プランニングポーカー、…)や、実際にスクラムを導入したチームの実例も紹介されています。

感想

どんなプロジェクトにも要求変更は付き物だと思います。ただ変更をきちんと管理できるチームはあまりない気がします。 開発者目線で言えば、迫る納期に増えるタスク、終わりの見えない戦いにだんだんとメンバーが疲弊して、モチベーションも落ちていってしまうのです…。
スクラム開発は要求は変わるものだと割り切ってしまって、短い間隔で見直しを繰り返す、と変更に対する考え方が最近の開発事情に合っているのだと思います。
それから、要求であれ進捗であれ徹底的に見える化することも良いですね。だいたいは各人の裁量になってしまって、問題がわかったときにはもう手遅れ、となりがちですが、見える化開発プロセスに組み込んで半ば強制的にやってしまおうという訳です。

Play Framework

Overview

  • A Java/Scala web application framework which aims to improve the productivity (development speed) and flexibility (easiness of change).
  • Although Applications can be coded with both Java and Scala, templates must be written with Scala.
  • Its design is affected by Ruby on Rails such as Convention over Configuration or MVC.

How to Install

Frequently Used Commands

Command Description
activator new [app name] play-java Create a new project
run [port number] Run an application
compile Compile the source codes(Usually compile is done when accessing the application)
eclipse Covert the project to an Eclipse project

How to Import to Eclipse

  • Convert the project to an Eclipse project by using eclipse command.
  • Open Eclipse and select "Import" and import the project as a "Existing project".
  • Turn off the feature which automatically deletes import statements.
    • Turn off "Project property -> Java -> Editor -> Save Actions -> Organize imports"
  • Add a class folder for the view of Play framework.
    • Project Property -> Java Build Path -> Add Class Folder
    • Add target/target/scala-2.11/classes_managed
  • (Appendix) Resolve the dependency from Maven repository using SBT
    • SBT (Simple Build Tool) is a build tool which is recommended in Play Framework.
    • Look for necessary libraries in Maven repository.
    • Copy the text in the SBT tab, and paste it in build.scala.
    • Re-compile the project.
libraryDependencies ++= Seq(
  javaJdbc,
  ...,
  "com.nimbusds" % "oauth2-oidc-sdk" % "4.13"
)
$ clean
$ compile
$ eclipse with-source=true
# Refresh the Eclipse project

Create a view

  • Create a template (*.scala.html) in app/views directory. => After compiling a class named views.html.{view name} will be created.
  • Available Control Syntax
    • if / for / function / variable / import
  • Helper methods
    • @helper.form
  • Specify other endpoints as links or targets of forms.
    • @routes.{controller class name}.{method name}

DB access using Ebean (O/R mapper)

  • DB Connection Settings
db.default.driver = {JDBC Driver}
db.default.url = {URL starting with jdbc:}
db.default.driver = org.h2.Driver
# Change "mem" to "file" when we want to make the data persistent.
db.default.url = jdbc:h2:mem:play
  • Ebean class
    • Package name: models.{class name} (customizable)
    • Extends play.db.ebean.Model
    • Available annotations
Annotation Description
@Entity Specify to an Ebean class.
@Id Specify to a member which is a primary key.
@NotNull Specify to a member which uses a NotNull constraint.
@CreatedTimestamp Specify to a member which stores a created date and time.
@Version Specify to a member which stores a updated date and time.
  • Basic DB Operations
Operation Method
INSERT save()
UPDATE update()
DELETE delete()
  • Search
    • Use play.db.ebean.Finder
Method Description
all() Search whole the records.
byId(Long id) Search by a primary key.
where(String arg) Search with a condition.
  • Relations between tables 1:N (parent-child relationship)
@Entity public class Child extends Model {
  @Id public Long id;
  @ManyToOne
  @JoinColmunName(name=”parent_id”)
  public Parent parent;
  ...
}
@Entity publi class Parent extends Model {
  @Id public Long id;
  @OneToMany(cascade=CascadeType.ALL, mappedBy=”parent”)
  public List<Child> children = new ArrayList<Child>();
}
  • Transactioins: Use TxRunnable.
Ebean.execute(new TxRunnable() {
  // Write Ebean procedures in the transaction.
});

How to use a controller

  • Write a routing configration in conf/routes.
{HTTP Method} {Path} {Method}
# Simple example
GET /list controllers.Page.showList()
# Pass the Path parameter and the query parameters
GET /search/:id controllers.Page.search(id :Integer, name :String)
  • Methods in a Controller class
    • Create a method which returns play.mvc.Result.
    • A helper method is prepared in play.mvc.Results.
      • ok, redirect, badRequest, internalServerError, …

Session Scope and Flash Scope

  • Session Scope
    • Retained in a user session
    • Can store up to 4KB string
  • How it works
    • Stored in the client side using HTTP Cookie.
    • The values of the cookie are signed with the secret key. (The values will be invalidated.)
    • There is no expiration date for the session. (As long as the client break it.) -> Store a timestamp in the session and manage the expiration date.
  • Code example
# Save values into the session
session(“key”, “value”);
# Read values from the session
String value = session(“key”);
# Delete values from the session
session.remove(“key”);
# Delete the session
session().clear();
  • Flash Scope (The difference from the session)
    • The data will be retained until the next request.
    • The values of the cookie are not signed. (They may be changed by a user.) → 非Ajaxアプリケーションでのメッセージ(成功/失敗など)のやり取りに利用する。

Refer a conf file

  • an instance of application.conf can be gotten with Configration#root.
Configuration.root().getString("application.langs")

How to use Bootstrap