ねこじゃすり
猫を魅了する魔法の装備品!
【最新機種】GoPro hero11 Black
最新機種でVlogの思い出を撮影しよう!
[ノースフェイス] THE NORTH FACE メンズ アウター マウンテンライトジャケット
防水暴風で耐久性抜群なので旅行で大活躍です!
ドラゴンクエスト メタリックモンスターズギャラリー メタルキング
みんな大好き経験値の塊をデスクに常備しておこう!
Bauhutte ( バウヒュッテ ) 昇降式 L字デスク ブラック BHD-670H-BK
メインデスクの横に置くのにぴったりなおしゃれな可動式ラック!
BANDAI SPIRITS ULTIMAGEAR 遊戯王 千年パズル 1/1スケール
もう一人の僕を呼び覚ませ!!
MOFT X 【新型 ミニマム版】 iPhone対応 スマホスタンド
Amazon一番人気のスマホスタンド!カード類も収納出来てかさ張らないのでオススメです!
スポンサーリンク
JPAを使ってみよう
O/R Mapperを使ってみよう
前回はFlywayを使ったDB構築の自動化についてご紹介しました。
今回はJPAを利用したデータベースからの参照処理のO/R Mappingを実装してみようと思います。
JPAとは?
JPAは正式にはJava Persistence APIと呼び、Java EE標準のO/R MappingおよびDAOの技術仕様の事を指します。
Java Persistence API(JPA)とは、関係データベースのデータを扱う Java SE および Java EE のアプリケーションを開発するためのJava用フレームワークである。
JPA は、以下の3つの部分から成る。
API(javax.persistence パッケージで定義されている)
Java Persistence Query Language
オブジェクト/関係メタデータJava Persistence API – Wikipedia
また、JPAはあくまで仕様なので実際にはEclipseLink,Hibernate ORM,Apache Open JPAなどのライブラリを使うことになると思います。
今回は、SpringBootでJPAを利用する際にデフォルトで仕様されるHibernateを使ってみようと思います。
手順
マッピングするテーブル構造
今回も前回作成したテーブル構造をベースにマッピングしていきます。
今回の目的は、ユーザー一覧を取得するためにマッピングテーブルであるcurrent_account_infomations
テーブルを軸に取得してこようと思います
今回利用するJPAアノテーション
JPAは基本的にアノテーションベースでマッピングの設定をしていきます。
今回登場するのは以下のアノテーションです。
アノテーション | 概要 |
---|---|
@Column( name = {カラム名} ) | フィールドにマッピングするDBのカラム名をname属性で設定する |
@Enumerated( EnumType.STRING ) | Enumにカラムをマッピングしたい場合に設定する |
@Entity | テーブルと対応するEntityクラスに設定する |
@Table( schema = {スキーマ名}, name = {テーブル名} ) | Entityクラスに紐付けたいテーブル情報を設定する |
@EmbeddedId | PKカラムを紐付けたいクラスを参照する際に設定する |
@Embedded | PKではないカラムを紐付けたいクラスを参照する際に設定する |
@OneToOne | 1…1のテーブルを結合したい際に設定する ※今回はテーブル定義情報は1..1~nだが、こちらを使うことでやりたいことは実現出来た |
@ManyToOne | N…0~1のテーブルを結合したい際に設定する |
@JoinColumn( name = {カラム名} ) | 結合する際のFKカラム名を指定したい場合に設定する |
@AttributeOverride(name = {上書き対象フィールド}, column = @Column(name = {上書き後の値} ) ) | 紐付けるEntity内のフィールドのカラム定義を上書きする ※今回のテーブル定義としては自テーブルと参照元によって同じコンテキストでも冗長的記述を端折るために異なるカラム名を付与しているので利用しています |
開発用afterMigrateデータ
今回はローカル開発動作確認用として、以下のデータを投入します。
期待値としてはマッピングテーブルを用いて(新)のものだけ取得出来ればOKです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
-- #################### -- # アカウント1 -- #################### INSERT INTO account.accounts ( id ) VALUES ( (SELECT nextval('account.account_id')) ); INSERT INTO account.account_infomations ( id, account_id, name, age, sex_type, display_name ) values ( (SELECT nextval('account.account_infomation_id')), (SELECT MAX(id) FROM account.accounts), '山田 太郎', 19, 'MALE', '山田 ローカル 太郎(古)' ); INSERT INTO account.account_infomations ( id, account_id, name, age, sex_type, display_name ) values ( (SELECT nextval('account.account_infomation_id')), (SELECT MAX(id) FROM account.accounts), '山田 太郎', 19, 'MALE', '山田 ローカル 太郎(新)' ); INSERT INTO account.current_account_infomations ( account_id, account_infomation_id ) values ( (SELECT MAX(id) FROM account.accounts), (SELECT MAX(id) FROM account.account_infomations) ); -- #################### -- # アカウント2 -- #################### INSERT INTO account.accounts ( id ) VALUES ( (SELECT nextval('account.account_id')) ); INSERT INTO account.account_infomations ( id, account_id, name, age, sex_type, display_name ) values ( (SELECT nextval('account.account_infomation_id')), (SELECT MAX(id) FROM account.accounts), '田中 花子', 20, 'FEMALE', '田中 ローカル 花子(古)' ); INSERT INTO account.account_infomations ( id, account_id, name, age, sex_type, display_name ) values ( (SELECT nextval('account.account_infomation_id')), (SELECT MAX(id) FROM account.accounts), '田中 花子', 20, 'FEMALE', '田中 ローカル 花子(新)' ); INSERT INTO account.current_account_infomations ( account_id, account_infomation_id ) values ( (SELECT MAX(id) FROM account.accounts), (SELECT MAX(id) FROM account.account_infomations) ); -- #################### -- # アカウント3 -- #################### INSERT INTO account.accounts ( id ) VALUES ( (SELECT nextval('account.account_id')) ); INSERT INTO account.account_infomations ( id, account_id, name, age, sex_type, display_name ) values ( (SELECT nextval('account.account_infomation_id')), (SELECT MAX(id) FROM account.accounts), '山田 二郎', 15, 'NONE', '山田 ローカル 二郎(古)' ); INSERT INTO account.account_infomations ( id, account_id, name, age, sex_type, display_name ) values ( (SELECT nextval('account.account_infomation_id')), (SELECT MAX(id) FROM account.accounts), '山田 二郎', 15, 'NONE', '山田 ローカル 二郎(新)' ); INSERT INTO account.current_account_infomations ( account_id, account_infomation_id ) values ( (SELECT MAX(id) FROM account.accounts), (SELECT MAX(id) FROM account.account_infomations) ); |
依存関係の追加
まずはgradleの依存関係にJPAを追加していきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
buildscript { apply from: 'property.gradle' ext { } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${accountService.springBootVersion}") classpath "org.yaml:snakeyaml:${accountService.snakeyamlVersion}" classpath "org.postgresql:postgresql:${accountService.postgresVersion}" } } allprojects { apply plugin: 'eclipse' } subprojects { apply plugin: "java" apply plugin: "io.spring.dependency-management" group = accountService.group version = accountService.version sourceCompatibility = accountService.sourceCompatibility repositories { mavenCentral() } dependencyManagement { } dependencies { implementation "org.springframework.boot:spring-boot-starter:${accountService.springBootVersion}" implementation "org.springframework.boot:spring-boot-starter-data-jpa:${accountService.springBootVersion}" // 追加 testImplementation "org.springframework.boot:spring-boot-starter-test:${accountService.springBootVersion}" } } |
Valueプロジェクトの修正
次にValueモデルを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package tech.blogenist.service.account.value.account; import java.io.Serializable; import javax.persistence.Column; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class AccountIdValue implements Serializable { public static final String LAVEL = "会員ID"; public static final String COLUMN_NAME = "id"; public static final String FK_COLUMN_NAME = "account_id"; @Column( name = COLUMN_NAME ) private Integer value; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package tech.blogenist.service.account.value.account; import java.io.Serializable; import javax.persistence.Column; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class AccountInfomationIdValue implements Serializable { public static final String LAVEL = "会員情報ID"; public static final String COLUMN_NAME = "id"; public static final String FK_COLUMN_NAME = "account_infomation_id"; @Column( name = COLUMN_NAME ) private Integer value; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package tech.blogenist.service.account.value.account; import javax.persistence.Column; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class AccountNameValue { public static final String LAVEL = "会員名"; public static final String COLUMN_NAME = "name"; @Column( name = COLUMN_NAME ) private String value; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package tech.blogenist.service.account.value.account; import javax.persistence.Column; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class AgeValue { public static final String LAVEL = "年齢"; public static final String COLUMN_NAME = "age"; @Column( name = COLUMN_NAME ) private Integer value; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package tech.blogenist.service.account.value.account; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.EnumType; import javax.persistence.Enumerated; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class SexTypeValue implements Serializable { public static final String LAVEL = "性別"; public static final String COLUMN_NAME = "type"; public static final String FK_COLUMN_NAME = "sex_type"; @Enumerated( EnumType.STRING ) @Column( name = COLUMN_NAME ) private Type type; @AllArgsConstructor public enum Type { NONE( "未設定" ), MALE( "男性" ), FEMALE( "女性" ); @Getter private String lavel; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package tech.blogenist.service.account.value.common.datetime; import java.time.LocalDateTime; import javax.persistence.Column; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class CommonCreatedAtValue { public static final String LAVEL = "作成日時"; public static final String COLUMN_NAME = "created_at"; @Column( name = COLUMN_NAME ) private LocalDateTime value; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package tech.blogenist.service.account.value.common.datetime; import java.time.LocalDateTime; import javax.persistence.Column; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class CommonUpdatedAtValue { public static final String LAVEL = "更新日時"; public static final String COLUMN_NAME = "updated_at"; @Column( name = COLUMN_NAME ) private LocalDateTime value; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package tech.blogenist.service.account.value.common.datetime; import javax.persistence.Column; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class MasterNameValue { public static final String LAVEL = "名称"; public static final String COLUMN_NAME = "name"; @Column( name = COLUMN_NAME ) private String value; } |
1 2 3 4 5 6 |
package tech.blogenist.service.account.value.infrastructure.field; public class ValueFieldConst { public static final String FIELD = "value"; } |
Entityプロジェクトの修正
次にEntityモデルを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package tech.blogenist.service.account.entity.db.account; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import tech.blogenist.service.account.value.account.AccountIdValue; import tech.blogenist.service.account.value.common.datetime.CommonCreatedAtValue; import tech.blogenist.service.account.value.common.datetime.CommonUpdatedAtValue; @Builder @Entity @Table( schema = AccountsTableEntity.SCHEMA_NAME, name = AccountsTableEntity.TABLE_NAME ) @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class AccountsTableEntity { public static final String SCHEMA_NAME = "account"; public static final String TABLE_NAME = "accounts"; @EmbeddedId private AccountIdValue accountId; @Embedded private CommonCreatedAtValue createdAt; @Embedded private CommonUpdatedAtValue updatedAt; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
package tech.blogenist.service.account.entity.db.account; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import tech.blogenist.service.account.value.account.AccountDisplayNameValue; import tech.blogenist.service.account.value.account.AccountIdValue; import tech.blogenist.service.account.value.account.AccountInfomationIdValue; import tech.blogenist.service.account.value.account.AccountNameValue; import tech.blogenist.service.account.value.account.AgeValue; import tech.blogenist.service.account.value.account.SexTypeValue; import tech.blogenist.service.account.value.common.datetime.CommonCreatedAtValue; import tech.blogenist.service.account.value.common.datetime.CommonUpdatedAtValue; @Builder @Entity @Table( schema = AccountInfomationsTableEntity.SCHEMA_NAME, name = AccountInfomationsTableEntity.TABLE_NAME ) @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class AccountInfomationsTableEntity { public static final String SCHEMA_NAME = "account"; public static final String TABLE_NAME = "account_infomations"; @EmbeddedId private AccountInfomationIdValue accountInfomationId; @ManyToOne @JoinColumn( name = AccountIdValue.FK_COLUMN_NAME ) private AccountsTableEntity accountEntity; @Embedded private AccountNameValue name; @Embedded private AgeValue age; @ManyToOne @JoinColumn( name = SexTypeValue.FK_COLUMN_NAME ) private SexTypesTableEntity sexType; @Embedded private AccountDisplayNameValue displayName; @Embedded private CommonCreatedAtValue createdAt; @Embedded private CommonUpdatedAtValue updatedAt; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
package tech.blogenist.service.account.entity.db.account; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import tech.blogenist.service.account.value.account.SexTypeValue; import tech.blogenist.service.account.value.common.datetime.MasterNameValue; @Builder @Entity @Table( schema = SexTypesTableEntity.SCHEMA_NAME, name = SexTypesTableEntity.TABLE_NAME ) @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class SexTypesTableEntity { public static final String SCHEMA_NAME = "account"; public static final String TABLE_NAME = "sex_types"; @EmbeddedId private SexTypeValue type; @Embedded private MasterNameValue name; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package tech.blogenist.service.account.entity.db.account; import javax.persistence.AttributeOverride; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import tech.blogenist.service.account.value.account.AccountIdValue; import tech.blogenist.service.account.value.account.AccountInfomationIdValue; import tech.blogenist.service.account.value.common.datetime.CommonCreatedAtValue; import tech.blogenist.service.account.value.common.datetime.CommonUpdatedAtValue; import tech.blogenist.service.account.value.infrastructure.field.ValueFieldConst; @Builder @Entity @Table( schema = CurrentAccountInfomationsTableEntity.SCHEMA_NAME, name = CurrentAccountInfomationsTableEntity.TABLE_NAME ) @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class CurrentAccountInfomationsTableEntity { public static final String SCHEMA_NAME = "account"; public static final String TABLE_NAME = "current_account_infomations"; @AttributeOverride( name = ValueFieldConst.FIELD, column = @Column( name = AccountIdValue.FK_COLUMN_NAME ) ) @EmbeddedId private AccountIdValue accountId; @OneToOne @JoinColumn( name = AccountInfomationIdValue.FK_COLUMN_NAME, referencedColumnName = AccountInfomationIdValue.COLUMN_NAME ) private AccountInfomationsTableEntity accountInfomations; @Embedded private CommonCreatedAtValue createdAt; @Embedded private CommonUpdatedAtValue updatedAt; } |
Datasourceプロジェクトの修正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package tech.blogenist.service.account.datasource.db.current_account.account_infomations; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import tech.blogenist.service.account.entity.db.account.CurrentAccountInfomationsTableEntity; import tech.blogenist.service.account.value.account.AccountIdValue; @Repository public interface CurrentAccountInfomationsRepository extends JpaRepository< CurrentAccountInfomationsTableEntity, AccountIdValue > { public List< CurrentAccountInfomationsTableEntity > findAll(); } |
APIプロジェクトの修正
modelパッケージ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package tech.blogenist.service.account.api.model.account.listing.response; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import tech.blogenist.service.account.value.account.AccountDisplayNameValue; import tech.blogenist.service.account.value.account.AccountIdValue; import tech.blogenist.service.account.value.account.AccountInfomationIdValue; import tech.blogenist.service.account.value.account.AccountNameValue; import tech.blogenist.service.account.value.account.AgeValue; import tech.blogenist.service.account.value.common.datetime.MasterNameValue; @Builder @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class AccountListingElementModel { private AccountIdValue accountId; private AccountInfomationIdValue accountInfomationId; private AccountNameValue name; private AgeValue age; private MasterNameValue sex; private AccountDisplayNameValue displayName; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package tech.blogenist.service.account.api.model.account.listing.response; import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Builder @AllArgsConstructor( staticName = "of" ) @NoArgsConstructor( staticName = "empty" ) @Data public class AccountListingResponseModel { private List< AccountListingElementModel > accounts; } |
serviceパッケージ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package tech.blogenist.service.account.api.service.account.listing; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import tech.blogenist.service.account.api.model.account.listing.response.AccountListingElementModel; import tech.blogenist.service.account.api.model.account.listing.response.AccountListingResponseModel; import tech.blogenist.service.account.datasource.db.current_account.account_infomations.CurrentAccountInfomationsRepository; import tech.blogenist.service.account.entity.db.account.AccountInfomationsTableEntity; import tech.blogenist.service.account.entity.db.account.CurrentAccountInfomationsTableEntity; import tech.blogenist.service.account.value.common.datetime.MasterNameValue; @Service public class AccountListingService { @Autowired private CurrentAccountInfomationsRepository currentAccountInfomationsRepository; public AccountListingResponseModel listing() { List< CurrentAccountInfomationsTableEntity > entities = currentAccountInfomationsRepository.findAll(); List< AccountListingElementModel > elements = entities.stream() .map( entity -> { AccountInfomationsTableEntity infomation = entity.getAccountInfomations(); AccountListingElementModel element = AccountListingElementModel.builder() .accountInfomationId( infomation.getId() ) .accountId( entity.getAccountId() ) .age( infomation.getAge() ) .name( infomation.getName() ) .sex( infomation.getSexType() == null ? MasterNameValue.empty() : infomation.getSexType().getName() ) .displayName( infomation.getDisplayName() ) .build(); return element; } ) .collect( Collectors.toList() ); return AccountListingResponseModel.of( elements ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package tech.blogenist.service.account.api.service.account.detail; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import tech.blogenist.service.account.api.model.account.detail.response.AccountDetailResponseModel; import tech.blogenist.service.account.datasource.db.current_account.account_infomations.CurrentAccountInfomationsRepository; import tech.blogenist.service.account.entity.db.account.CurrentAccountInfomationsTableEntity; import tech.blogenist.service.account.value.account.AccountIdValue; @Service public class AccountDetailService { @Autowired private CurrentAccountInfomationsRepository currentAccountInfomationsRepository; public AccountDetailResponseModel findBy( AccountIdValue id ) { CurrentAccountInfomationsTableEntity entity = currentAccountInfomationsRepository .findByAccountId( id ); return AccountDetailResponseModel.builder() .accountId( entity.getAccountId() ) .accountInfomationId( entity.getAccountInfomations().getId() ) .name( entity.getAccountInfomations().getName() ) .age( entity.getAccountInfomations().getAge() ) .displayName( entity.getAccountInfomations().getDisplayName() ) .sex( entity.getAccountInfomations().getSexType().getName() ) .build(); } } |
apiパッケージ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package tech.blogenist.service.account.api.controller.account.listing; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import tech.blogenist.service.account.api.infrastructure.rest.path.RestPathConst; import tech.blogenist.service.account.api.model.account.listing.response.AccountListingResponseModel; import tech.blogenist.service.account.api.service.account.listing.AccountListingService; @RestController @RequestMapping( RestPathConst.VersionPath.V1 + RestPathConst.CategoryPath.AccountPath.BASE_PATH ) public class AccountListingController { @Autowired private AccountListingService service; @GetMapping public AccountListingResponseModel listing() { AccountListingResponseModel response = service.listing(); return response; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package tech.blogenist.service.account.api.controller.account.detail; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import tech.blogenist.service.account.api.infrastructure.rest.path.RestPathConst; import tech.blogenist.service.account.api.model.account.detail.response.AccountDetailResponseModel; import tech.blogenist.service.account.api.service.account.detail.AccountDetailService; import tech.blogenist.service.account.value.account.AccountIdValue; @RestController @RequestMapping( RestPathConst.VersionPath.V1 + RestPathConst.CategoryPath.AccountPath.BASE_PATH ) public class AccountDetailController { @Autowired private AccountDetailService service; @GetMapping( path = RestPathConst.CategoryPath.AccountPath.RESOURCE_PATH ) public AccountDetailResponseModel detail( @PathVariable( RestPathConst.CategoryPath.AccountPath.PATH_VARIABLE ) Integer accountId ) { AccountDetailResponseModel response = service.findBy( AccountIdValue.of( accountId ) ); return response; } } |
動作確認
では、実際にエンドポイントを叩いてみましょう!
一覧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
{ "accounts": [ { "accountId": { "value": 10001 }, "accountInfomationId": { "value": 20002 }, "name": { "value": "山田 太郎" }, "age": { "value": 19 }, "sex": { "value": "男性" }, "displayName": { "value": "山田 ローカル 太郎(新)" } }, { "accountId": { "value": 10002 }, "accountInfomationId": { "value": 20004 }, "name": { "value": "田中 花子" }, "age": { "value": 20 }, "sex": { "value": "女性" }, "displayName": { "value": "田中 ローカル 花子(新)" } }, { "accountId": { "value": 10003 }, "accountInfomationId": { "value": 20006 }, "name": { "value": "山田 二郎" }, "age": { "value": 15 }, "sex": { "value": "未設定" }, "displayName": { "value": "山田 ローカル 二郎(新)" } } ] } |
詳細
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "accountId": { "value": 10001 }, "accountInfomationId": { "value": 20002 }, "name": { "value": "山田 太郎" }, "age": { "value": 19 }, "sex": { "value": "男性" }, "displayName": { "value": "山田 ローカル 太郎(新)" } } |
無事にテーブル結合が行われて、複数テーブルのデータをレスポンスモデルに変換して取得することが出来ました♪
参考
終わりに
以上のように、JPAの仕組みやマッピング方法や結合方法さえわかれば、SQLを書くことなくデータの取得が可能になります。
他にもJPAには便利な機能が搭載されていますので、是非使ってみてください♪