Red Glitter Pointer

 DAO (Data Access Object) 란?

repository package

  • repository와 거의 유사함
    • 좀 더 깊이있게 차이를 설명하자면, repository는 엔티티 객체를 보관하고 관리하는 저장소이고, DAO는 데이터에 접근하도록 DB 접근 관련 로직을 모아둔 객체이다. 개념 차이일뿐 실제 개발할 때는 비슷하게 사용한다.
  • DB의 데이터에 접근하기 위한 객체
    • DB에 접근하기 위한 로직을 분리하기 위해 사용한다
    • 직접 DB에 접근하여 data를 삽입, 삭제, 조회 등 조작할 수 있는 기능을 수행한다
  • Persistence Layer(DB에 data를 CRUD하는 계층)
  • Service와 DB를 연결하는 역할
  • SQL 사용(개발자가 직접 코딩)하여 DB에 접근한 후 적절한 CRUD API 제공
    • JPA 대부분의 기본적인 CRUD method를 제공하고 있따
    • extends JpaRepository<User, Long>
public interface ChattingLogRepository extends MongoRepository<ChattingLog, String> {
	
    public ChattingLog findAllByRoomIdx(Long roomIdx);
    
    public List<ChattingLog> findByRoomIdx(Long roomIdx);
}

 

 

 

 

 DTO(Data Transfer Object) 란?

dto package

  • 계층 간 데이터 교환을 위한 객체(Java Beans)
  • DB에서 데이터를 얻어 Service나 Controller 등으로 보낼 때 사용하는 객체를 말한다
  • DB의 데이터가 Presentation Logic Tier로 넘어오게 될 때는 DTO의 모습으로 바뀌어 오고가는 것임
  • 순수한 데이터 객체이다.
    • DTO는 목적 자체가 로직을 가지고 있지 않고 단순히 데이터를 전달하는 것
  • getter / setter 메소드만을 갖는다. 
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class UserDto {
  @NotBlank
  @Pattern(regexp = "^([\\w-]+(?:\\.[\\w-]+)*)@((?:[\\w-]+\\.)*\\w[\\w-]{0,66})\\.([a-z]{2,6}(?:\\.[a-z]{2})?)$")
  private String email;

  @JsonIgnore
  @NotBlank
  @Size(min = 4, max = 15)
  private String password;

  @NotBlank
  @Size(min = 6, max = 10)
  private String name;

  public User toEntity() {
      return new User(email, password, name);
  }

  public User toEntityWithPasswordEncode(PasswordEncoder bCryptPasswordEncoder) {
      return new User(email, bCryptPasswordEncoder.encode(password), name);
  }
}


// 출처
// https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html

 

 

 

 

 VO(Value Object) 란?

  • Read-Only 속성을 가진 값 오브젝트 이다.
  • 자바에서 단순히 값 타입을 표현하기 위해 불변 객체를 만들어 사용한다.
  • getter 기능만 존재함!
  • VO의 핵심 역할은 equals()와 hashcode()를 overriding 하는 것
    • equals, hashCode Method를 구현하여 중요한 Data를 전달할 때는 VO를 생성하여 객체 비교까지 필요한 로직 내에서 주로 사용한다. 
@Getter
public enum BaseResponseStatus {
    SUCCESS(true, 1000, "요청에 성공하였습니다."),

    REQUEST_ERROR(false, 2000, "입력값을 확인해주세요."),
    RESPONSE_ERROR(false, 3000, "값을 불러오는데 실패하였습니다."),
    DATABASE_ERROR(false, 4000, "데이터베이스 연결에 실패하였습니다.");
    
    private final boolean isSuccess;
    private final int code;
    private final String message;

    private BaseResponseStatus(boolean isSuccess, int code, String message) {
        this.isSuccess = isSuccess;
        this.code = code;
        this.message = message;
    }
}

✔️ 위 코드는 BaseResponseStatus라는 enum으로 요청의 상태를 저장한 enum이다. 즉, 값은 고정되어 있고 불변하는 클래스이다. 

 

💡 참고

VO는 DTO와 동일한 개념이지만, VO는 특정한 비즈니스 값을 담는 객체이고, DTO는 Layer간의 통신 용도로 오고가는 객체를 말한다.

 

 

 

 

 Entity Class 란?

domain package

  • 실제 DB의 테이블과 매칭될 클래스
    • 테이블과 링크될 클래스임을 나타낸다
    • Entity 클래스 또는 가장 Core한 클래스라고 부른다
    • @Entity, @Column, @Id 등을 이용한다
  • 최대한 외부에서 Entity 클래스의 getter method를 사용하지 않도록 해당 클래스 안에서 필요한 로직 method를 구현한다
    • 단, Domain Logic만 가지고 있어야 하고 Presentation Logic을 가지고 있어서는 안된다
    • 여기서 구현한 method는 주로 Service Layer에서 사용한다
💡 Entity 클래스와 DTO 클래스를 분리하는 이유

1. View Layer와 DB Layer의 역할을 철저하게 분리하기 위함
2. 테이블과 매핑되는 Entity 클래스가 변경되면 여러 클래스에 영향을 끼치게 되는 반면, View와 통신하는 DTO 클래스(Request / Response 클래스)는 자주 변경되므로 분리해야 한다.
3. Domain Model을 아무리 잘 설계했다고 하더라도 각 View 내에서 Domain Model의 getter만을 이용하여 원하는 정보를 표시하기가 어려운 경우가 있음. 이런 경우 Domain Model 내에 Presentation을 위한 필드나 로직을 추가하게 되는데, 이러한 방식이 모델링의 순수성을 깨고 Domain Model 객체를 망가뜨리게 된다.
4. Domain Model을 복잡하게 조합한 형태의 Presentation 요구사항들이 있기 때문에 Domain Model을 직접 사용하는 것은 어렵다. 
5. 즉 DTO는 Domain Model을 복사한 형태로, 다양한 Presentation Logic을 추가한 정도로 사용하며 Domain Model 객체는 Persistent만을 위해서 사용한다.

 

 

 

 

 전체 구조(package 기준)

 

 

 Controller(Web)

  • 기능
    • 해당 요청 url에 따라 적절한 view와 mapping 처리
    • @Autowired Service를 통해 service의 method를 이용
    • 적절한 ResponseEntity(DTO)를 body에 담아 Client에 반환
@Controller
@RequestMapping("/")
public class HomeController {
  @GetMapping
  public String home(HttpSession session) {
      if (!SessionUtil.getUser(session).isPresent()) {
          return "login";
      }
      return "index";
  }
}
  • ⬆️ @RestController
    • view가 필요없는 API만 지원하는 서비스에서 사용
    • @RequestMapping 메소드가 기본적으로 @ResponseBody 의미를 가정한다
    • data(json, xml 등) return이 주목적. return ResponseEntity
    • 즉, @RestController = @Controller + @ResponseBody

 

 

 

  Service

  • 기능
    • @Autowired Repository를 통해 repository의 method를 이용
    • 적절한 비즈니스 로직을 처리한다
    • DAO로 DB에 접근하고 DTO로 데이터를 전달받은 다음, 비즈니스 로직을 처리해 적절한 데이터 반환
@Service
public class UserService {
  @Autowired
  private UserRepository userRepository;
  @Resource(name = "bCryptPasswordEncoder")
  private PasswordEncoder bCryptPasswordEncoder;
  @Autowired
  private MessageSourceAccessor msa;

  public User save(UserDto userDto) {
      if (isExistUser(userDto.getEmail())) {
          throw new UserDuplicatedException(msa.getMessage("email.duplicate.message"));
      }
      return userRepository.save(userDto.toEntityWithPasswordEncode(bCryptPasswordEncoder);
  }
}

 

 

 

 

 

🌐 참고 링크

https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html

 

 

+ Recent posts

loading