Spring Boot를 활용한 첫 프로젝트를 완성했습니다.
아직 부족한 부분이 많지만 고치다 보면 완성이 계속 미뤄질 거 같더라고요😥
추후 리팩토링을 위해 프로젝트를 다시 보며 든 궁금증이 생겼습니다.
어떠한 구조가 최고의 프로젝트 구조일까?
controller, service, dto, dao, repository 등
spring boot 프로젝트를 위해 필요한 요소들은 꽤 다양합니다.
이 요소들에 대해 살펴보고 최고의 프로젝트 구조란 무엇일지
포스팅해보려 합니다🤩
MVC 패턴을 전제로 합니다.
잘못된 정보가 있다면 댓글로 꼭 알려주세요!
1. 필요한 요소들
1) Entity (Domain)
실제 DB 테이블과 매핑되는 요소이다.
하나의 객체가 DB의 하나의 Column처럼 작용한다.
// Entity 예시 코드
@Entity
@Getter
@Table(name = "COMMENT")
public class CommentEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String commentContents;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id")
private BoardEntity boardEntity;
}
2) Repository
Entity에 의해 생성된 DB에 접근하기 위한 인터페이스이다.
직접 쿼리문을 작성하기도 하고 JPA를 사용하여 보다 쉽게 접근하기도 한다.
// Repository 예시 코드 - JPA 사용
public interface CommentRepository extends JpaRepository<CommentEntity, Long> {
// 해당 게시물에 댓글 오름차순 조회
List<CommentEntity> findAllByBoardEntityOrderByIdAsc(BoardEntity boardEntity);
}
3) DAO
실제로 DB에 접근하는 객체입니다.
Repositoy와 거의 같지만 동일한 것은 아니다.
- Repository는 Entity 객체를 보관하고 있는 저장소
- DAO는 데이터에 접근하도록 DB 접근 관련 로직을 모아둔 객체
개념은 엄연히 다르지만 개발할 때에는 비슷하게 사용된다.
출처) 인프런 김영한님 답변
4) Mapper
Repository에 포함되는 개념이다.
000.xml과 같이 SQL문을 정의해놓은 파일로 사용한다.
정의해놓은 SQL과 개발할 때 사용하는 메소드를 연결하여 나온 결과값을
정의해놓은 타입으로 mappig 시켜준다.
5) DTO
Controller, Service, Repository 등
계층 간 데이터 교환을 할 때의 Entity로 통신하는 것은
보안에 좋지 못하기 때문에 DTO를 사용한다.
// DTO 예시 코드
@Getter
@Setter
@ToString
public class CommentDTO {
private Long id;
private String commentWriter;
private String commentContents;
private Long boardId;
private LocalDateTime commentCreatedTime;
}
6) VO
DTO와의 차이점은 Read-Only라는 것이다.
DTO과 getter, setter가 있다면 VO는 getter만 있다.
7) Service
DAO 혹은 Repository에서 받아온 데이터를 받아 가공한다.
// Service 예시 코드
@Service
@Transactional
@RequiredArgsConstructor
public class CommentService {
private final UserRepository userRepository;
private final BoardRepository boardRepository;
private final CommentRepository commentRepository;
// 댓글 조회
public List<CommentDTO> findCommentAll(Long boardId) {
BoardEntity boardEntity = boardRepository.findById(boardId).get();
List<CommentEntity> commentEntityList = commentRepository.findAllByBoardEntityOrderByIdAsc(boardEntity);
List<CommentDTO> commentDTOList = new ArrayList<>();
for(CommentEntity commentEntity : commentEntityList){
CommentDTO commentDTO = CommentDTO.toCommentDTO(commentEntity);
commentDTOList.add(commentDTO);
}
return commentDTOList;
}
}
7) ServiceImpl
이 요소를 프로젝트에 둘 경우 Service는 인터페이스, ServiceImpl은 구현체가 된다.
다형성과 OCP를 지키는 구조가 되기 때문에 코드의 수정이 용이하다.
개인적으로 1:1로 매핑되는 인터페이스 - 구현체 구조가 과연 필요할까라는 의구심이 듭니다. 인터페이스의 존재 이유가 하나의 존재로 여러 역할을 내 입맛대로 쓰기 위한 것이니까요.
8) Controller
비즈니스 로직이 있는 서비스를 호출한다.
- Controller : 주로 View를 반환하기 위해 사용한다.
- RestController : @Controller + @ResponseBody가 합쳐진 것으로 Json형태의 데이터를 반환하기 위해 사용한다.
// Controller 예시 코드
@Controller
@RequiredArgsConstructor
public class UserController {
// 로그인
@GetMapping("/login")
public String loginForm(@RequestParam(value="error", required = false) String error,
@RequestParam(value = "exception", required = false) String exception,
Model model){
model.addAttribute("error", error);
model.addAttribute("exception", exception);
return "user/info/login";
}
}
2. 최고의 프로젝트 구조
전 controller - service - dto - repository - entity 구조를 사용했습니다.
repository 대신 dao를 사용할 수도 있고
service를 인터페이스로 두고 serviceImpl을 둘 수도 있고
restcontroller와 controller를 따로 둘수도 있고..정말 다양한 구조가 나올 수 있습니다.
최고의 프로젝트 구조..그런 건 없습니다
허무하시죠?
프로젝트의 상황과 규모 등에 따라 그에 맞는 프로젝트 구조를 만들 수 있는 것이 가장 중요한 것 같습니다.
확장 가능성이 있다면 service와 serviceImpl을 두고
restful api가 많다면 restcontroller와 controller로 나누는 등으로요.
또 기능에 따라 폴더를 나누고 controller, dto, entity 넣을 수도 있고
controller, dto, entity 안에 기능별로 나눌 수도 있겠죠.
상황에 따라 유동적으로 구조를 바꿀 수 있는 능력이 될 때까지 계속 공부하며 발전해나가봅시다!
출처) 인프런 김영한님 답변
'JAVA > [개인프로젝트] GooGoo' 카테고리의 다른 글
JDBC, JPA, Spring Data JPA 차이 그리고 Hibernate와 ORM (0) | 2023.10.13 |
---|---|
CSR VS SSR (0) | 2023.09.10 |
[Spring Security] 일반 로그인과 소셜 로그인 (oauth2) 그리고 JWT (0) | 2023.09.06 |
[외부 API 호출] RestTemplate, WebFlux (WebClient) 그리고 WebSocket (0) | 2023.09.02 |
[JAVA] Selenium으로 구글 로그인 자동화 만들기 (0) | 2023.07.29 |