3 분 소요

뷰 리졸버

resources>application.properties에 아래 코드를 추가한다.

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

스프링 부트는 InternalResourceViewResolver라는 뷰 리졸버를 자동으로 등록하는데, 이때 application.properties에 등록한 spring.mvc.view.prefix , spring.mvc.view.suffix 설정 정보를 사용해서 등록한다.

💎 v1 - 스프링 MVC 시작하기

스프링이 제공하는 컨트롤러는 애노테이션 기반으로 동작해서, 매우 유연하고 실용적이다.

SpringMemberFormControllerV1 - 회원 등록 폼

@Controller // 스프링이 자동으로 스프링 빈으로 등록한다. (컴포넌트 스캔의 대상이 됨)
public class SpringMemberFormControllerV1 {

    @RequestMapping("/springmvc/v1/members/new-form") // 요청 정보를 매핑한다. 해당 URL이 호출되면 이 메서드가 호출된다.
    public ModelAndView process(){
        return new ModelAndView("new-form"); // 모델과 뷰 정보를 담아서 반환한다.
    }
}

@Controller

  • 스프링이 자동으로 스프링 빈으로 등록한다. (내부에 @Component 애노테이션이 있어서 컴포넌트 스캔의 대상이 됨)
  • 스프링 MVC에서 애노테이션 기반 컨트롤러로 인식한다.

@RequestMapping

  • 요청 정보를 매핑한다.
  • 해당 URL이 호출되면 이 메서드가 호출된다.
  • 애노테이션을 기반으로 동작하기 때문에 메서드의 이름은 임의로 지으면 된다.

SpringMemberSaveControllerV1 - 회원 저장

@Controller
public class SpringMemberSaveControllerV1 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/springmvc/v1/members/save")
    public ModelAndView process(HttpServletRequest req, HttpServletResponse res) {

        String username = req.getParameter("username");
        int age = Integer.parseInt(req.getParameter("age"));

        Member member = new Member(username, age);
        memberRepository.save(member);

        ModelAndView mv = new ModelAndView("save-result"); // 뷰의 전체 path가 아닌 논리적인 이름을 넣는다.
        mv.addObject("member", member); // 스프링이 제공하는 ModelAndView를 통해 Model 데이터를 추가할 때는 ddOnject()를 사용한다. 이 데이터는 이후 뷰를 렌더링 할 때 사용된다.

        return mv;
    }
}

SpringMemberListControllerV1 - 회원 목록

@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;
    }
}

💎 v2 - 컨트롤러 통합

@RequestMapping을 잘 보면 클래스 단위가 아니라 메서드 단위에 적용된 것을 확인할 수 있다.
따라서 컨트롤러 클래스를 유연하게 하나로 통합할 수 있다.

SpringMemberControllerV2

@Controller
@RequestMapping("/springmvc/v2/members") // 🌟 중복 제거
public class SpringMemberControllerV2 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/new-form") // /springmvc/v2/members/new-form
    public ModelAndView newForm(){
        return new ModelAndView("new-form");
    }

    @RequestMapping("/save") // /springmvc/v2/members/save
    public ModelAndView save(HttpServletRequest req, HttpServletResponse res) {

        String username = req.getParameter("username");
        int age = Integer.parseInt(req.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("/springmvc/v2/members/new-form")
@RequestMapping("/springmvc/v2/members")
@RequestMapping("/springmvc/v2/members/save")

위 코드는 /springmvc/v2/members라는 부분에 중복이 있다.
물론 이렇게 사용해도 되지만, 클래스 레벨에 @RequestMapping을 두어 중복을 제거할 수도 있다.

조합 결과

  • 클래스 레벨 @RequestMapping("/springmvc/v2/members")
    - 메서드 레벨 @RequestMapping("/new-form") -> /springmvc/v2/members/new-form
    - 메서드 레벨 @RequestMapping("/save") -> /springmvc/v2/members/save
    - 메서드 레벨 @RequestMapping -> /springmvc/v2/members

💎 v3 - 실용적인 방식

이전에 MVC 프레임워크 만들기에서, v3은 ModelView를 개발자가 직접 생성해서 반환했기 때문에 불편했었다. 따라서 v4를 만들면서 실용적으로 개선할 수 있었다.
실무에서는 이 방식을 주로 사용한다.

SpringMemberControllerV3

@Controller
@RequestMapping("/springmvc/v3/members") 
public class SpringMemberControllerV3 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @GetMapping("/new-form") // GET /springmvc/v3/members/new-form
    public String newForm(){
        return "new-form"; // ModelAndView 객체가 아닌 String 형태로 반환한다.
    }

    @PostMapping("/save") // POST /springmvc/v3/members/save
    public String save(@RequestParam ("username") String username, @RequestParam ("age") int age, Model model) { // 파라미터를 받기 위해 @RequestParam 사용

        Member member = new Member(username, age);
        memberRepository.save(member);

        model.addAttribute("member", member);

        return "save-result";
    }

    @GetMapping // GET /springmvc/v3/members
    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")와 거의 같은 코드라 생각하면 된다. 물론 GET 쿼리 파라미터, POST Form 방식을 모두 지원한다.

@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 모두 애노테이션이 준비되어 있다.



💛 개인 공부 기록용 블로그입니다. 👻

맨 위로 이동하기