DTO 상속에 대하여

2024. 3. 14. 23:50자바/자바스프링

반응형

#1. 개요

  • API를 구현할 때 기획과 프론트엔드의 요구로 인해 기존 Dto에 property 가 하나씩 추가되어야할 때가 있다.
    • 호출되는 데이터의 DB 스키마가 변경되지 않더라도 말이다!
    • 처음에 기존 Dto에 계속 property 를 추가했더니 하나의 Dto가 너무 커지고, 여러 API에 쓰이기 시작했다. 결과적으로 스웨거에 스키마가 올라갔을 때, 각 API에서 안 쓰이는 property 가 많아졌다.
      • 이는 백엔드, 프론트엔드 양쪽에 다 여간 불편한 것이 아니었다.
    • 그렇기에 Dto를 여러 개로 나누려했다.
  • 그러나 나누려하는 이 Dto들은 결국 비슷한 정보를 리턴하기에, 겹치는 정보가 많았다. 그렇기에 아예 분리를 하기보다, 상속을 하는 것이 제일 좋은 판단이라고 생각했다.
    • 그리고 분류를 해보면 보통 같은 정보끼리 뭉치는 것을 확인했다.
      • Request Body 용 Dto / Response 용 Dto / 백엔드 내부 Dto
    • 그래서 각 DB 스키마와 제일 흡사한 정보를 제일 부모로 두고, 해당 부모를 상속받는 자식 Dto를 각각 return, request Dto 명칭을 두는 패턴을 만들었다.

#2. 코드

@Getter
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuDto {

	@Schema(description = "메뉴아이디")
	@JsonProperty("menuId")
	private Integer menuId;

	@Schema(description = "메뉴명")
	@JsonProperty("menuNm")
	private String menuNm;

	public MenuDto(Integer menuId, String menuNm) {
		this.menuId = menuId;
		this.menuNm = menuNm;
	}

	@Getter
	@SuperBuilder(toBuilder = true)
	@NoArgsConstructor
	@JsonInclude(JsonInclude.Include.NON_NULL)
	public static class MenuReturnDto extends MenuDto {

		@Schema(description = "리턴 쪽에만 추가되는 정보")
		@JsonProperty("returnExtraInfo")
		private String returnExtraInfo;

		public MenuReturnDto(Integer menuId, String menuNm, String returnExtraInfo) {
			super(menuId, menuNm);
			this.returnExtraInfo = returnExtraInfo;
		}
	}

	@Getter
	@SuperBuilder(toBuilder = true)
	@NoArgsConstructor
	@JsonInclude(JsonInclude.Include.NON_NULL)
	public static class MenuRequestDto extends MenuDto {

		@Schema(description = "요청 쪽에만 추가되는 정보")
		@JsonProperty("requestExtraInfo")
		private String requestExtraInfo;

		public MenuRequestDto(Integer menuId, String menuNm, String requestExtraInfo) {
			super(menuId, menuNm);
			this.requestExtraInfo = requestExtraInfo;
		}
	}

}

#3. 주의점

  • 만약 해당 상속 받는 Dto를 MyBatis Xml 에서 호출하여 매핑을 해주려면, 풀명칭을 써줘야한다.
<select id="getMenu" resultType="com.api.dto.menu.menuDto$menuReturnDto">
    SELECT *
    FROM menu
</select>
  • 또한 controller / service / repository 단에서도 부모의 이름부터 써줘야한다.
반응형