Spring MVC

2025. 4. 30. 15:09·SpringBoot
728x90
반응형
SMALL

목차

1. Spring@MVC

2. @Controller

3. @Controller 단위 테스트

4. Handler 메서드의 파라미터

 

Spring MVC란?

- MVC 기반(model2)의 Web Application을 작성하기 위한 Spring Framework의 하위 모듈

 

- Front controller pattern : Dispatcherservlet

  - / 경로를 처리하므로 모든 요청을 받아들임

  - Action parameter방식이 아닌 URL 기반으로 요청 분기

 

- 주요 특징

  - Annotaion 기반 -> spring @MVC

  - 다양한 view 지원

  - restful 웹 서비스 지원

  - 테스트 용

 

Spring@MVC 구성요소

- DispatcherServlet

  - 가장 중추적인 역할

  - Front Controller pattern의 적용으로 client의 모든 request 접수

  - 주로 다른 객체들 (Infrastructure Component)에게 위임하여 처리

 

- Spring@MVC  Infrastructure Component

  - Handler Mapping : 이런 request 받았는데 어떤 Handler가 처리할 수 있나요?

  - Handler Adapter : XXHandler에게 request 좀 처리 해달라고 해~

  - ViewResolves : 이런 뷰가 필요한데 부탁해요~

 

- 프로그래머가 작성할 부분

  - model 영역(service/dao)

  - View page

  - Handler

 

Spring MVC이전 웹 프로그래밍

- 서블릿

/**
 * 회원 관련 요청을 처리하는 서블릿 컨트롤러 클래스.
 * URL 패턴 "/member" 로 들어오는 모든 요청을 이 클래스가 담당합니다.
 */
@WebServlet("/member")
public class MemberControllerServlet extends HttpServlet {

    // 비즈니스 로직을 수행할 Service 객체를 생성 (구현체는 MemberServiceImpl)
    private final MemberService mService = new MemberServiceImpl();

    /**
     * 모든 HTTP 메서드(GET, POST 등)는 service() 메서드를 통해 처리됩니다.
     * 요청 파라미터 "action" 에 따라 알맞은 메서드를 호출해 분기 처리합니다.
     */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 클라이언트 요청으로 전달된 action 값을 읽어옴
        String action = req.getParameter("action");

        // action 파라미터가 없는 경우 400 Bad Request 에러 전송
        if (action == null) {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Action parameter is missing.");
            return;
        }

        // action 값에 따라 서로 다른 기능 메서드 호출
        switch (action) {
            case "member-detail" ->
                memberDetail(req, resp);       // 회원 상세 조회
            // case "member-list"    -> memberList(req, resp);     // 회원 목록 조회 예시
            // case "member-update"  -> memberUpdate(req, resp);   // 회원 정보 수정 예시
            default ->
                // 정의되지 않은 action 요청이면 404 Not Found 에러 전송
                resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown action: " + action);
        }
    }

    /**
     * 회원 상세 정보를 조회하여 JSP로 포워딩하는 메서드.
     * 요청 파라미터 "email" 을 기준으로 DB를 조회합니다.
     */
    private void memberDetail(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 요청 파라미터로 전달된 이메일을 읽어옴
        String email = request.getParameter("email");

        // 이메일이 없거나 빈 문자열인 경우 오류 메시지를 설정
        if (email == null || email.isBlank()) {
            request.setAttribute("alertMsg", "Email 파라미터가 없습니다.");
        } else {
            try {
                // Service를 호출해 이메일에 해당하는 회원 정보 조회
                Member member = mService.selectDetail(email);
                // 조회된 회원 객체를 request 범위에 "member" 속성으로 저장
                request.setAttribute("member", member);
            } catch (SQLException e) {
                // SQL 예외 발생 시 스택 트레이스 출력
                e.printStackTrace();
                // JSP에서 출력할 수 있도록 alertMsg 속성에 오류 메시지 저장
                request.setAttribute("alertMsg", "회원 정보 조회 중 오류 발생: " + e.getMessage());
            }
        }

        // 최종적으로 JSP 페이지로 포워드하여 화면 렌더링
        request.getRequestDispatcher("/member/member-detail.jsp")
               .forward(request, response);
    }

    // TODO: 추가적인 액션을 처리할 메서드를 아래에 구현할 수 있습니다.
    // 예) 회원 목록 조회, 회원 정보 수정, 회원 삭제 등
}

 

Model 2 아키텍처 (Servlet + JSP)

Servlet: Controller 역할

JSP: View 역할

Servlet에서 비즈니스 로직(또는 Service/DAO 호출)을 수행하고, 그 결과를 request.setAttribute()에 담아 JSP로 포워드

 

web.xml 기반 서블릿 매핑

web.xml에 <servlet>과 <servlet-mapping>으로 서블릿과 URL을 일일이 연결

요청이 들어오면 DispatcherServlet 같은 중앙 조정기가 없으므로, 각 서블릿이 직접 request.getParameter("action") 등을 보고 분기 처리

 

HttpServlet 기반 컨트롤러

수동 분기: switch나 if-else로 파라미터에 따라 메서드 호출

직접 포워드: RequestDispatcher를 사용해 JSP에 전달

JSP 스크립틀릿: <% Member m = (Member) request.getAttribute("member"); %> 형태로 값 출력

 

단점 및 한계

유지보수 어려움 : 액션이 늘어날수록 service()/doGet() 메서드 안의 분기문이 복잡해짐

반복 코드 : 파라미터 읽기·예외 처리·포워드 코드가 서블릿마다 중복

관심사의 분리(S.o.C) 미흡 : 웹 설정(web.xml), 컨트롤러, 뷰, 비즈니스 로직이 느슨하게만 분리

테스트 불편 : 서블릿 컨테이너 없이 단위 테스트가 거의 불가능

 


 

그렇다면 위의 Servlet이 Spring MVC코드로 어떻게 변환되는지 보기 전에 그림을 통해서 어떻게 동작하는지 알아보자.

mvc패턴 동작 방식

 

서버 시작 시

  • 스프링 컨텍스트가 로드되면서 @RequestMapping, XML 설정 등에 정의된 컨트롤러 매핑 정보들이 HandlerMapping에 등록된다.

요청 처리 흐름

  1. 클라이언트 요청 수신
    클라이언트가 URL/파라미터를 포함한 HTTP 요청을 보내면, 스프링의 DispatcherServlet이 가장 먼저 이 요청을 받는다.
  2. 핸들러 조회
    DispatcherServlet은 등록되어 있는 HandlerMapping들에게 “이 요청을 처리할 컨트롤러가 어디에 있나요?”라고 묻고, URL·HTTP 메서드에 맞는 핸들러(컨트롤러) 정보를 받아온다.
  3. 핸들러 어댑터 선택
    찾은 핸들러를 실행할 수 있는 HandlerAdapter를 DispatcherServlet이 결정한다. (예: RequestMappingHandlerAdapter)
  4. 컨트롤러 호출
    선택된 HandlerAdapter가 내부에서 실제 컨트롤러의 메서드(@RequestMapping이 붙은 메서드 등)를 호출한다.
    • 이때 컨트롤러는 Service → Repository를 차례로 호출해 비즈니스 로직과 데이터 조회/변경을 수행하고,
    • 결과 데이터를 Model에 담고 반환할 뷰 이름(view name)을 함께 내놓는다.
  5. ModelAndView 취합
    HandlerAdapter는 컨트롤러가 돌려준 ModelAndView 객체(모델 데이터 + 뷰 이름)를 DispatcherServlet에 전달한다.
  6. 뷰 해석
    DispatcherServlet은 ModelAndView에서 꺼낸 뷰 이름을 ViewResolver에 넘겨, 실제 렌더링 가능한 뷰 객체(JSP 뷰, Thymeleaf 뷰 등)를 얻어낸다.
  7. 뷰 렌더링
    얻어온 뷰 객체에 모델 데이터를 주입한 뒤 render(model, request, response)를 호출해 HTML/CSS/JS 결과물을 생성한다.
  8. 응답 반환
    최종적으로 생성된 HTML이 HTTP 응답 바디에 담겨 클라이언트(브라우저)로 전송되고, 사용자는 화면을 확인할 수 있다.

 

 

sevlet에서 spring mvc으로 변환 및 각 어노테이션 설명

Spring MVC 버전

@Controller
@RequestMapping("/member")
@RequiredArgsConstructor
public class MemberController {

    private final MemberService mService;

    /**
     * 회원 상세 조회
     * GET /member/detail?email={email}
     */
    @GetMapping("/detail")
    public String memberDetail(
            @RequestParam("email") String email,
            Model model) {

        if (email.isBlank()) {
            model.addAttribute("alertMsg", "Email 파라미터가 없습니다.");
        } else {
            try {
                Member member = mService.selectDetail(email);
                model.addAttribute("member", member);
            } catch (SQLException e) {
                model.addAttribute("alertMsg", "조회 중 오류: " + e.getMessage());
            }
        }
        // View 이름 반환 → /WEB-INF/views/member/member-detail.jsp 로 포워드
        return "member/member-detail";
    }
}

각 어노테이션 설명

어노테이션용도
@Controller MVC의 “Handler” 컴포넌트임을 선언. 스프링이 빈으로 관리하여 DispatcherServlet이 호출할 수 있게 함.
@RequestMapping 클래스·메서드 수준에서 URL 매핑 지정. 클래스 위에 쓰면 하위 모든 메서드에 공통 경로 prefix 적용.
@GetMapping @RequestMapping(method = GET)의 축약형. 주로 조회용 HTTP GET 요청 처리 메서드에 사용.
@PostMapping @RequestMapping(method = POST)의 축약형. 폼 제출 등 HTTP POST 요청 처리에 사용.
@RequestParam 쿼리 파라미터(?foo=bar)나 폼 필드 값을 메서드 파라미터로 바인딩. required, defaultValue 지정 가능.
@PathVariable URL 경로에 포함된 {id} 같은 변수를 메서드 파라미터로 바인딩. RESTful URI 설계 시 자주 사용.
Model 컨트롤러에서 뷰로 넘길 데이터를 담는 컨테이너. model.addAttribute("key", value) 후 뷰 템플릿에서 ${key}로 참조.
@Autowired (필드/생성자/세터) 의존성 자동 주입. 요즘은 생성자 주입 + Lombok의 @RequiredArgsConstructor 조합이 권장됨.
@ResponseBody 메서드 반환값을 뷰가 아닌 HTTP 응답 바디(JSON·문자열 등)로 바로 직렬화. @RestController안에 기본 포함.
@RestController @Controller + @ResponseBody의 합성 어노테이션. REST API용 핸들러임을 선언.

이렇게 바꾸면…

  • 분기 로직(switch, action 파라미터)이 사라지고
  • 메서드별 매핑으로 URL과 HTTP 메서드가 직관적으로 드러나며
  • 뷰 포워드는 단순히 문자열 리턴으로 대체되어 코드 중복이 크게 줄어든다.
728x90
반응형
LIST

'SpringBoot' 카테고리의 다른 글

AOP(Aspect Oriented Programming) - (2)  (5) 2025.04.25
AOP(Aspect Oriented Programming) - (1)  (0) 2025.04.25
DI(Dependency Injection) - (3)  (0) 2025.04.18
DI(Dependency Injection) - (2)  (0) 2025.04.18
DI(Dependency Injection) - (1)  (1) 2025.04.18
'SpringBoot' 카테고리의 다른 글
  • AOP(Aspect Oriented Programming) - (2)
  • AOP(Aspect Oriented Programming) - (1)
  • DI(Dependency Injection) - (3)
  • DI(Dependency Injection) - (2)
알파 조
알파 조
공부 일기장
  • 알파 조
    Blue Ocean
    알파 조
  • 전체
    오늘
    어제
    • 분류 전체보기 (93)
      • Algorithm (9)
      • Data Structure (3)
      • Python (7)
      • 컴퓨터 구조 요약 (6)
      • 몰입 교육 (7)
      • JavaScript (1)
      • Vue.js (7)
      • 코딩테스트 연습 (40)
      • SpringBoot (9)
      • 데이터베이스 (2)
  • 블로그 메뉴

    • Home
    • Computer structure
    • Algorithm
    • SpringBoot
    • Vuejs
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    리그오브레전드 #롤 #LOL #60프레임 버그 #GPU #윈도우10 #롤 60프레임 고정
    Udemy#Python#Bootcamp#Object and Data Structure Basics
    항해99
    잔디 기부 캠페인
    오블완
    Git
    MSA 기초
    티스토리챌린지
    잔디 기부
  • hELLO· Designed By정상우.v4.10.3
알파 조
Spring MVC
상단으로

티스토리툴바