공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.
스프링 MVC - 시작하기
스프링이 제공하는 컨트롤러는 애노테이션 기반으로 동작하여 매우 유연하고 실용적이다. 과거에는 자바에 애노테이션이 없었고, 스프링도 처음부터 이러한 컨트롤러를 제공하지 않았다.
@RequestMapping
스프링은 애노테이션을 활용한 매우 유연하고 실용적인 컨트롤러를 만들었으며, 그 대표적인 것이 @RequestMapping 애노테이션을 사용하는 컨트롤러이다.
과거에는 스프링의 MVC 기능이 약하여 MVC 웹 기술로 스트럿츠 같은 다른 프레임워크를 사용했다. 하지만 @RequestMapping 기반 애노테이션 컨트롤러가 등장하면서 스프링의 MVC 기능이 강력해졌고, 현재는 99.9% 이 방식을 사용한다.
@RequestMapping과 관련된 핵심 요소
- RequestMappingHandlerMapping
- RequestMappingHandlerAdapter
이 두 가지 요소는 애노테이션 기반 컨트롤러를 지원하는 핸들러 매핑과 어댑터이다.
@RequestMapping 기반의 컨트롤러 적용
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 : 스프링이 자동으로 스프링 빈으로 등록하고, 애노테이션 기반 컨트롤러로 인식한다.
- @RequestMapping : 특정 URL 요청을 해당 메서드와 매핑한다.
- ModelAndView : 모델과 뷰 정보를 포함하는 객체이다.
- RequestMappingHandlerMapping은 @RequestMapping 또는 @Controller 애노테이션이 붙은 클래스를 매핑 대상으로 인식한다.
@Component를 활용한 등록 (동일한 동작 수행)
@Component
@RequestMapping
public class SpringMemberFormControllerV1 {
@RequestMapping("/springmvc/v1/members/new-form")
public ModelAndView process() {
return new ModelAndView("new-form");
}
}
스프링 빈 직접 등록하는 방법
@Bean
SpringMemberFormControllerV1 springMemberFormControllerV1() {
return new SpringMemberFormControllerV1();
}
스프링 3.0 이상에서의 주의사항
스프링 부트 3.0(스프링 프레임워크 6.0)부터는 클래스 레벨에 @RequestMapping만 있어서는 컨트롤러로 인식되지 않는다. 반드시 @Controller 애노테이션이 필요하다. (@RestController는 @Controller를 포함하고 있으므로 문제없음)@Controller가 없는 위의 두 코드는 스프링 컨트롤러로 인식되지 않는다. (RequestMappingHandlerMapping에서 @RequestMapping는 이제 인식하
지 않고, Controller 만 인식한다.)
SpringMemberSaveControllerV1 - 회원 저장
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@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);
System.out.println("member = " + member);
memberRepository.save(member);
ModelAndView mv = new ModelAndView("save-result");
mv.addObject("member", member);
return mv;
}
}
ModelAndView.addObject() 활용
mv.addObject("member", member)를 통해 Model 데이터를 추가하면, 뷰에서 이를 활용하여 화면을 렌더링할 수 있다.
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;
}
}
실행 URL
- 회원 등록 폼: http://localhost:8080/springmvc/v1/members/new-form
- 회원 저장: http://localhost:8080/springmvc/v1/members/save
- 회원 목록 조회: http://localhost:8080/springmvc/v1/members
스프링 MVC - 컨트롤러 통합
@RequestMapping을 메서드 단위로 적용할 수 있기 때문에 컨트롤러 클래스를 보다 유연하게 하나로 통합할 수 있다.
SpringMemberControllerV2
package hello.servlet.web.springmvc.v2;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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 mav = new ModelAndView("save-result");
mav.addObject("member", member);
return mav;
}
@RequestMapping
public ModelAndView members() {
List<Member> members = memberRepository.findAll();
ModelAndView mav = new ModelAndView("members");
mav.addObject("members", members);
return mav;
}
}
컨트롤러 통합과 조합
컨트롤러 클래스를 하나로 통합할 수 있을 뿐만 아니라, 클래스 레벨의 @RequestMapping을 활용하면 URL 패턴을 효과적으로 조합할 수 있다.
예를 들어, 아래와 같은 중복된 URL 매핑이 있을 경우
@RequestMapping("/springmvc/v2/members/new-form")
@RequestMapping("/springmvc/v2/members")
@RequestMapping("/springmvc/v2/members/save")
클래스 레벨에서 @RequestMapping("/springmvc/v2/members")를 선언하면, 개별 메서드 레벨의 @RequestMapping과 조합되어 중복을 제거할 수 있다.
조합 결과
클래스 레벨메서드 레벨최종 매핑 URL
클래스 레벨메서드 레벨최종 매핑 URL
클래스 레벨 | 메서드 레벨 | 최종 매핑 URL |
@RequestMapping("/springmvc/v2/members") | @RequestMapping("/new-form") | /springmvc/v2/members/new-form |
@RequestMapping("/springmvc/v2/members") | @RequestMapping("/save") | /springmvc/v2/members/save |
@RequestMapping("/springmvc/v2/members") | @RequestMapping (기본 경로) | /springmvc/v2/members |
실행
- 등록 폼: http://localhost:8080/springmvc/v2/members/new-form
- 회원 목록: http://localhost:8080/springmvc/v2/members
스프링 MVC - 실용적인 방식
스프링 MVC는 개발자가 보다 편리하게 개발할 수 있도록 다양한 편의 기능을 제공한다.
이전 버전(v3)에서는 ModelView를 직접 생성하여 반환해야 했지만, v4에서는 이를 개선하여 더 실용적인 방식을 도입했다.
실무에서는 지금부터 설명하는 방식을 주로 사용한다.
SpringMemberControllerV3
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.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
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는 Model을 통해 데이터를 뷰에 전달하는 기능을 제공한다.
- 이전 방식에서 ModelAndView 객체를 직접 생성해야 했던 불편함을 해결했다.
2. ViewName 직접 반환
- 컨트롤러 메서드에서 뷰의 논리 이름을 문자열로 직접 반환할 수 있다.
- 예를 들어, "new-form"을 반환하면 src/main/resources/templates/new-form.html을 렌더링 한다.
3. @RequestParam 사용
- HTTP 요청 파라미터를 @RequestParam을 통해 편리하게 받을 수 있다.
- 예를 들어, @RequestParam("username")은 request.getParameter("username")와 동일한 역할을 한다.
- GET 쿼리 파라미터와 POST Form 방식 모두 지원한다.
4. @GetMapping, @PostMapping 적용
@RequestMapping은 기본적으로 URL 매핑뿐만 아니라 HTTP 메서드(GET, POST 등)도 구분할 수 있다.
예전 방식
@RequestMapping(value = "/new-form", method = RequestMethod.GET)
개선된 방식
@GetMapping("/new-form")
- @PostMapping도 동일한 방식으로 사용할 수 있다.
- 참고로 @PutMapping, @DeleteMapping, @PatchMapping 등도 제공된다.
실행 URL
'Spring MVC' 카테고리의 다른 글
[MVC] 스프링 MVC - 기본 기능(2) (1) | 2025.02.24 |
---|---|
[MVC] 스프링 MVC - 기본 기능(1) (0) | 2025.02.23 |
[MVC] 스프링 MVC - 구조 이해(2) (0) | 2025.02.20 |
[MVC] 스프링 MVC - 구조 이해(1) (0) | 2025.02.19 |
[MVC] MVC 프레임워크 만들기(4) (0) | 2025.02.17 |