자바
객체관련
。대표적으로POJO,Java Bean,Spring Bean이 존재
Spring Bean
POJO( Plain Old Java Object )
。 특정 기술 (ex : Framework )에 종속되어있지않은 상태인 순수한자바객체
▶DTO,VO등의 경우도POJO
▶Spring Bean에 등록되지 않은자바객체를POJO라고 간주할 수 있다.
。EJB에 종속된 무거운자바 객체를 생성하는것에 반발하여 도출된 용어
。Spring Framework에서Spring Context에 의해 관리되는 경우Spring Bean이고 관리되지않는 경우POJO
Java Bean
。EJB에 의한 제약조건이 부여된자바객체
▶Java BeanPOJO
Java Bean특징class JavaBean implements Serializable { private int age; public JavaBean(){} public int getAge(){ return this.age; } public void setAge(int a){ this.age = a; } }。 모든
필드는private로 구성되며 오직메소드로서getter&setter로 접근 가능
▶캡슐화
。인자가 없는기본생성자만 가진다.
。Serializable interface를 상속하여 전송용도로 활용할 수 있음
EJB( Jarkata Enterprise Beans )
。서버측 어플리케이션의생산성향상과이동성을 실현하기 위해 제작한 규격.
▶ 기업환경의 시스템을 구현하기 위한Server측의Component 모델
Serializable 인터페이스:java.io.Serializable
。객체를직렬화(Selialization)하는 용도의인터페이스
▶ 해당인터페이스를 상속하여 네트워크를 통해 객체를 전송하거나 (Web API) ,객체를파일이나DB에 저장 시 활용
。해당인터페이스에는객체를이진데이터(ByteStream)으로직렬화하거나역직렬화하는 기능을 정의
▶Byte Stream:데이터를Byte단위로 input , output 할 수 있는Stream 객체
직렬화(Serialization) :
。객체를Byte Stream으로 변환하여파일에 저장하거나네트워크를 통해 전송할 수 있도록 하는 과정
역직렬화(Deserialization) :
。Byte Stream을객체로 변환하는 과정.
Persistence Layer의Java Bean 객체
。DAO,DTO,VO
DAO( Data Access Object ) :
。DB의 데이터로 접근하는Transaction Object로서,DB의 데이터를 조회하거나 조작하는 기능을 수행하는 객체.
。Spring은JdbcTemplate,JPA와 같은 DB와CRUD하는 기능을 제공하는Repository Class를 선언 및Spring Bean으로 생성하여DB와의CRUD를 수행하는DAO로서 작용하도록 설정.
VO( Value Object )
。DTO와 달리Getter만 제공하는 간단한 형태의POJO
▶도메인 객체( =Business Model) 또는JPA의DB Entity를 선언 시 활용@Getter @NoArgsConstructor @AllArgsConstructor @Entity // 도메인 객체와 DB Entity 역할을 동시에 수행 public class Member { @Id private Long id; // 유저로 부터 받는 부분 private String loginId; private String password; private String name; private String email; private String mobile; private Gender gender; private LocalDate birthday; private LocalDateTime createdAt; private LocalDateTime updatedAt; }▶
도메인및DB Entity역할을 동시에 수행하는클래스
DTO( Data Transfer Object )
。계층( 레이어 )간 데이터 교환에서 데이터를 전송하는 객체를 의미하는POJO
。 순전히 데이터를 저장 및 회수하는 기능을 제외하고 아무 기능을 가지고 있지 않음.
▶Getter,SetterMethod만 포함하고있는 순수한 Class.
。1계층간 전달용도로 사용되야하며2계층이상으로 동일한DTO가 전달되는것은 지양해야하나,팀원간의 협의에 따라 전달되는 경우도 존재.
ex )@Controller에서@RequestBody를 통해매핑되어 수신한DTO를@Service Class의메서드까지 전달하여 사용
。Record로DTO를 선언하여불변객체를 통해 데이터전송을 수행하여불변성을 보장가능
▶ 해당DTO의 값재할당을 금지하고 읽기만 가능
。주로API 요청/응답에서Message Body를 바인딩하여데이터를 전달하는 용도로 사용
▶DTO 객체는@ResponseBody의JacksonMessageConverter를 통해JSON으로 변환되어Http Body에 적재하기 적합
DTO에Spring Bean을 사용하지 못하는 이유
。Spring Bean은 기본적으로싱글톤패턴이므로데이터 전달용도로는 부적합
DTO를 선언하는 3가지 방법
- 1.
기능별로요청과응답의DTO를 각각 생성
。불변을 위해 주로Record로 선언// Bean에 대해 Validation 을 수행 public record MemberCreateRequest( @NotBlank String loginId, // 최소 8자 이상 대문자 소문자 숫자 특수문자 포함 @NotBlank @Pattern(regexp="^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^])[A-Za-z\\d!@#$%^]{8,}$") String password, @NotBlank String name, @NotBlank @Pattern(regexp="^[0-9A-Za-z._%+-]+@[0-9A-Za-z.-]+\\.[A-Za-z]{2,6}$") String email, @NotBlank @Pattern(regexp="^(0\\d{1,2})-(\\d{3,4})-(\\d{4})$") String mobile, @NotNull Gender gender, @NotNull LocalDate birthday ) { }。
Member를 생성하는기능의요청에 사용되는DTO
- 2.
요청 / 응답을 각각클래스로 분할 및기능 별 DTO를Record또는Static Nested Class로 구현
。Nested Class의 경우에도 기본적으로default로 설정되어있으므로 다른패키지의클래스에서DTO로서 사용 할 수 있으므로public으로 명시적으로 선언
。Swagger를 통한API 문서화를 수행하는 경우API 문서에서 동일한 명칭의DTO간 충돌이 발생할 수 있으므로@Schema(name = "API 문서내 이름")으로 별칭을 부여해야한다.public class ProductRequest { @Schema(name = "ProductReqpuest.Create") public record Create( @NotBlank String name, @NotNull Long price, @NotNull Long quantity ){} @Getter @AllArgsConstructor @Schema(name = "ProductReqpuest.Update") public static class Update{ @NotBlank private String name; @NotNull private Long price; @NotNull private Long quantity; } }。
요청의DTO를 포함하는 역할의클래스내 각기능별 DTO를 구현@PostMapping @ResponseStatus(HttpStatus.CREATED) public void create(@RequestBody @Valid ProductRequest.Create request){ productService.create( request.getName(), request.getPrice(), request.getQuantity() ); }▶ 사용하는쪽은 다음처럼
클래스.중첩클래스명로서Type을 선언하여 사용
- 3.
요청 / 응답을 각각인터페이스로 분할 및기능 별 DTO를Record또는Class로 내부에 구현
。인터페이스내부에DTO로 활용할Record또는클래스를 정의public interface MemberResponse { @Schema(name = "ProductReqpuest.Details") record Details( String loginId, String name, String email ){ // 정적 팩토리 메서드 public static Details of(MemberEntity memberEntity){ return new Details( memberEntity.getLoginId(), memberEntity.getName(), memberEntity.getEmail() ); } } }▶
클라이언트에게DB Entity 객체반환 시연관관계 객체등 모든field를 포함해서 반환하면 안되므로정적 팩토리 메서드를 통해DTO를 생성하여 반환
。사용하는 쪽은인터페이스명.내부클래스로Data Type으로 설정하여 사용