지금까지 개발한 프레임워크는 스프링 MVC와 굉장히 흡사하다.
스프링 MVC도 프론트 컨트롤러 패턴으로 구현되어 있다.
직접 개발한 프론트 컨트롤러의 역할이 스프링 MVC에서는 Dispatcher Servlet으로 동작한다.
<요청 흐름>
1. 스프링부트는 Dispatcher Servlet을 서블릿으로 자동으로 등록하면서 모든 경로에 대해 매핑한다.
2. 서블릿이 호출되면 HttpServlet이 제공하는 service()가 호출된다.
3. 스프링 MVC는 Dispatcher Servlet의 부모인 FrameworkServlet에서 오버라이드한 service()를 호출한다.
4. service()를 시작으로 여러 메서드가 호출되면서 DispatcherServlet.doDispatch()가 호출된다.
5. doDispatch() 코드 내에
1. 핸들러 조회
2. 핸들러 어댑터 조회
3. 핸들러 어댑터 실행
4. 핸들러 실행
5. ModelAndView 반환
6. viewResolver 호출
7. View 반환
8. 뷰 렌더링
가 동작한다.
<스프링 MVC - 시작하기>
@RequestMapping
스프링에서 주로 사용하는 애노테이션 기반의 컨트롤러를 지원하는 핸들러 매핑과 어댑터. 실무에서는 99.9% 이 방식의 컨트롤러를 사용.
@RequestMapping 기반의 스프링 MVC 컨트롤러로 변경해보자.
SpringMemberFormControllerV1 - 회원 등록 폼
package hello.servlet.web.springmvc.v1;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class SpringMemberFormControllerV1 {
@RequestMapping("/springmvc/v1/members/new-form")
public ModelAndView process() {
return new ModelAndView("new-form");
}
}
@Controller
*스프링이 자동으로 스프링 빈으로 등록한다.
*스프링 MVC에서 애노테이션 기반 컨트롤러로 인식한다.
@RequestMapping
*요청 정보를 매핑한다. 해당 URL이 호출되면 이 메서드가 호출된다.
*애노테이션 기반 동작이기 때문에, 메서드의 이름은 임의로 지으면 된다.
@ModelAndView
*모델과 뷰 정보를 담아서 반환한다.
ServletApplication - 스프링 빈 등록
//스프링 빈 직접 등록
@Bean
SpringMemberFormControllerV1 springMemberFormControllerV1() {
return new SpringMemberFormControllerV1();
}
SpringMemberSaveControllerV1 - 회원 저장
package hello.servlet.web.springmvc.v1;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class SpringMemberSaveControllerV1 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@RequestMapping("/springmvc/v1/members/save")
public ModelAndView process(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
memberRepository.save(member);
ModelAndView mv = new ModelAndView("save-result");
mv.addObject("member", member);
return mv;
}
}
mv.addObject("member", member)
*스프링이 제공하는 ModelAndView를 통해 Model 데이터를 추가할 때는 addObject()를 사용한다.
SpringMemberListControllerV1 - 회원 목록
package hello.servlet.web.springmvc.v1;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
public class SpringMemberListControllerV1 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@RequestMapping("/springmvc/v1/members")
public ModelAndView process() {
List<Member> members = memberRepository.findAll();
ModelAndView mv = new ModelAndView("members");
mv.addObject("members", members);
return mv;
}
}
<스프링 MVC V2 - 컨트롤러 통합>
@RequestMapping을 보면 클래스 단위가 아니라 메서드 단위에 적용된 것을 확인할 수 있다. 따라서 컨트롤러 클래스를 유연하게 하나로 통합할 수 있다.
package hello.servlet.web.springmvc.v2;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
/**
* 클래스 단위 -> 메서드 단위
* @RequestMapping 클래스 레벨과 메서드 레벨 조합
*/
@Controller
@RequestMapping("/springmvc/v2/members")
public class SpringMemberControllerV2 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@RequestMapping("/new-form")
public ModelAndView newForm() {
return new ModelAndView("new-form");
}
@RequestMapping("/save")
public ModelAndView save(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
memberRepository.save(member);
ModelAndView mv = new ModelAndView("save-result");
mv.addObject("member", member);
return mv;
}
@RequestMapping
public ModelAndView members() {
List<Member> members = memberRepository.findAll();
ModelAndView mv = new ModelAndView("members");
mv.addObject("members", members);
return mv;
}
}
/springmvc/v2/members 의 중복을 클래스 레벨 @RequestMapping("springmvc/v2/members")로 통합했고,
각각 메서드 레벨 @RequestMapping을 추가했다.
<스프링 MVC V3 - 실용적인 방식>
실무에서는 이 방식을 주로 사용한다.
package hello.servlet.web.springmvc.v3;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* v3
* Model 도입
* ViewName 직접 반환
* @RequestParam 사용
* @RequestMapping -> @GetMapping, @PostMapping
*/
@Controller
@RequestMapping("/springmvc/v3/members")
public class SpringMemberControllerV3 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@GetMapping("/new-form")
public String newForm() {
return "new-form";
}
@PostMapping("/save")
public String save(
@RequestParam("username") String username,
@RequestParam("age") int age,
Model model) {
Member member = new Member(username, age);
memberRepository.save(member);
model.addAttribute("member", member);
return "save-result";
}
@GetMapping
public String members(Model model) {
List<Member> members = memberRepository.findAll();
model.addAttribute("members", members);
return "members";
}
}
1. Model 파라미터
save(), members() 를 보면 Model을 파라미터로 받는 것을 확인할 수 있다. 스프링 MVC는 이런 편의 기능을 제공한다.
2. ViewName 직접 반환
뷰의 논리 이름을 반환할 수 있다.
3. @RequestParam 사용
HTTP 요청 파라미터를 @RequestParam 으로 받을 수 있다.
@RequestParam 은 request.getParameter() 와 거의 같은 코드라 생각하면 된다.
GET 쿼리 파라미터, POST Form 방식을 모두 지원한다.
4. @RequestMapping -> @GetMapping, @PostMapping
URL만 매칭하는 것이 아니라, HTTP 메서드도 함께 구분할 수 있다.
'공부 > Spring' 카테고리의 다른 글
[Spring MVC](7) 기본 기능 - 요청 데이터 2, 응답 (1) | 2024.01.22 |
---|---|
[Spring MVC](6) 기본 기능 - 요청 매핑, 요청 데이터 1 (0) | 2024.01.22 |
[Spring MVC](4) 프레임워크 만들기 v4,5 (0) | 2024.01.22 |
[Spring MVC](3) 프론트 컨트롤러 도입, 프레임워크 만들기 v1,2,3 (0) | 2024.01.20 |
[Spring MVC](2) MVC 패턴 (1) | 2024.01.19 |