Skip to content

Conversation

@mintcoke123
Copy link

@mintcoke123 mintcoke123 commented Nov 6, 2025

안녕하세요! 준수님!
저번 자바 미션에 이어 스프링 미션에서 다시 만나뵙게 되었네요!
이번 미션도 잘부탁드립니다!!

🚀 1단계 - 홈 화면

요구사항
localhost:8080 요청 시 아래 화면과 같이 어드민 메인 페이지가 응답할 수 있도록 구현하세요.
어드민 메인 페이지는 templates/home.html 파일을 이용하세요.

🚀 2단계 - 예약 조회

요구사항
/reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현하세요.
어드민 메인 페이지는 templates/reservation.html 파일을 이용하세요.
아래의 API 명세를 따라 예약 관리 페이지 로드 시 호출되는 예약 목록 조회 API도 함께 구현하세요.


파일 구조

각 파일의 역할은 다음과 같습니다.

src/main/java/roomescape 파일 역할

  • RoomescapeApplication.java: Spring Boot 실행 진입점.
  • HomeController.java: 메인 페이지 라우팅. GET / 요청 시 templates/home.html을 반환
  • ReservationController.java:
    • GET /reservation: 예약 관리 화면(templates/reservation.html) 반환.
    • GET /reservations: 예약 목록 JSON 응답.
  • Reservation.java: 예약 데이터를 표현하는 DTO. id, name, date, time 필드를 가진다.

생각한 점

이번 스터디에서 DTO에 대해 공부하면서 Reservation 객체는 단순히 데이터를 전달하기 위한 용도라고 판단했습니다. 즉, 별도의 비즈니스 로직이나 상태 변화가 필요하지 않고, 생성 이후 값이 변경되면 안 되는 특성이 있어 불변 객체라고 보았습니다.

그래서 DTO에는 불변성을 보장해 의도가 더 명확한 record를 적용했습니다.

Copy link

@gogo1414 gogo1414 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요, 동현님 😁
저도 다시 만나뵙게 되어 반갑네요!

코멘트 몇개와 생각하신 점에 대해 질문 드릴게 있어 적어봤습니다!
그리고, 2개의 파일에서 EOL 에러가 발생하고 있는데 해당 부분만 수정 부탁드릴게요!

생각한 점에 대한 질문

DTO에 대해 공부하면서 Reservation 객체는 단순히 데이터를 전달하기 위한 용도라고 판단했습니다. 즉, 별도의 비즈니스 로직이나 상태 변화가 필요하지 않고, 생성 이후 값이 변경되면 안 되는 특성이 있어 불변 객체라고 보았습니다.
그래서 DTO에는 불변성을 보장해 의도가 더 명확한 record를 적용했습니다

이번 스터디 때 DTO에 대해 배우셨군요! DTO는 Data Transfer Object로 동현님이 적으신 내용과 같이 데이터를 전달하기 위한 용도의 객체입니다. 비즈니스 로직 혹은 상태 변화가 필요 없기 때문에 Record 객체를 주로 사용하죠!

다만, 이번에 적용해주신 Reservation 객체가 DTO라고 한다하면, 고민을 해봐야 할 것 같아요! 이번 미션에서는 홈 화면을 활성화 하는 것과 예약 조회만 있었다고 하셨는데, 이후 미션에선 제 기억 상 예약을 생성, 수정 삭제 기능을 구현해야 하는 것으로 알고있어요. 그렇다면 불변 객체인 DTO로 정의된 Reservation의 값에 변화를 줘야한다거나 새롭게 생성하거나 제거를 해야하는데, 단순히 데이터를 전달하기 위한 객체가 비즈니스 로직을 갖게되고 상태에 대한 변화가 생기는게 아닐까요?

이럴 때는 어떻게 하는게 좋을까요?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

줄내림 마지막 부분에 없는데 확인 부탁드려요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정했습니다!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 확인 부탁드릴게요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정했습니다!

Comment on lines +21 to +30
@GetMapping("/reservation")
public String reservationPage() {
return "reservation";
}

@GetMapping("/reservations")
@ResponseBody
public List<Reservation> findAll() {
return reservations;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컨트롤러를 잘 작성해주셨네요👍👍

컨트롤러 내에서 @GetMapping, @ResponseBody 어노테이션을 사용하고 계시는데 내부에서는 어떻게 동작이 실행되는지 한번 생각해 보신 적 있으신가요? 이미 알고 계시다면 아래의 질문에 대한 답변을 적어주시고, 아니라면 한번 해당 어노테이션이 어떤 역할을 하는지 찾아보며 질문에 답해주시면 좋겠네요!

  • /reservation으로 오는 요청은 어떻게 String 타입의 "reservation"을 반환하는데 reservation.html 파일을 반환할까요?

  • /reservations 요청의 응답 Content-Typeapplication/json으로 결정되는 것은 어떤 어노테이션 덕분일까요? 그리고 그 과정은 어떻게 될까요?"

  • @GetMapping은 정확히 어떤 동작을 처리해주는 걸까요?

관련 키워드

  • Spring MVC 동작 원리
  • ViewResolver
  • @responsebody와 MessageConverter
  • HandlerMapping

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/reservation으로 오는 요청은 어떻게 String 타입의 "reservation"을 반환하는데 reservation.html 파일을 반환할까요?

해당 동작 방식은 다음과 같이 이해했습니다!

  1. 클라이언트가 @GetMapping("/reservation") 으로 /reservation을 요청하면,
  2. DispatcherServlet이 요청을 받고 HandlerMapping이 어떤 메서드를 호출할지 찾고, HandlerAdapter가 해당 메서드를 실행합니다.
  3. @responsebody가 없기 때문에 Spring MVC는 이를 뷰 이름(View Name)으로 해석합니다.
  4. ViewResolver가 prefix/suffix를 붙여 파일 경로로 변환합니다.

/reservation으로 오는 요청은 어떻게 String 타입의 "reservation"을 반환하는데 reservation.html 파일을 반환할까요?

  1. 위의 단계와 비슷한 방식으로 reservations를 반환하게 되면,
  2. @responsebody 때문에 ViewResolver가 아니라 HttpMessageConverter로 전달됨.
  3. 그렇게 되면 HttpMessageConverter가 List을 JSON으로 직렬화하고,
  4. Content-Type을 application/json으로 지정하고 JSON으로 응답합니다.

@GetMapping은 정확히 어떤 동작을 처리해주는 걸까요?

GetMapping은 url과 메서드를 연결해주는 역할을 합니다.
GetMapping내부의 값인 url을 읽어서,
"해당 url을 받으면 연결된 해당 메서드를 실행하라"
라는 의미로 받아들였습니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

답변을 보면서 제가 중복된 질문을 2번 드렸나 순간 의아했네요 😅

답변 감사합니다! 1, 2, 3번 질문 모두 스프링 MVC의 핵심 동작 원리를 잘 설명해주셨습니다.

특히 2번 답변에서 @ResponseBody 유무에 따라 ViewResolverHttpMessageConverter로 분기되는 과정을 정확하게 짚어주셨네요.

다만, 1번 답변에서 "클라이언트가 @GetMapping("/reservation") 으로 /reservation을 요청하면" 이라고 하신 부분이 조금 오해의 소지가 있을 것 같습니다. 아마 답변이 꼬이신 것 같아 제가 이해한 내용을 바탕으로 조금 더 명확하게 정리해볼게요!


1번 답변

먼저 클라이언트(브라우저)는 @GetMapping이라는 어노테이션의 존재 자체를 모릅니다.

클라이언트는 그저 서버에 HTTP GET /reservation 이라는 요청을 보낼 뿐입니다. 서버는 이 요청을 받고, HandlerMapping@GetMapping("/reservation") 어노테이션을 스캔해서 연결해주는 것입니다.

동현님이 적어주신 부분은, 클라이언트의 /reservation 요청을 서버의 HandlerMapping@GetMapping 어노테이션을 기준으로 처리할 메서드를 찾는다는 의미로 이해되지만, 주어가 섞이면서 설명이 약간 꼬인 것 같습니다. 혹시 몰라서 정리 해봤는데 참고해주시면 좋을 것 같습니다!

3번 답변

@GetMapping에 대해 조금 만 더 보충하자면, @GetMapping은 사실 @RequestMapping(method = RequestMethod.GET) 의 축약형어노테이션입니다. 이렇게 HTTP Method까지 명시적으로 지정해주는 어노테이션이라는 점을 함께 이해하시면 나중에 @PostMapping, @PutMapping 등 다른 어노테이션의 의미를 더 쉽게 이해하실 수 있을 것 같습니다!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

몇가지 의존성이 있네요!

추가된 의존성은 명확하게 어떤 역할을 하고 있을까요? 간단하게 설명 부탁드릴게요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

implementation 'org.springframework.boot:spring-boot-starter-web'
HTTP 요청/응답을 처리하기 위한 모든 기본 컴포넌트로써, @GetMapping, @ResponseBody를 사용할 때 사용됩니다!

implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
Thymeleaf 템플릿 엔진으로써, ViewResolver(prefix·suffix)를 자동 설정하기 위해 사용됩니다.

return "reservation";

위 코드에서 반환되는 String이
.../reservation.html로 랜더링되게 해줍니다.

spring-boot-devtools
위 의존성은 코드 수정시에 자동 재시작을 도와줍니다!
템플릿 자동 새로고침을 도와주기 때문에 개발자 편의를 위해 사용됩니다.
사실 devtools를 적용해야 html에 코드 수정사항이 반영되는 걸로 역할을 오해하고 있었는데,
다시 찾아보니 개발 편의성을 위해 이용하는 툴이고 없어도 작동했네요..
그래도 남겨두도록 하겠습니다!

@mintcoke123
Copy link
Author

mintcoke123 commented Nov 9, 2025

그렇다면 불변 객체인 DTO로 정의된 Reservation의 값에 변화를 줘야한다거나 새롭게 생성하거나 제거를 해야하는데, 단순히 데이터를 전달하기 위한 객체가 비즈니스 로직을 갖게되고 상태에 대한 변화가 생기는게 아닐까요?

이럴 때는 어떻게 하는게 좋을까요?

생각해보니 초기 비즈니스 로직은 값에 "변화를 주고, 제거가 가능하다" 까지 가능한 상태겠네요.
단순한 데이터 전송용 묶음으로 계속 사용하기는 어려울 것 같습니다,
그렇다면 DTO에 엔티티급 로직을 넣어 엔티티처럼 만드는 방식을 생각해봤습니다만, 어차피 컨트롤러와의 통신을 위해서는 별도의 dto가 필요한 상황입니다.
그렇다면 dto는 두고, 생성,수정,삭제는 도메인 엔티티가 담당하도록 분리하는 방식이 좋을 것 같습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants