Spring MVC 실제 사용

최준호·2021년 7월 6일
0

Spring

목록 보기
16/47

Spring MVC

스프링은 어노테이션을 활용하여 매우 유연하고 실용적인 컨트롤러를 만들었는데 @ReqeustMapping을 사용하는 컨트롤러가 그것이다.

  • @RequestMapping
    • RequestMappingHandlerMapping
    • RequestMappingHandlerAdapter

핸들러 매핑과 핸들러 어댑터의 우선순위가 있는데

HandlerMapping

0 = RequestMappingHandlerMapping : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
1 = BeanNameUrlHandlerMapping : 스프링 빈의 이름으로 핸들러를 찾는다.

HandlerAdapter

0 = RequestMappingHandlerAdapter : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
1 = HttpRequestHandlerAdapter : HttpRequestHandler 처리
2 = SimpleControllerHandlerAdapter : Controller 인터페이스(애노테이션X, 과거에 사용) 
처리

다음과 같은 우선순위를 가진다. 그 중 가장 우선순위가 높은 핸들러 매핑과 어댑터를 사용하는 @RequestMapping은 스프링에서 주로 사용되는 컨트롤러 어노테이션이다. 이제 컨트롤러 어노테이션을 활용하여 컨트롤러를 만들어보자!

  1. 회원 등록

    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); 
            memberRepository.save(member);
            ModelAndView mv = new ModelAndView("save-result");
            mv.addObject("member", member);
            return mv;
        }
    }

    지금 까지의 예제인 회원등록을 하는 컨트롤러는 @Controller와 @RequestMapping으로 구현해봤다.

    • @Controller
      -내부에 @Component가 내장되어 있어 스프링 빈으로 등록되며 스프링 MVC에서 어노테이션 기반 컨트롤러로 인식한다.
    • @RequestMapping
      • 메서드 level에서는 요청 정보를 매핑하고 URL이 호출되면 이 메서드가 호출된다. 어노테이션 기반으로 동작하기 때문에 메서드의 이름은 임의로 지어도
        된다.
      • 클래스 level에서는 RequestMappingHandlerMapping에 매핑정보로 인식할 수 있도록 동작시킨다.
    • ModelAndView
      • 모델과 뷰 정보를 담아 반환한다.

어노테이션 기반의 Controller 통합

이전의 하나의 url에 대해 하나의 Controller를 매핑해서 프로세스를 진행했던 과거와 달리 어노테이션을 통해 하나의 컨트롤러로 여러 url을 처리할 수 있게 되었다. 아래 코드로 확인해보자! 근데 이건 솔직히 실무나 웹을 만들어봤던 사람이라면 다 알거다...

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 process1(){
        return new ModelAndView("new-form");
    }

    @RequestMapping("/save")
    public ModelAndView process2(HttpServletRequest request, HttpServletResponse response) {
        String username = request.getParameter("username");
        Integer age = Integer.valueOf(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 process3() {
        List<Member> members = memberRepository.findAll();
        ModelAndView mv = new ModelAndView("members");
        mv.addObject("members",members);
        return mv;
    }
}

하지만 실무에서나 실제 웹을 개발할때 봤던 코드보다 아쉬운게 ModelAndView 객체를 반환해야 한다는 것이다. 그리고 HttpServlet의 기능들도 controller에서 직접 사용하여야하고 이 아쉬운 점 어디서 많이 본거 같지 않을까? 맞다 이전 Controller를 직접 만들때 V3와 V4의 개선 점과 동일하다. 그래서 이 점을 개선하여 다시 Controller를 작성해보자

실무에서 사용되는 Controller 코드

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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;

@Controller
@RequestMapping("/springmvc/v3/members")
public class SpringMemberControllerV3 {
    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/new-form")
    public String process1(){
        return "new-form";
    }

    @RequestMapping("/save")
    public String process2(@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";
    }

    @RequestMapping
    public String process3(Model model) {
        List<Member> members = memberRepository.findAll();

        model.addAttribute("members", members);
        return "members";
    }
}

위 코드는 이전 코드와 동일하게 동작하는 코드들이다. 차이점을 보자면

  1. 더이상 ModelAndView 객체를 반환하지 않아도 된다.
  2. HttpServlet 기술들을 직접 사용하지 않는다.
  3. HttpServletRequest를 대체하는 @ReqeustParma을 통해 직접 사용자의 파라미터 정보를 가져온다.
  4. HttpServletResponse를 대체하는 Model 객체가 존재하므로 view로 전달되는 데이터는 모두 model 객체에 담아서 넘기면 된다.

또한 어노테이션을 사용하며 method의 방식도 설정할 수 있는데

@RequestMapping(value = "/new-form", method = RequestMethod.GET)
public String process1(){
    return "new-form";
}

@RequestMapping(value = "/save", method = RequestMethod.POST)
public String process2(@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";
}

@RequestMapping(method = RequestMethod.GET)
public String process3(Model model) {
    List<Member> members = memberRepository.findAll();

    model.addAttribute("members", members);
    return "members";
}

다음과 같이 method를 사용하거나 @GetMapping, @PostMapping을 통해 method의 방식도 설정하여 사용할 수 있다.

@GetMapping(value = "/new-form")
public String process1(){
    return "new-form";
}

@PostMapping(value = "/save")
public String process2(@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 process3(Model model) {
    List<Member> members = memberRepository.findAll();

    model.addAttribute("members", members);
    return "members";
}

출처 https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글