스프링이 제공하는 컨트롤러는 애노테이션 기반으로 동작해서, 매우 유연하고 실용적이다.
@RequestMapping
스프링은 애노테이션을 활용한 매우 유연하고, 실용적인 컨트롤러를 만들었는데 이것이 바로@RequestMapping
애노테이션을 사용하는 컨트롤러이다.
RequestMappingHandlerMapping
RequestMappingHandlerAdapter
@ReqeustMapping
기반의 스프링 MVC Controller
를 작성하면서 V1부터 V3까지 개선하는 과정
을 작성해보려고 한다.
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
@Component
애노테이션이 있어서 스프링이 자동으로 스프링 빈
으로 등록한다.Spring MVC
에서 애노테이션 기반 Controller
로 인식한다.
RequestMappingHandlerMapping
은 스프링 빈 중에서@RequestMapping
or@Controller
가 클래스 레벨에 붙어 있는 경우매핑 정보
로 인식한다.
그러므로 다음 코드도 동일하게 동작한다.package hello.servlet.web.springmvc.v1; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Component //Component Scan을 통해 스프링 빈으로 등록 @RequestMapping public class SpringMemberFormControllerV1 { @RequestMapping("/springmvc/v1/members/new-form") public ModelAndView process() { return new ModelAndView("new-form"); } }
package hello.servlet.web.springmvc.v1;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.ModelView;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
import java.util.Map;
@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;
}
}
mv.addObject("member", member)
ModelAndView
를 통해 Model
데이터를 추가할 때는 addObject()
를 사용하면 된다. 이 데이터는 이후 View
를 렌더링 할 때 사용된다.package hello.servlet.web.springmvc.v1;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.ModelView;
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.Map;
@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;
}
}
V1은 각
Controller
가 따로 분리되어 있어 한 눈에 파악하기가 어렵다. V2에서는 이 부분을개선
해보겠다.
V1의 각
Controller
의@RequestMapping
를 보면 클래스 단위가 아닌메서드 단위
에 적용되어 있다. 그러므로Controller Class
를 유연하게 하나로통합
할 수 있다.
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;
@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;
}
}
클래스 단위에 @RequestMapping("/springmvc/v2/members")
를 작성함으로서 중복되는 부분도 제거하였다. 그런데 여전히 개발자가 ModelView
를 직접 생성해서 반환해야 한다는 불편한 부분이 존재한다. 개선할 방법이 없을까?
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 org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@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";
}
}
V3에서는 V2의 불편한 부분을 개선하기 위해 다음과 같은 기능을 추가했다.
Model
도입 ModelAndView
객체가 아닌 ViewName
를 직접 반환@GetMapping
, PostMapping
사용Model 파라미터
save()
, members()
를 보면 Model
을 파라미터로 받는 것을 확인할 수 있다. Spring MVC도 이런 편의 기능을 제공한다.ViewName 직접 반환
View
의 논리 이름을 반환할 수 있다.@GetMapping, @PostMapping
@GetMapping
과 @PostMapping
은 다음 코드의 간략화 버전이다.@RequestMapping(value="/...", method = RequestMethod.Get)
@RequestMapping(value="/...", method = RequestMethod.Post)
//@RequestMapping은 URL만 매칭하는 것이 아니라, HTTP Method도 함께 구분할 수 있다.