Spring Bootでアプリを作成してみた【ログイン及び検索機能付きCRUDアプリ】

## 開発に利用するツール及びフレームワーク
- JDK(Amazon Corretto17)
- VSCode
- Docker
- Git
- Boostrap
- Thymeleaf
- Spring Framework
- Mybatis
- Gradle

## 1. Javaプロジェクト作成

公式：[spring initializr](https://start.spring.io/)
##### spring initializrとは？
Spring Initializrは条件に合わせてSpring Bootプロジェクトの雛形を生成するWebサービス。Web UIからプロジェクト設定や利用するSpring Projectを指定することで、簡単にSpring Bootプロジェクトの開発を始めることができる。

1. ブラウザを開き、(https://start.spring.io/)を入力し、開く
2. 下記を入力し、Dependenciesで下記を選択し、『GENERATE』ボタンを押す
- Group:
- Artifact:
- Package name:
- Dependencies:

Dependencies
- Spring Boot Dev Tools
- Spring Web
- Thymeleaf
- Lombok
- MySQL Driver
- MyBatis Framework

##### Gradleとは？
- Javaの構成管理ツールの一つで、Javaのアプリをまとめる時に使う。
- アプリで利用するライブラリをインターネットから取得して依存関係を作る。
- Mavenの後継ツールで、Mavenを使っても良い。
[Gradleを基本からまとめてみた【入門】](https://qiita.com/kanfutrooper/items/dbe92a9cd6da6981a0d6)

VScodeの『Run and Debug』をクリックし、『create a lanuch.json file』をクリックし、JAVAを選択し、Springを起動する。

##### Gradleの最新化を行う

```build.gradle
//implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.0'

```
このソースコードをコメントアウトした後、Gradleの同期を行いますか？
と質問が出てくるので『Yes』を押す



 mainのjava/jo/planaria/sample/motocatalogにcontrollersフォルダを作成し、MotosController.javaファイルを作成する。

##### ※ 『command』+ 『.』で import文を保管する

## 2. 画面の見た目を作る
##### Boostrapとは？
- レスポンシブデザインを実現するフロントエンドライブラリ
- グリッドシステムで画面を構成する

①resources/templates/moto_list.htmlを作成する。
②Bootstrapのスターターテンプレートをコピペして貼る。
[Bootstrapのスターターテンプレート](https://getbootstrap.jp/docs/5.0/getting-started/introduction/)

```resources/templates/moto_list.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <!-- Bootstrap CSS -->
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
      crossorigin="anonymous"
    />
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Montserrat&family=Open+Sans:wght@400;700&family=Poppins&display=swap"
      rel="stylesheet"
    />
    <title>Hello, world!</title>
    <style>
      body {
        font-family: 'Montserrat', sans-serif;
        font-family: 'Open Sans', sans-serif;
        font-family: 'Poppins', sans-serif;
      }
    </style>
  </head>
  <body>
    <!-- As a heading -->
    <nav class="navbar navbar-dark bg-primary mb-5">
      <div class="container-fluid">
        <span class="navbar-brand mb-0 h1">バイク管理</span>
      </div>
    </nav>
    <div class="container">
      <div class="row">
        <div class="col">
          <div class="mb-3">
            <label for="brand" class="form-label">バイクメーカー</label>
            <select
              class="form-select"
              id="brand"
              aria-label="Default select example"
            >
              <option selected>HONDA</option>
              <option value="1">KAWASAKI</option>
              <option value="2">SUZUKI</option>
              <option value="3">YAMAHA</option>
            </select>
          </div>
        </div>
        <div class="col">
          <div class="mb-3">
            <label for="keyword" class="form-label">キーワード</label>
            <input
              type="text"
              class="form-control"
              id="keyword"
              placeholder="name@example.com"
            />
          </div>
        </div>
      </div>
      <div class="row">
        <div class="col d-flex flex-row-reverse">
          <button type="button" class="btn btn-primary">新規</button>
          <button type="button" class="btn btn-primary ms-1 me-1">
            リセット
          </button>
          <button type="button" class="btn btn-primary">検索</button>
        </div>
      </div>
      <div class="row">
        <div class="col">
          <table class="table mt-5">
            <thead>
              <tr>
                <th scope="col">No.</th>
                <th scope="col">メーカー</th>
                <th scope="col">車名</th>
                <th scope="col">エンジン</th>
                <th scope="col">価格</th>
                <th scope="col">コメント</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <th scope="row">1</th>
                <td>KAWASAKI</td>
                <td>Z900RS</td>
                <td>水冷４気筒</td>
                <td>1500000</td>
                <td>カッコ良い</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>

    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
      crossorigin="anonymous"
    ></script>
  </body>
</html>
```

## 3. 画面を動的ページにする
main/javaに beanフォルダとBrand.javaとMotorcycle.javaを作成する

```main/bean/Brand.java
package jp.co.planaria.sample.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Brand {
    
//ブランドID
private String brandId;
//ブランド名
private String brandName;
}
```
```main/bean/Motorcycle.java
package jp.co.planaria.sample.bean;

import java.time.LocalDateTime;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Motorcycle {
    
    //バイク番号
    private Integer motoNo;
    //バイク名
    private String motoName;
    //シート高
    private Integer seatHeight;
    //シリンダー
    private Integer cylinder;
    //冷却
    private String cooling;
    //価格
    private Integer price;
    //バージョン
    private String comment;
    //ブランドID
    private Brand brand;
    //バージョン
    private Integer version;
    //登録日時
    private LocalDateTime insDt;
    //更新日時
    private LocalDateTime updDt;
}
```

```controllers/Motorcontroller.java
package jp.co.planaria.sample.motocatalog.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.thymeleaf.engine.AttributeName;

@Controller
public class MotosController {
    
    @RequestMapping("/hello")
    public String hello(@RequestParam String name,Model model){
        model.addAttribute(attributeName:"name", name);
        return "test";
 }


//moto_list.html を呼び出す
 @GetMapping("/motos")
 public String motos(Model model){
    //ブランド
    List<Brand>brands = new ArrayList<>();
    brands.add(new Brand(BrandId:"01", brandName:"HONDA"));
    brands.add(new Brand(BrandId:"02", brandName:"KAWASAKI"));
    brands.add(new Brand(BrandId:"03", brandName:"YAMAHA"));
    brands.add(new Brand(BrandId:"04", brandName:"SUZUKI"));
    //バイク
    List<Motorcycle>motos = new ArrayList<>();
    motos.add(new Motorcycle (motoNo:1, motoName:"GB350",seatHeight:800, cylinder:1,cooling:"空冷",price:5000000, comment:"良い音",new Brand(brandId:"01",brandName:"HONDA"),version:1,insDt:null,updDt:null));
    motos.add(new Motorcycle (motoNo:2, motoName:"NINJA",seatHeight:800, cylinder:2,cooling:"水冷",price:10000000, comment:"良い良い音",new Brand(brandId:"02",brandName:"KAWASAKI"),version:1,insDt:null,updDt:null));
    motos.add(new Motorcycle (motoNo:3, motoName:"Z900RS CAFE",seatHeight:820, cylinder:2,cooling:"水冷",price:13800000, comment:"良い音がする",new Brand(brandId:"02",brandName:"KAWASAKI"),version:1,insDt:null,updDt:null));
    

    model.addAttribute(AttributeName:"brands", brands);
    model.addAttribute(AttributeName:"motos", motos);

    return "moto_list";
 }
}
```
## 4. データベースの情報を画面に表示

#### データベースとは
- データを効率よく保管・取り出したを行うためのソフトウエアのこと

#### 仮想環境とは
- 実際に存在する物理的なコンピュータに仮想的なコンピュータやOSを利用できるようにした環境のこと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939638/c129e0b3-f555-5595-bce5-b2198893e687.png)

#### docker
- コンテナ仮想化を実現してくれる製品の一つ


#### dockerでMySQLを準備する

公式サイト：[dockerhub](https://hub.docker.com/)

① docker-compose.ymlを作成し、下記のコードを貼り付ける
```
touch docker-compose.yml
```
```docker-compose.yml
# Use root/example as user/password credentials
version: '3.1'

services:

  db:
    image: mysql
    # NOTE: use of "mysql_native_password" is not recommended: https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-password
    # (this is just an example, not intended to be a production configuration)
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
 ```
②docker desktopを起動する

③ターミナルで、下記のコードを入力する

```
docker-compose up -d
docker ps -a
docker images
docker-compose down --rmi all -v
```
④docker-compose.ymlを編集する

```docker-compose.yml
version: '3.1'

services:
  db:
    image: mysql

    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASE: monocatalogdb
      MYSQL_USER: develop
      MYSQL_PASSWORD: develop
    ports: [5432, 5433]
```
⑤docker-compose up -dをする


## 5. データベースの情報を画面に表示
##### ログ出力とは
- ログとはプログラムの動作状況を目に見える情報として時系列に出力するもの
- 正常に動作していることと確認したり、異常が発生した時の原因特定に利用
例）
- アクセスログ（システムにアクセスがあった記録）など

```controllers/Motorcontroller.java
package sample.project.monocatalog.controllers;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import ch.qos.logback.classic.Logger;
import lombok.extern.slf4j.Slf4j;
import sample.project.bean.Brand;
import sample.project.bean.Motorcycle;

@Controller

@Slf4j // ログ出力その２
public class MotosController {
   // ログ出力処理その１ ログ部品を使えるようになる
   // private static final Logger log =
   // LoggerFactory.getLogger(MotosController.class);

   // @RequestMapping("/hello")
   // public String hello(@RequestParam String name, Model model){
   // model.addAttribute(attributeName:"name", name);
   // return "test";
   // }

   // moto_list.html を呼び出す
   @GetMapping("/motos")
   public String motos(Model model) {

      // ブランド
      List<Brand> brands = new ArrayList<>();
      brands.add(new Brand("01", "HONDA"));
      brands.add(new Brand("02", "KAWASAKI"));
      brands.add(new Brand("03", "YAMAHA"));
      brands.add(new Brand("04", "SUZUKI"));

      // バイク
      List<Motorcycle> motos = new ArrayList<>();
      motos.add(new Motorcycle(1, "GB350", 800, 1, "空冷", 50, "良い音", new Brand("01", "HONDA"), 1, null, null));
      motos.add(new Motorcycle(2, "Ninja", 800, 2, "水冷", 100, "良い音", new Brand("02", "KAWASAKI"), 1, null, null));
      motos.add(new Motorcycle(3, "Z900RS", 820, 4, "水冷", 138, "良い音", new Brand("03", "KAWASAKI"), 1, null, null));
      motos.add(new Motorcycle(4, "GB350", 800, 1, "空冷", 5, "良い音", new Brand("01", "HONDA"), 1, null, null));
      motos.add(new Motorcycle(5, "GB350", 800, 1, "空冷", 5, "良い音", new Brand("01", "HONDA"), 1, null, null));
      motos.add(new Motorcycle(6, "GB350", 800, 1, "空冷", 5, "良い音", new Brand("01", "HONDA"), 1, null, null));

      model.addAttribute("brands", brands);
      model.addAttribute("motos", motos);

      log.info("motos:{}", motos);// ログ出力する

      return "moto_list";
   }
}
```

##### ログ出力先
- デフォルト状態のログ出力先 = 標準出力 
- ターミナルもしくはコンソールと呼ばれるところのみ出力される
- 永続的に残らない
- Spring Bootではアプリ設定ファイルにログ出力に関する設定を記述できる

```application.properties
//ログの出力レベルの設定を行う
logging.level.root=debug
//ログをファイルに出力できるようにファイル名を指定する
logging.file.name=app.log
```

##### ログローテーション
- ログローテーションとは一定の単位ごとにログファイルを切り替えること


```application.properties
//ログテーション
logging.logback.rollingpolicy.max-file-size=1MB
```

|ログレベル |     説明      | 運用時 |
| ---- | ----------- | ------- |
| trace | デバッグよりもさらに詳細な情報 | 出力しない |
| debug | システムの動作を確認・調査する際に利用する情報 | 出力しない |
| info  | システムが正常に動作することを確認するための情報 | 出力する |
| warn  | 異常ではないが早期に対応が推奨される事象の情報 | 出力する |
| error | 異常発生に関する情報 | 出力する |
| fatal | 致命的な異常発生に関する情報 | 出力する |


## 6.入力チェック

## 7.ログイン・ログアウト


## 参考サイト
[VSCodeでSpringBoot開発 #00.講座紹介](https://www.youtube.com/watch?v=6sS2Eco1y1U)
[VSCodeでSpringBoot開発 #02.プロジェクト作成](https://www.youtube.com/watch?v=QjxCHk2wyFs)
[【話題のITトレンド】コンテナ技術と仮想マシンの違いとは？　ー Vol.15 ー](https://psc-smartwork.com/topics/2021/08/162.html)
[VSCodeでSpringBoot開発 #07.データベースを準備](https://www.youtube.com/watch?v=q8sSEQeQTfg)
[VSCodeでSpringBoot開発 #08.データベースアクセス](https://www.youtube.com/watch?v=i6mauFYuCrc)