たなかのJava日記

どんなことをやったか(学んだか)、どこで詰まったか(わからなかったか)、どこで工夫したかの記録です。

Day38

■時間

1.0時間

 

■行ったこと

1,GW中に実施したところの復習

 

■出来たこと

使用したSpring Bootのアノテーションについて

Webアプリケーションの仕組みについて

 

■出来なかったこと

GW中に最低限でもDB以外は完成させたかったのですがあと一歩でした。

しかし、これまで行ったところでわからないところは確実につぶしながらこれたので、引き続き焦らず進めていきたいです。

【Spring Boot】HTMLとJavaを分けて構成する②

前回まででThymeleafを利用する準備が整いました。
次にWebページの静的部分を構成するHTMLテンプレートを作成します。


HTMLテンプレート作成する場所は、
プロジェクトのsrc/resources/templatesディレクトリ以下です。
今回はhello.htmlというファイルで作成します。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
    <h1>Hello</h1>
    It works<br>
    現在時刻は<span th:text="${time}"></span>です。
</body>
</html>


通常のHTMLと異なる部分があります。
まず、htmlタグの宣言部分です。

<html xmlns:th="http://www.thymeleaf.org">

ここに付けられているxmlns:thの属性がThymeleafのテンプレートであることを示す宣言になります。
もっと平易な言葉で説明すると、これでThymeleafが使えるようになるということです。

このツールを使用することによって、
個別のファイルで作成されたHTMLテンプレートファイルとJavaプログラムがHTTPリクエストを受け取ると、
HTMLファイルにJavaのプログラムで生成されたデータを埋め込んでレスポンスとして返すことができます。


もう一つ通常のHTMLと大きく異なる箇所があります。本文の中にあるspanタグの部分です。

<span th:text="${time}"></span>


ここはサーバー上の現在時刻を示す部分です。
時刻はリアルタイムで表示したいので、あらかじめHTMLに書いておくことができません。
このページにアクセスし表示されるときに、時刻を取得するようにしたいです。
そこで、HTTPレスポンスを返す段階でテンプレートエンジン(Thymeleaf)によって動的に中身を変える仕組みを使います。
今回の場合、th:textと書かれている部分がThymeleafによって処理される箇所になります。
具体的な処理の内容は、spanタグの中身がth:text属性の値として指定されている文字列に変わります。
属性の中では変数を使用することができ、${}を使って表現します。
今回は${time}としていますが、spanタグの中身がtime変数の値になるということです。
time変数には、Javaのプログラムから値を設定することができるようになっています。


これでhello.htmlは、HTMLとしてJavaから分けることができました。
次にHomeControllerクラスのhelloメソッドで、今作成したhello.htmlを使うようにJavaプログラムを書き換えます。
書き換える理由としては、以下の流れで言うとJavaで現在時刻の取得する処理を行った結果を、
hello.htmlのtime変数に埋め込みたいからです。


HTTPリクエストを受け取る

Javaで現在時刻の取得する処理を行う

処理を行った結果(現在時刻)をHTMLの変数へ指定して渡す

HTMLでデータ(現在時刻)を受け取ったら指定された箇所(time変数)へ埋め込む

埋め込んだ結果をHTMLレスポンスとして返す

結果がWebブラウザに表示される

@Controller
public class HomeController {
    @RequestMapping(value="/hello")
    String hello(Model model) {
        model.addAttribute("time", LocalDateTime.now());
        return "hello";
    }
}

繰り返しになりますが、ここで行っていることは、
Javaで現在時刻の取得する処理を行い、処理の結果(現在時刻)をHTMLへ渡すだけになります。
また、今回はビューを構成するHTMLはコントローラ自身ではなくテンプレートエンジンが作成してくれます。
なので、JavaとHTMLを別々にしているということはここにHTMLは書きませんし、
このエンドポイントのメソッドではHTTPレスポンスの本体そのものは返しません。
@ResponseBodyアノテーションも付けません。

返すのは、対応するビュー名の文字列になります。
対応するビュー名というのは、このJavaのhelloメソッドの処理結果はどこのHTMLに埋め込むのか、
そのHTMLの名前になります。
注意点としては、ビュー名は設定ファイルなどで別途指定していない場合には、
HTMLのテンプレートファイルから拡張子を除いたものになります。
今回のhelloメソッド場合、hello.htmlを使うので「hello」をビュー名として返します。
その仕組み(処理の結果(現在時刻)をHTMLへ渡すこと)がhelloメソッド内になります。


String hello(Model model)


引数として、org.springframework.ui.Modelクラスのオブジェクトを受け取ります。
ModelクラスはJavaプログラムとHTMLテンプレートの間で値を受け渡す役割を担います。


model.addAttribute("time", LocalDateTime.now());


引数に渡されたModelオブジェクトに対しては、addAttributeメソッドを使って属性を設定できます。
属性はキーと値の組み合わせになっていて、キーはHTMLテンプレート側で使用している変数になります。

まとめると、今回はhello.htmlに渡す属性として、
キーに"time"を、
値に現在時刻を設定しています。
こうすることで、hello.htmlの${time}の部分が渡された現在時刻に置き換えられる仕組みになっています。


この状態でプロジェクトを再実行し、ブラウザでアクセスします。

http://localhost:8888/hello
※ポート番号は自分で指定した値を使用する

問題なく表示されていれば成功です。

【Spring Boot】HTMLとJavaを分けて構成する①

前回までで、Webブラウザからのタスクの追加と一覧表示ができるようになりました。
しかし、HomeControllerクラスには大きな問題があります。

package jp.gihyo.projava.tasklist;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.time.LocalDateTime;

@Controller
public class HomeController {
    @RequestMapping(value="/hello")
    @ResponseBody()
    String hello() {
        return """
                <html>
                    <head><title>Hello<title></head>
                    <body>
                        <h1>Hello</h1>
                        It works!<br>
                        現在時刻は%sです。
                    </body>
                </html>
                """.formatted(LocalDateTime.now());
    }
}


それはJavaクラスにHTMLが直接記述されていることです。

これにより2点ほど問題が発生します。

1,Webページのデザインを少し変えたい場合など、Javaソースコードを修正しなければならない
2,Javaを知らなければ、デザインを組むことも出来ない

実際の開発現場では、Webページのデザインは開発者ではなく、デザイナーが担当するケースが多いことと、
可読性などを踏まえると2つを分けるのが一般的とのことです。

そこで、「コントローラ」をJavaプログラムで、
「ビュー」をHTMLのコードで別々に分けて構成することにします。


そうすることによって、処理の流れとしては以下のようになります。

HTTPリクエストを受け取る

Javaで処理を行う

処理を行った結果(データ)をHTMLへ渡す

HTMLでデータを受け取ったら該当の箇所へ埋め込む

埋め込んだ結果をHTMLレスポンスとして返す

結果がWebブラウザに表示される


ただ分けて構成を変更しても、その二つは別々のものです。
これらを組み合わせるツールが、テンプレートエンジンと呼ばれるものです。
Spring Frameworkと組み合わせて使えるテンプレートエンジンとしてはいくつかありますが、
Spring Bootと相性が良く、人気があるのがThymeleafです。
今回は、タスク管理アプリケーションのビュー部分をThymeleafを導入し改良していきます。

Thymeleafを導入の前に、
繰り返しになりますが、作成するタスク管理アプリケーションの仕組みを復習します。

まず、フォームやテーブルのタグなどの部分はHTMLテンプレートとして用意します。
そして、TaskItemオブジェクトで管理されているタスク情報についてはプログラムで生成し、
テンプレートと組み合わせてHTTPレスポンスとして返すような仕組みになります。

では、早速Thymeleafが使えるようにpom.xmlを修正します。

Mavenを使用している場合は、pom.xmlに依存関係の設定を追加するだけです。
それだけで、Spring Bootプロジェクトに導入することができます。

pom.xmlのdependenciesタグの中に、以下のように依存関係を追加します。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>


追加後は必ずMavenモジュールの再ロードを行ってください。
これでThymeleafを利用する準備が整いました。

【Spring Boot】@Controllerでコントローラを作成する

まずJavaによるWebアプリケーションの仕組みについての復習です。

Webアプリケーションは3つのパーツに分けて考えることができます。
その3つとは「モデル」、「ビュー」、「コントローラ」です。
それぞれの役割は以下になります。


1、「モデル」
 ⇒アプリケーションで使用するデータを保持する部分

2、「ビュー」
 ⇒ユーザーによって利用されるユーザーインターフェースの部分

3、「コントローラ」
 ⇒ユーザーインターフェース(Webページ)から送られてくるリクエストを処理する部分


この3つを組み合わせるような構成や仕組みを「MVCモデル」と呼ばれることがあります。MVCは3つの頭文字を取ったものです。


これまで、タスク管理アプリケーションの「モデル」、「コントローラ」の部分は作りましたが、UIの部分を担う「ビュー」については、単にテキストを表示するだけでした。
しかし、これではWebアプリとは到底呼べません。
ここからはタスク管理アプリケーションを「ビュー」を持つように変更していきます。


WebアプリケーションにおけるUIとは、
ご存知かとは思いますが、HTMLを使って記述されたWebページとなります。
これまではWebブラウザへのレスポンスとして文字列をそのまま返していましたが、UIとして成立させるために見た目を整えてHTMLとして返す必要があります。
また、リクエストのパラメータについてもアドレスバーにURLの一部として打ち込むのではなく、HTMLのフォームから入力できるようにしなくてはなりません。


これから行うことをまとめると以下になります。

1、Webブラウザへのレスポンスとして文字列をそのまま返していたのを変更
 ⇒WebアプリケーションのUIとして成立させるために見た目を整えてHTMLとして返す

2、リクエストのパラメータはアドレスバーにURLの一部として打ち込んでいたのを変更
 ⇒WebアプリケーションのUIとして成立させるために、HTMLのフォームから入力できるようにする


まず、1についてです。
HTTPレスポンスとして、HTMLを返したい場合は、Spring Webに用意されている@Controtllerを使用します。
となると、これまで使用していた@RestControllerは、HTTPレスポンスとして文字列を返すために使用していたということになります。

早速、@Controllerを使用したコントローラを作成するために、新しくHomeControllerという名前のクラスを作成します。

package jp.gihyo.projava.talklist;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.time.LocalDateTime;

@Controller
public class HomeController {
    @RequestMapping(value="/hello")
    @ResponseBody()
    String hello() {
        return """
                <html>
                    <head><title>Hello<title></head>
                    <body>
                        <h1>Hello</h1>
                        It works!<br>
                        現在時刻は%sです。
                    </body>
                </html>
                """.formatted(LocalDateTime.now());
    }
}


@RestControllerと同様、helloメソッドの@RequestMappingは同じです。
"/hello"としてパスに対するエンドポイント指定し、文字列を返しています。
しかし、返す文字列の内容がHTMLになっている点が大きく違います。

エンドポイントとは簡単に言うと、「Webブラウザ(クライアント)との窓口となるメソッド」のことです。

@Controllerでコントローラを作成する場合、
レスポンスとして返す際に、サーバー側のプログラム内でWebコンテンツを生成して返すことになります。

その他の違う点としては、@Controllerのhelloメソッドには@ResponseBodyというアノテーションが付いています。
このアノテーションを付けることで、Stringのオブジェクト自体がレスポンス本体として扱われるようになります。
別の言い方をすると、メソッドの戻り値を Web レスポンスの本文にバインドする(埋め込む)必要があることを示すアノテーションになります。


なぜこのアノテーションが必要かというと、
@Controllerを使った場合にはデフォルトの挙動として、
各エンドポイントメソッドは戻り値として「ビューを表すオブジェクトの名称」を返すことになっているからです。
「ビューを表すオブジェクトの名称」とは、端的に言えばレスポンス本体のHTML文書を生成してくれるオブジェクトのことです。
helloメソッドの場合、自分自身でHTML文書をStringオブジェクトととして生成し、戻り値として返しています。
なので、このまま@ResponseBody無しで返しても厳密にはHTMLではないのでエラーになります。
@Controllerを使った場合の戻り値(レスポンス)は、HTMLでないといけないということです。
@ResponseBodyを付けることで、Stringのオブジェクト自体がレスポンス本体(HTML)として扱われるようになります。


理解が出来たら、プロジェクトを再実行します。
問題なく起動が出来たら、Webブラウザから以下のアドレスを入力します。

 

http://localhost:8888/hello
※8888の箇所は自分で指定したポート番号にする


ブラウザに以下のように表示されたら成功です。


Hello
It works!
現在時刻は2022-05-06T18:22:34.879833600です。

Day35

■時間

3.0時間

 

■行ったこと

1,Spring Bootのアノテーションの使用

2,ラムダ式やStreamを使った処理

 

■出来たこと

@RequestMaping,@GetMappingを使用して、登録済みのタスクを一覧表示するが出来ました。

 

■出来なかったこと

また、一覧表示するまでの過程でラムダ式やStreamを使いましたが、難しくまだ使いこなせていません。基本を押さえるための時間が別途必要と考えています。