@RequestMapping
- @RequestMapping 애노테이션 컨트롤러가 등장하면서, MVC 부분도 스프링의 한 부분이다.
@RequestMapping
- RequestMappingHandlerMapping
- RequestMappingHandlerAdapter
이제 본격적으로 컨트롤러를 @RequestMapping 기반의 스프링 MVC 컨트롤러로 변경해보자.
회원 등록 폼을 만들어보자.
SpringMemberFormControllerV1
package hello.setvlet.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() {
// ModelAndView에 viewName을 넘겨주었다.
return new ModelAndView("new-form");
}
}
@RequestMapping url로 가보면 나온다.
- @Controller
- 스프링이 자동으로 스프링 빈으로 등록한다. (내부에 @Component 애노테이션이 있어서 컴포넌트 스캔의 대상이 된다.)
- 스프링 MVC에서 애노테이션 기반 컨트롤러로 인식한다.
- @RequestMapping: 요청 정보를 매핑한다. 해당 URL이 호출되면 메서드가 호출이 되고
- 애노테이션을 기반으로 동작하기 때문에 메서드의 이름은 임의로 지으면 된다.
- ModelAndView: 모델과 뷰 정보를 담아서 반환하면 된다.
컴포넌트 스캔을 통해 스프링 빈으로 등록해도 동작한다.
- RequestMappingHandlerMapping은 스프링 빈 중에서 @RequestMapping 또는 @Controller가 클래스 레벨에 붙어 있는 경우에 매핑 정보로 인식한다.
// SpringMemberControllerV1
package hello.setvlet.web.springmvc.v1;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
//@Controller
@Component
@RequestMapping
public class SpringMemberFormControllerV1 {
@RequestMapping("/springmvc/v1/members/new-form")
public ModelAndView process() {
// ModelAndView에 viewName을 넘겨주었다.
return new ModelAndView("new-form");
}
}
그리고 SpringMemberFormControllerV1을 그대로 두고
package hello.setvlet.web.springmvc.v1;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@RequestMapping
public class SpringMemberFormControllerV1 {
@RequestMapping("/springmvc/v1/members/new-form")
public ModelAndView process() {
// ModelAndView에 viewName을 넘겨주었다.
return new ModelAndView("new-form");
}
}
ServletApplication에 SpringBean을 직접 등록해도 된다.
// ServletApplication
package hello.setvlet;
import hello.setvlet.web.springmvc.v1.SpringMemberFormControllerV1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.view.InternalResourceView;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@ServletComponentScan // 서블릿 자동 등록
@SpringBootApplication
public class SetvletApplication {
public static void main(String[] args) {
SpringApplication.run(SetvletApplication.class, args);
}
@Bean
SpringMemberFormControllerV1 springMemberFormControllerV1() {
return new SpringMemberFormControllerV1();
}
}
근데 컨트롤러는 그냥 SpringMemberFormControllerV1에 Controller라고 등록하는게 제일 깔끔하다.
// SpringMemberFormControllerV1
package hello.setvlet.web.springmvc.v1;
import org.springframework.stereotype.Component;
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");
}
}
// ServletApplication Class
package hello.setvlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan
@SpringBootApplication
public class SetvletApplication {
public static void main(String[] args) {
SpringApplication.run(SetvletApplication.class, args);
}
}
회원 저장 기능을 만들어보자.
MemberSaveControllerV3에서 아래 코드를 가져와서 MemberSaveControllerV1에 붙여주자.
ModelView => ModelAndView로 바꿈
// MemberSaveControllerV3
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap) {
String username = paramMap.get("username");
int age = Integer.parseInt(paramMap.get("age"));
Member member = new Member(username, age);
memberRepository.save(member);
ModelView mv = new ModelView("save-result");
mv.getModel().put("member", member);
return mv;
}
// SpringMemberSaveControllerV1
package hello.setvlet.web.springmvc.v1;
import hello.setvlet.domain.member.Member;
import hello.setvlet.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.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;
}
}
List도 만들어주자.
// SpringMemberSaveControllerV1
package hello.setvlet.web.springmvc.v1;
import hello.setvlet.domain.member.Member;
import hello.setvlet.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;
import java.util.Map;
@Controller
public class SpringMemberListControllerV1 {
private final 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 - 컨트롤러를 통합해보자.
각 파일에서 가져와서 통합한게 끝이다.
- RequestMapping은 메서드 단위로 되기 때문에 원하는 만큼 넣어줄 수 있다.
// SpringMemberControllerV2
package hello.setvlet.web.springmvc.v2;
import hello.setvlet.domain.member.Member;
import hello.setvlet.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
public class SpringMemberControllerV2 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@RequestMapping("/springmvc/v2/members/new-form")
public ModelAndView newForm() {
return new ModelAndView("new-form");
}
@RequestMapping("/springmvc/v2/members/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("/springmvc/v2/members")
public ModelAndView members() {
List<Member> members = memberRepository.findAll();
ModelAndView mv = new ModelAndView("members");
mv.addObject("members", members);
return mv;
}
}
결과가 잘 나온다.
획기적인 방법으로 @RequestMapping을 맨위에 두고 중복되는 url을 간편하게 지정할 수 있다.
// SpringMemberControllerV2
package hello.setvlet.web.springmvc.v2;
import hello.setvlet.domain.member.Member;
import hello.setvlet.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;
}
// /springmvc/v2/members가 되니까 이 부분은 안적어줘도 된다.
@RequestMapping
public ModelAndView members() {
List<Member> members = memberRepository.findAll();
ModelAndView mv = new ModelAndView("members");
mv.addObject("members", members);
return mv;
}
}
결과가 잘 나온다.
정리를 해보자.
- 컨트롤러 클래스를 통합하는 것을 넘어서 조합도 가능
- 다음 코드는 /springmvc/v2/members라는 부분에 중복이 있다.
그래서 위에서 SpringMemberControllerV2에서 RequestMapping에 중복되는 url을 한번에 등록해 주었다.
@RequestMapping("/springmvc/v2/members/new-form")
@RequestMapping("/springmvc/v2/members")
@RequestMapping("/springmvc/v2/members/save")
@Controller
@RequestMapping("/springmvc/v2/members")
public class SpringMemberControllerV2 {}
실용적인 방식을 한 번 알아보자.
기존의 SpringMemberControllerV3에서 코드를 더 간단히 했다.
// SpringMemberV3 Class
package hello.setvlet.web.springmvc.v3;
import hello.setvlet.domain.member.Member;
import hello.setvlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
/**
* v3
* Model 도입
* ViewName 직접 반환
* @RequestParam 사용
* @RequestMapping -> @GetMapping, @PostMapping */
@Controller
@RequestMapping("/springmvc/v3/members")
public class SpringMemberControllerV3 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@RequestMapping("/new-form")
public String newForm() {
return "new-form";
}
@RequestMapping("/save")
public String save(
// username이라는 요청 파라미터 받고싶다.
@RequestParam("username") String username,
@RequestParam("age") int age,
Model model) {
Member member = new Member(username, age);
memberRepository.save(member);
// view에 이름 반환해준다.
model.addAttribute("member", member);
return "save-result";
}
@RequestMapping
public String members(Model model) {
List<Member> members = memberRepository.findAll();
model.addAttribute("members", members);
return "members";
}
}
결과가 SpringMVC3에서도 잘 나온다.
SpringMVC를 이제 Postman으로 api 테스트를 해보자. POST GET 둘다 아래와 같은 BODY 값이 나온다.
// SpringMemberControllerV3
package hello.setvlet.web.springmvc.v3;
import hello.setvlet.domain.member.Member;
import hello.setvlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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();
@RequestMapping("/new-form")
public String newForm() {
return "new-form";
}
@RequestMapping("/save")
public String save(
// username이라는 요청 파라미터 받고싶다.
@RequestParam("username") String username,
@RequestParam("age") int age,
Model model) {
Member member = new Member(username, age);
memberRepository.save(member);
// view에 이름 반환해준다.
model.addAttribute("member", member);
return "save-result";
}
@RequestMapping
public String members(Model model) {
List<Member> members = memberRepository.findAll();
model.addAttribute("members", members);
return "members";
}
}
아래와 같이 해주면 GET인 경우에만 호출이 된다.
처음 형태에서
@RequestMapping("/new-form")
public String newForm() {
return "new-form";
}
value값을 지정해주고 method값을 넣어줬다.
@RequestMapping(value = "/new-form", method = RequestMethod.GET)
public String newForm() {
return "new-form";
}
// MemberControllerV3 Class
package hello.setvlet.web.springmvc.v3;
import hello.setvlet.domain.member.Member;
import hello.setvlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
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();
@RequestMapping(value = "/new-form", method = RequestMethod.GET)
public String newForm() {
return "new-form";
}
@RequestMapping("/save")
public String save(
// username이라는 요청 파라미터 받고싶다.
@RequestParam("username") String username,
@RequestParam("age") int age,
Model model) {
Member member = new Member(username, age);
memberRepository.save(member);
// view에 이름 반환해준다.
model.addAttribute("member", member);
return "save-result";
}
@RequestMapping
public String members(Model model) {
List<Member> members = memberRepository.findAll();
model.addAttribute("members", members);
return "members";
}
}
그러면 save는? POST로 해주자. save 하는데 GET으로 하면? 어색하다. save는 조회하는 거니까 POST로 해주자.
@RequestMapping(value = "/save", method = RequestMethod.POST)
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";
}
members는?
GET으로 해주자.
@RequestMapping(method = RequestMethod.GET)
public String members(Model model) {
List<Member> members = memberRepository.findAll();
model.addAttribute("members", members);
return "members";
}
잘 나온다.
정말 간단하게 한번 더 변경해보자. getmapping / postmapping를 써준다.
package hello.setvlet.web.springmvc.v3;
import hello.setvlet.domain.member.Member;
import hello.setvlet.domain.member.MemberRepository;
import org.apache.coyote.Request;
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";
}
}
Model 파라미터
- save(), members()를 보면 Model을 파라미터로 받는 것을 확인할 수 있다. 스프링 MVC도 이런 편의 기능을 제공한다.
ViewName 직접 반환
- 뷰의 논리 이름을 반환할 수 있다.
@RequestParam 사용
- 스프링은 HTTP 요청 파라미터를 @RequestParam으로 받는다.
- @RequestParam("username")은 request.getParameter("username")와 같은 코드라고 생각하면 된다.
@RequestMapping @GetMapping, @PostMapping
@RequestMapping은 URL만 매칭하는게 아니고, HTTP Method도 함께 구분한다.
예를 들어 URL /new-form이고, HTTP Method가 GET인 경우 모두 만족하는 매핑을 하려면 다음과 같이 처리.
@RequestMapping(value = "/new-form", method = RequestMethod.GET)
이것을 @GetMapping, @PostMapping으로 더 편리하게 사용할 수 있다.
Get, Post, Put, Delete, Patch 모두 애노테이션이 준비되어 있다.
@GetMapping 코드를 열어서 @RequestMapping 애노테이션을 내부에 가지고 있는 모습을 확인하자.
<출처 김영한: 스프링 MVC 1편 - 벡앤드 웹 개발 핵심 기술>
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의
웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -
www.inflearn.com
'Spring > SpringMVC' 카테고리의 다른 글
스프링MVC 기본기능 (0) | 2022.04.29 |
---|---|
SpringMVC 구조 정리 (0) | 2022.04.28 |
뷰 리졸버 (0) | 2022.04.28 |
핸들러 매핑과 핸들러 어댑터 (0) | 2022.04.28 |
스프링 MVC 전체 구조 (0) | 2022.04.25 |