LoginSignup
9

More than 5 years have passed since last update.

Spring BootとJPAでREST APIを実装する(インフラ層編)

Last updated at Posted at 2018-07-14

Spring Boot + MySQLでシンプルなWeb REST APIサーバを実装する - Qiita

Outline

以下の設計に従って、インフラ層を実装する。
Spring Bootで実装するWebAPIのアーキテクチャを考える - Qiita

以下の3クラスを作成する。

  • UserEntity.java
  • UserJpaRepository.java
  • UserRepository.java
├── infrastructure
│   ├── entity
│   │   └── UserEntity.java
│   └── repository
│       ├── UserJpaRepository.java
│       └── UserRepositoryImpl.java

UserEntity.java

MySQLのレコードがマッピングされるクラス。
Domain Object(User.java)と双方向に変換するメソッドを定義。

UserEntity.java
package com.example.springapi.infrastructure.entity;

import com.example.springapi.domain.object.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * RDBレコードのマッピング用クラス
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "test_users")
public class UserEntity {
    @Id
    @Column(name = "id")
    private String id;

    @Column(name = "value")
    private String value;

    /**
     * ドメインオブジェクトからインスタンスを生成
     *
     * @param user ドメインオブジェクト
     * @return UserEntity
     */
    public static UserEntity build(User user) {
        return UserEntity.builder()
                .id(user.getId())
                .value(user.getValue())
                .build();
    }

    /**
     * ドメインオブジェクトへ変換
     *
     * @return ドメインオブジェクト
     */
    public User toDomainUser() {
        return User.builder()
                .id(this.id)
                .value(this.value)
                .build();
    }
}

※ JPAアノテーション

@Entity

これでJPAのEntity(マッピングされるクラス)ってことを表現する。

@Table

テーブル名を指定する。

@id

プライマリキーであることを指定する。
複合キーの場合は書き方が変わる。

@Column

テーブルの列名を指定する。

※ Lombokアノテーション

@NoArgsConstructor

引数なしのコンストラクタを自動で作成する。
JPAのEntityのライフサイクル上、引数なしのコンストラクタが必要。
引数なしのコンストラクタが存在するような構成ならば不要。(finalなフィールドが無い場合など。@Builder使うなら絶対必要)

@AllArgsConstructor

すべてのフィールドを引数に取るコンストラクタを作成する。
NoArgsConstructorを指定した場合、こちらも指定しないと、@Builderが動かない(@Builderではすべてのフィールドを引数にとるコンストラクタを自動で生成するが、xxxArgsConstructorがついてるクラスに対しては、コンストラクタを作成しない。そして動かない。)

UserJpaRepository.java

JPAの実装を利用するために必要なインタフェース。
JpaRepositoryを継承し、Entityクラスと、プライマリキーの型を指定する。
実行時にはSimpleJpaRepositoryというspring-data-jpaが用意している標準実装がDIコンテナによって注入されるため、実装クラスを記述する必要はない。

UserJpaRepository.java
package com.example.springapi.infrastructure.repository;

import com.example.springapi.infrastructure.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * JPAを利用するためのインタフェース
 */
public interface UserJpaRepository extends JpaRepository<UserEntity, String> {
}

UserRepositoryImpl.java

ドメイン層で定義したUserRepositoryインタフェースの実装クラス。
実際の処理はSimpleJpaRepositoryが行う。

UserRepositoryImpl.java
package com.example.springapi.infrastructure.repository;

import com.example.springapi.domain.object.User;
import com.example.springapi.domain.repository.UserRepository;
import com.example.springapi.infrastructure.entity.UserEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.Optional;

/**
 * 永続化の実装クラス
 * ドメインオブジェクトをEntityに変換してJPAをラップする
 */
@Repository
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserRepository {

    @NonNull
    private final UserJpaRepository userJpaRepository;

    /**
     * {@inheritDoc}
     */
    @Override
    public Optional<User> findById(String id) {
        return this.userJpaRepository.findById(id)
                .map(UserEntity::toDomainUser);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public User save(User user) {
        return this.userJpaRepository.save(UserEntity.build(user))
                .toDomainUser();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void deleteById(String id) {
        this.userJpaRepository.deleteById(id);
    }
}

@Repository

@Compornentのエイリアス。
@Serviceと一緒。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
9