いろんなJava Webフレームワークで同じ画面を作ってみる(Ninja web framework編)

いろんなJava Webフレームワークで同じ画面を作ってみる(Ninja web framework編)です。
お題は、こちら

2年以上前と同じテーマの続編を今頃書くという。
Ninja web frameworkは、Play1みたいな感じのフレームワークです。

Routes.java

まずは、URLとコントローラクラスのマッピングを定義するクラスです。

package conf;

import ninja.Router;
import ninja.application.ApplicationRoutes;
import controllers.Add1Controller;
import controllers.Add2Controller;

public class Routes implements ApplicationRoutes {

    @Override
    public void init(Router router) {
        router.GET().route("/add1/input").with(Add1Controller.class, "input");
        router.GET().route("/add1/calculate")
                .with(Add1Controller.class, "calculate");

        router.GET().route("/add2/input").with(Add2Controller.class, "input");
        router.POST().route("/add2/calculate")
                .with(Add2Controller.class, "calculate");
    }

}

アノテーションで各クラスに定義するJAX-RSやSpring MVCよりこっちの方が好きかも。
今回、メソッド引数でリクエストパラメータを受け取るパターンと、Dtoで受け取るパ
ターンの2パターンを作ってみました。

アクセスURLは以下の2つです。

メソッド引数でリクエストパラメータを受け取るパターン

Add1Controller.java

コントローラクラスです。

package controllers;

import java.util.Map;

import ninja.Result;
import ninja.Results;
import ninja.params.Param;
import ninja.validation.IsInteger;
import ninja.validation.Required;
import ninja.validation.Validation;

import com.google.common.collect.Maps;

public class Add1Controller {

    public Result input() {
        return Results.html();
    }

    public Result calculate(@Param("arg1") @Required @IsInteger String arg1,
            @Param("arg2") @Required @IsInteger String arg2,
            Validation validation) {

        Map<String, Object> map = Maps.newHashMap();

        if (validation.hasViolations()) {
            map.put("errors", validation.getFieldViolations());
            map.put("arg1", arg1);
            map.put("arg2", arg2);
            return Results.html().render(map)
                    .template("views/Add1Controller/input.ftl.html");
        }

        map.put("result", Integer.parseInt(arg1) + Integer.parseInt(arg2));
        return Results.html().render(map);
    }
}

リクエストパラメータの受け取りの@Param("arg1")の部分ですが、Play1のようにデフォルトで変数名を使ってくれると嬉しいのですが、そうではありません。

input.ftl.html

入力画面のテンプレートです。
Viewには、JSPではなく、FreeMakerが使われています。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Add1</title>
  </head>
<body>
<#list errors! as error>
${error.constraintViolation.defaultMessage}<br/>
</#list>
<form method="get" action="${contextPath}/add1/calculate">
<input type="text" name="arg1" value="${arg1!}" />
+
<input type="text" name="arg2" value="${arg2!}" />
<input type="submit" />
</form>
</body>
</html>

FreeMakerの使い方は、よくわかってないです。エラーメッセージの出力とか完全手探り。

result.ftl.html

結果表示画面。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Add1</title>
  </head>
<body>
${result}
</body>
</html>

Dtoでリクエストパラメータを受け取るパターン

別パターンです。
コントローラクラスです。

Add2Controller.java

package controllers;

import java.util.List;
import java.util.Map;

import javax.validation.constraints.Digits;

import org.hibernate.validator.constraints.NotBlank;

import ninja.Result;
import ninja.Results;
import ninja.validation.FieldViolation;
import ninja.validation.JSR303Validation;
import ninja.validation.Validation;

import com.google.common.collect.Maps;

public class Add2Controller {

    public Result input() {
        return Results.html();
    }

    public Result calculate(@JSR303Validation Form form, Validation validation) {

        Map<String, Object> map = Maps.newHashMap();

        if (validation.hasViolations()) {
            List<FieldViolation> beanViolations = validation.getBeanViolations();
            map.put("errors", beanViolations);
            map.put("arg1", form.arg1);
            map.put("arg2", form.arg2);
            return Results.html().render(map)
                    .template("views/Add2Controller/input.ftl.html");
        }

        map.put("result",
                Integer.parseInt(form.arg1) + Integer.parseInt(form.arg2));
        return Results.html().render(map);
    }

    public static class Form {
        
        @NotBlank
        @Digits(integer=9,fraction=0)
        public String arg1;
        
        @NotBlank
        @Digits(integer=9,fraction=0)
        public String arg2;
    }
}

メソッド引数にアノテーションつけまくるより、Dtoに切り出したほうが見やすいかも。しかし、GETの場合は、Dtoでリクエストパラメータで受け取ることはできないみたいです。

input.ftl.html

入力画面。最初のパターンとエラーメッセージの出力の仕方がちょっと違うくらい。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Add2</title>
  </head>
<body>
<#list errors! as error>
${error.field}: ${error.constraintViolation.messageKey}<br/>
</#list>
<form method="post" action="${contextPath}/add2/calculate">
<input type="text" name="arg1" value="${arg1!}" />
+
<input type="text" name="arg2" value="${arg2!}" />
<input type="submit" />
</form>
</body>
</html>

結果表示画面は最初のパターンと同じです。

今回は、単純なHTMLを出力する例ですが、JSONのレスポンスとか簡単にできるようです。

Struts1がEOLとなりましたが、このNinjaが移行先には、、、、
ならないだろうなー。たぶん。

github ソースコードをアップしました。

(2013-06-24編集)
contextPathがテンプレートから簡単に取れるようになったので修正しました。