1.目的
SpringBootのAPIにおいて、DBから取得した内容をModelに設定した後に、レスポンスに返す前にDTOへ設定する際の方法について残します。
2.環境
eclipse(Version: 2022-12 (4.26.0))
java(ver.17)
spring boot 3.1.1
Gradle - Groovy
mysql(Ver 8.0.33)
3.事前準備
(1) MapStructを紐付ける土台となるファイルを用意します。
※これを用意しないと実際のMappingがうまくいかない。
配置場所はプロジェクト直下や問わない。
package com.talent.setting;
import org.mapstruct.MapperConfig;
import org.mapstruct.NullValueMappingStrategy;
import org.mapstruct.ReportingPolicy;
/**
* MapStruct設定用
*/
@MapperConfig(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE,
nullValueMappingStrategy = NullValueMappingStrategy.RETURN_NULL)
public interface ConfigMapper {
}
(2) DBの結果や値の設定が格納されているModelを準備します。
※以下は、
前回記事「MyBatisGeneratorを用いて、Model・Mapperの作成」で作成したものと同様。
(https://qiita.com/yu-F/items/a612dc9b0ee4008c8b31)
package com.model;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Generated;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
/**
* オンエア管理テーブル情報(全列)
*/
@Schema(name = "tOnAirKanri", description = "オンエア管理テーブル情報(全列)")
@JsonTypeName("tOnAirKanri")
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2023-06-12T21:30:49.581521+09:00[Asia/Tokyo]")
public class TOnAirKanri {
@JsonProperty("id")
private String id;
@JsonProperty("onairDay")
private String onairDay;
@JsonProperty("programId")
private String programId;
@JsonProperty("talentId")
private String talentId;
@JsonProperty("targetNentsuki")
private Integer targetNentsuki;
@JsonProperty("targetShu")
private Integer targetShu;
@JsonProperty("deleteFlg")
private Integer deleteFlg;
@JsonProperty("torokuDay")
private String torokuDay;
@JsonProperty("koushinDay")
private String koushinDay;
public TOnAirKanri id(String id) {
this.id = id;
return this;
}
/**
* ID
* @return id
*/
@Size(max = 8)
@Schema(name = "id", description = "ID", required = false)
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public TOnAirKanri onairDay(String onairDay) {
this.onairDay = onairDay;
return this;
}
/**
* オンエア日
* @return onairDay
*/
@Valid
@Schema(name = "onairDay", description = "オンエア日", required = false)
public String getonairDay() {
return onairDay;
}
public void setonairDay(String onairDay) {
this.onairDay = onairDay;
}
public TOnAirKanri programId(String programId) {
this.programId = programId;
return this;
}
/**
* 番組ID
* @return programId
*/
@NotNull @Size(max = 8)
@Schema(name = "programId", description = "番組ID", required = true)
public String getProgramId() {
return programId;
}
public void setProgramId(String programId) {
this.programId = programId;
}
public TOnAirKanri talentId(String talentId) {
this.talentId = talentId;
return this;
}
/**
* タレントID
* @return talentId
*/
@Size(max = 8)
@Schema(name = "talentId", description = "タレントID", required = false)
public String getTalentId() {
return talentId;
}
public void setTalentId(String talentId) {
this.talentId = talentId;
}
public TOnAirKanri targetNentsuki(Integer targetNentsuki) {
this.targetNentsuki = targetNentsuki;
return this;
}
/**
* 対象年月
* minimum: 1990
* maximum: 2100
* @return targetNentsuki
*/
@Min(1990) @Max(2100)
@Schema(name = "targetNentsuki", description = "対象年月", required = false)
public Integer getTargetNentsuki() {
return targetNentsuki;
}
public void setTargetNentsuki(Integer targetNentsuki) {
this.targetNentsuki = targetNentsuki;
}
public TOnAirKanri targetShu(Integer targetShu) {
this.targetShu = targetShu;
return this;
}
/**
* 対象週
* minimum: 1
* maximum: 5
* @return targetShu
*/
@Min(1) @Max(5)
@Schema(name = "targetShu", description = "対象週", required = false)
public Integer getTargetShu() {
return targetShu;
}
public void setTargetShu(Integer targetShu) {
this.targetShu = targetShu;
}
public TOnAirKanri deleteFlg(Integer deleteFlg) {
this.deleteFlg = deleteFlg;
return this;
}
/**
* 論理削除フラグ
* minimum: 0
* maximum: 9
* @return deleteFlg
*/
@Min(0) @Max(9)
@Schema(name = "deleteFlg", description = "論理削除フラグ", required = false)
public Integer getDeleteFlg() {
return deleteFlg;
}
public void setDeleteFlg(Integer deleteFlg) {
this.deleteFlg = deleteFlg;
}
public TOnAirKanri torokuDay(String torokuDay) {
this.torokuDay = torokuDay;
return this;
}
/**
* 登録日
* @return torokuDay
*/
@Schema(name = "torokuDay", description = "登録日", required = false)
public String getTorokuDay() {
return torokuDay;
}
public void setTorokuDay(String torokuDay) {
this.torokuDay = torokuDay;
}
public TOnAirKanri koushinDay(String koushinDay) {
this.koushinDay = koushinDay;
return this;
}
/**
* 更新日
* @return koushinDay
*/
@Schema(name = "koushinDay", description = "更新日", required = false)
public String getKoushinDay() {
return koushinDay;
}
public void setKoushinDay(String koushinDay) {
this.koushinDay = koushinDay;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TOnAirKanri tOnAirKanri = (TOnAirKanri) o;
return Objects.equals(this.id, tOnAirKanri.id) &&
Objects.equals(this.onairDay, tOnAirKanri.onairDay) &&
Objects.equals(this.programId, tOnAirKanri.programId) &&
Objects.equals(this.talentId, tOnAirKanri.talentId) &&
Objects.equals(this.targetNentsuki, tOnAirKanri.targetNentsuki) &&
Objects.equals(this.targetShu, tOnAirKanri.targetShu) &&
Objects.equals(this.deleteFlg, tOnAirKanri.deleteFlg) &&
Objects.equals(this.torokuDay, tOnAirKanri.torokuDay) &&
Objects.equals(this.koushinDay, tOnAirKanri.koushinDay);
}
@Override
public int hashCode() {
return Objects.hash(id, onairDay, programId, talentId, targetNentsuki, targetShu, deleteFlg, torokuDay, koushinDay);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class TOnAirKanri {\n");
sb.append(" id: ").append(toIndentedString(id)).append("\n");
sb.append(" onairDay: ").append(toIndentedString(onairDay)).append("\n");
sb.append(" programId: ").append(toIndentedString(programId)).append("\n");
sb.append(" talentId: ").append(toIndentedString(talentId)).append("\n");
sb.append(" targetNentsuki: ").append(toIndentedString(targetNentsuki)).append("\n");
sb.append(" targetShu: ").append(toIndentedString(targetShu)).append("\n");
sb.append(" deleteFlg: ").append(toIndentedString(deleteFlg)).append("\n");
sb.append(" torokuDay: ").append(toIndentedString(torokuDay)).append("\n");
sb.append(" koushinDay: ").append(toIndentedString(koushinDay)).append("\n");
sb.append("}");
return sb.toString();
}
/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private String toIndentedString(Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
}
(3) (2)の戻りの値を格納したいDTOを用意します。
※(2)の内容とは異なるフィールドで用意。
package com.talent.service.dto;
import java.io.Serializable;
import com.talent.service.dto.entity.Talent;
import com.talent.service.dto.entity.TvProgram;
import lombok.Data;
/**
* オンエア管理情報DTO
*/
@Data
public class OnAirKanriInfoDto implements Serializable {
private String id;
private Talent talent;
private TvProgram tvProgram;
private Integer nentsuki;
private Integer shu;
}
(4) (2)と(3)の内容を紐付け用のメソッド定義を用意。
※今回は、Helperクラスに定義を記載する。
package com.talent.service.helper;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import com.model.TOnAirKanri;
import com.talent.service.dto.OnAirKanriInfoDto;
import com.talent.setting.ConfigMapper;
@Mapper(config = ConfigMapper.class)
public interface ShukanTalentJohoBffHelper {
@Mapping(source = "model.talentId", target = "talent.id")
@Mapping(source = "talentNm", target = "talent.name")
@Mapping(source = "model.programId", target = "tvProgram.id")
@Mapping(source = "programNm", target = "tvProgram.name")
@Mapping(source = "model.onairDay", target = "tvProgram.onairDay")
OnAirKanriInfoDto toOnairKanriInfoDto(TOnAirKanri model);
}
メソッド定義は、
→「 【対象のDTO】メソッド名(【元となるModel】別名);」
元となるModelのプロパティ名と対象のDTOのプロパティ名が異なる場合は、
「@Mapping(source = "【元となるModel.プロパティ名】", target = "【対象のDTO.プロパティ名】")
上記の定義をメソッドの上に用意する。
※DTOの内部のプロパティとModelの内部のプロパティ名が全く同様、ないしは値ごとに設定が無くても問題ない場合は、「@Mapping」は不要となる。(NULLで設定されたりする)
4.まとめ
MapStructはMybatisにおいては使用する機会が多く、一括で値が設定できるため、便利のため、使えるようになると簡潔にかけるようになります。