Spring Boot JPAを使ってみる

##JPA（Spring Data JPA）とは
ざっくり何かというと「SpringBootでデータベースにアクセスできるアプリを作るためのもの」です。

SpringBoot公式サイトにある[「JPAを使用したデータへのアクセス（英語記事）」](https://spring.io/guides/gs/accessing-data-jpa/#scratch)をもとに、自分なりに調べて理解した内容を書きます。


##実行環境
・Mac
・VSCode
・Maven
MavenというJavaプログラムをビルドするためのものを使うので、落としてない人はインストールしましょう。


##さっそく始めよう

まずはSpringBootを落とします。
spring initializr を開きましょう。

<img width="1338" alt="スクリーンショット 2020-07-01 15.42.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367972/93520c92-7286-1b40-e446-4a00dc482d48.png">


この内容で作っていきます。
右のDependencies（依存関係）タブをクリックして、「Spring Data JPA」と「H2 Database」を追加し、GENERATEでアプリ作成。

作成したアプリをVSCodeなり任意のエディタで開いてみます。

pomファイルを確認します。pomファイルはアプリ上で使ういろんな機能の依存関係を書いたファイルです。
手順通り作られていれば以下の内容になっているはずです。


```pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>accessing-data-jpa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>accessing-data-jpa</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
```


###クラスの定義
このアプリでは、データベースに顧客情報を登録し、条件に合う顧客情報をconsoleに出力できるようにしていきます。
まずはCustomerクラスを作りましょう。Customer.javaファイルを追加します。 （src/main/java/com/example/accessingdatajpa/Customer.java）

```Customer.java
package com.example.accessingdatajpa;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Customer {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;
  private String firstName;
  private String lastName;

　//JPAのためのコンストラクタ。使うことはないためprotectedを指定。
  protected Customer() {}

　//データベースに保存する Customer のインスタンスを作成するためのコンストラクタ。
  public Customer(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  @Override
  public String toString() {
    return String.format(
        "Customer[id=%d, firstName='%s', lastName='%s']",
        id, firstName, lastName);
  }

  public Long getId() {
    return id;
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }
}
```

id、firstName、lastNameの3つの属性を持つCustomerクラスができました。

**＠Entity**
Customer クラスには @Entity というアノテーションが付けられています。
Entityはデータベースにセットするためのもので、 ここではCustomer というテーブルに紐づいています。
Entityの言葉は、`実在、存在、実体、本体`などの意味を持つようです。

**@ID**
Customer オブジェクトの id プロパティは、JPA がオブジェクトの ID として認識するように @Id をつけます。

**.@GeneratedValue**
idプロパティには、@GeneratedValue というアノテーションあります。
これはidを自動で生成してくれます。


toString() メソッドは、顧客情報を出力します。

###リポジトリを作る
次に顧客情報を記録するCustomerRepository.javaを作ります。（Customersrc/main/java/com/example/accessingdatajpa/CustomerRepository.java）

```CustomerRepository.java
package com.example.accessingdatajpa;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer, Long> {

  List<Customer> findByLastName(String lastName);

  Customer findById(long id);
}

```

CustomerRepositoryはCrudRepositoryのインターフェイスを受け継いでいます。
Crudというのはシステムに必要な4つの主要機能である「Create（生成）」「Read（読み取り）」「Update（更新）」「Delete（削除）」の頭文字を並べた用語で、 CrudRepositoryは名前の通り、これらの機能を備えているので、CustomerRepositoryにCrudRepositoryを引き継がせると、これらが使えるようになります。


###アプリケーションクラスを作る
Initializrがアプリ作成の時に作ったクラスに、内容を追加します。
（src/main/java/com/example/accessingdatajpa/AccessingDataJpaApplication.java）

**以下が元の内容**

```AccessingDataJpaApplication.java
package com.example.accessingdatajpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataJpaApplication {

  public static void main(String[] args) {
    SpringApplication.run(AccessingDataJpaApplication.class, args);
  }

}
```

**以下が内容を追加したもの**

```AccessingDataJpaApplication.java
package com.example.accessingdatajpa;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class AccessingDataJpaApplication {

  private static final Logger log = LoggerFactory.getLogger(AccessingDataJpaApplication.class);

  public static void main(String[] args) {
    SpringApplication.run(AccessingDataJpaApplication.class);
  }

  @Bean
  public CommandLineRunner demo(CustomerRepository repository) {
    return (args) -> {
      // save a few customers
      repository.save(new Customer("Jack", "Bauer"));
      repository.save(new Customer("Chloe", "O'Brian"));
      repository.save(new Customer("Kim", "Bauer"));
      repository.save(new Customer("David", "Palmer"));
      repository.save(new Customer("Michelle", "Dessler"));

      // fetch all customers
      log.info("Customers found with findAll():");
      log.info("-------------------------------");
      for (Customer customer : repository.findAll()) {
        log.info(customer.toString());
      }
      log.info("");

      // fetch an individual customer by ID
      Customer customer = repository.findById(1L);
      log.info("Customer found with findById(1L):");
      log.info("--------------------------------");
      log.info(customer.toString());
      log.info("");

      // fetch customers by last name
      log.info("Customer found with findByLastName('Bauer'):");
      log.info("--------------------------------------------");
      repository.findByLastName("Bauer").forEach(bauer -> {
        log.info(bauer.toString());
      });
      // for (Customer bauer : repository.findByLastName("Bauer")) {
      //  log.info(bauer.toString());
      // }
      log.info("");
    };
  }

}
```
@SpringBootApplicationは、以下のアノテーションを含んでいます。

>**@Configuration**:アプリケーション・コンテキストのためのBean定義のソースとしてクラスにタグを付けます。

>**@EnableAutoConfiguration**: アプリケーションコンテキストのためのビーン定義のソースとしてクラスにタグを付けます。クラスパス設定、他のビーン、様々なプロパティ設定に基づいてビーンの追加を開始するようにSpring Bootに指示します。例えば、spring-webmvcがクラスパス上にある場合、このアノテーションはアプリケーションをウェブアプリケーションとしてフラグを立て、DispatcherServletの設定などの主要な動作をアクティブにします。

>**@ComponentScan**: パッケージ内の他のコンポーネントや設定等を探し、コントローラを見つけるようにSpringに指示します。

@Beanは、@Beanを記述したメソッドでインスタンス化したクラスを返すためのものです。
@Component、@Service、@Repository、@Controllerをつけるクラスについては、このアノテーションをつけた時点でBeanとして登録されるため、@Beanを付与する必要はありません。


main()メソッドはアプリを起動します。

loggerはconsoleに結果を出力するためのものです。
顧客情報を設定してlogに出力してみます。
AccessingDataJpaApplicationクラスに内容を追加してみましょう。(src/main/java/com/example/accessingdatajpa/AccessingDataJpaApplication.java)。

```AccessingDataJpaApplication.java

package com.example.accessingdatajpa;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class AccessingDataJpaApplication {

  //logにAccessingDataJpaApplicationクラスに書かれた内容を出す
  private static final Logger log = LoggerFactory.getLogger(AccessingDataJpaApplication.class);

  //SpringApplicationを起動させる
  public static void main(String[] args) {
    SpringApplication.run(AccessingDataJpaApplication.class);
  }

  @Bean
  public CommandLineRunner demo(CustomerRepository repository) {
    return (args) -> {
      // 顧客情報を設定する
      repository.save(new Customer("Jack", "Bauer"));
      repository.save(new Customer("Chloe", "O'Brian"));
      repository.save(new Customer("Kim", "Bauer"));
      repository.save(new Customer("David", "Palmer"));
      repository.save(new Customer("Michelle", "Dessler"));

      // 全ての顧客情報を取り出す
      log.info("Customers found with findAll():");
      log.info("-------------------------------");
      for (Customer customer : repository.findAll()) {
        log.info(customer.toString());
      }
      log.info("");

      // 一致するIDを持った顧客情報を取り出す
      Customer customer = repository.findById(1L);
      log.info("Customer found with findById(1L):");
      log.info("--------------------------------");
      log.info(customer.toString());
      log.info("");

      // 一致するLastNameを持った顧客情報を取り出す
      log.info("Customer found with findByLastName('Bauer'):");
      log.info("--------------------------------------------");
      repository.findByLastName("Bauer").forEach(bauer -> {
        log.info(bauer.toString());
      });
      // for (Customer bauer : repository.findByLastName("Bauer")) {
      //  log.info(bauer.toString());
      // }
      log.info("");
    };
  }

}
```


###実行してみる
ターミナルに`./mvnw spring-boot:run`を打ち込み、実行してみましょう。
すると、以下のような実行結果になるはずです。

<img width="664" alt="スクリーンショット 2020-07-01 14.19.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367972/1473860a-0658-88e1-f30d-28398c2f7cfa.png">

##完成
以上でSpring Data JPAを使ってオブジェクトをデータベースに保存したり、データベースから取得したりするシンプルなアプリができました。