MVC-1

황규혁·2023년 7월 28일

Spring 원리

목록 보기
2/5

1. MVC - 구조 이해

MVC 뜻

MVC (모델-뷰-컨트롤러) 는 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴이다. 소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있다. 이러한 "관심사 분리" 는 더나은 업무의 분리와 향상된 관리를 제공한다.

DispatcherServlet 구조 살펴보기

    1. 핸들러 조회 : 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러를 조회
    1. 핸들러 어댑터 조회 : 핸들러를 처리할 수 있는 어댑터 : 핸들러를 실행할 수 있는 핸들러 어댑터를 조회
    1. 핸들러 어댑터 실행
    1. 핸들러 어댑터를 통해 핸들러 실행
    1. ModelAndView 반환
    1. 뷰 리졸버를 통해서 뷰 찾기
    1. View 반환 : 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환
    1. 뷰 렌더링

핸들러 매핑과 핸들러 어댑터

  • HandlerMapping(핸들러 매핑)

    사용자의 요청과 이 요청을 처리하는 Handler를 매핑해주는 역할을 하는 것

  • HandlerAdapter(핸들러 어댑터)
    - 핸들러 매핑에서 리턴받은 핸들러 객체를 가지고 이에 맞는 어댑터를 찾는 과정
    - 여기서 어댑터란, 2개 이상의 인터페이스에 스펙이 맞지 않을 때, 중간에 이 스펙을 맞도록 변환해주는 역할을 하는 객체

뷰 리졸버

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

@Controller

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

@RequestMapping

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

ModelAndView

  • 모델과 뷰 정보를 담아서 반환하면 됨.

Model 파라미터

  • Model을 파라미터로 받을 수 있음

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으로 더욱 편리하게 사용 가능함

@RestController

  • @Controller 는 반환 값이 String 이면 뷰 이름으로 인식됨
  • @RestController 는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력

@RequestMapping("hello-basic")

  • /hello-basic URL 호출이 오면 이 메서드가 실행되도록 매핑
  • 대부분의 속성을 배열[] 로 제공하므로 다중 설정이 가능하다. {"/hello-basic", "/hello-go"}
    -> 다른 url이지만 스프링이 같은 것으로 매핑해줌

HTTP 메서드

  • @RequestMapping 에 method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출.
    -> 따라서 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE

PathVariable(경로 변수) 사용

  • 변수명이 같으면 생략 가능
  • ex) @PathVariable("userId") String userId -> @PathVariable userId
 @GetMapping("/mapping/{userId}")
  public String mappingPath(@PathVariable("userId") String data) {
      return "ok";
  }
  • @RequestMapping 은 URL 경로를 템플릿화 할 수 있는데, @PathVariable 을 사용하면 매칭 되는 부분을 편리하게 조회할 수 있음.

PathVariable 사용 - 다중

@GetMapping("/mapping/users/{userId}/orders/{orderId}")
  public String mappingPath(@PathVariable String userId, @PathVariable Long
  orderId) {
      return "ok";
  }

HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form HTTP 요청 데이터 조회 - 개요

클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 다음 3가지 방법을 사용.
1. GET - 쿼리 파라미터

  • /url?username=hello&age=20
  • 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
  • ex) 검색, 필터, 페이징등에서 많이 사용하는 방식

GET 쿼리 파리미터 전송 방식이든, POST HTML Form 전송 방식이든 둘다 형식이 같으므로 구분없이 조회할 수 있음.
이것을 간단히 요청 파라미터(request parameter) 조회라 함.

  • HTTP 요청 파라미터 - @RequestParam

스프링이 제공하는 @RequestParam 을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있음.

    • @RequestParam 사용
    • 파라미터 이름으로 바인딩
    • @ResponseBody 추가
    • View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
  • HTTP 요청 파라미터 - @ModelAttribute

실제 개발을 하면 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어주어야 하는데 @ModelAttribute는 이를 자동화해줌

    • 스프링MVC는 @ModelAttribute 가 있으면 다음을 실행
    • HelloData 객체를 생성
    • 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾고 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩)
    • ex) 파라미터 이름이 username 이면 setUsername() 메서드를 찾아서 호출하면서 값을 입력
  • @RequestParam과 @ModelAttribute는 생략 가능함

  • String, int 같은 단순 타입 = @RequestParam

  • argument resolver 로 지정해둔 타입 외 = @ModelAttribute

  1. POST - HTML Form
  • content-type: application/x-www-form-urlencoded

  • 메시지 바디에 쿼리 파리미터 형식으로 전달 username=hello&age=20

  • ex) 회원 가입, 상품 주문, HTML Form 사용

  • 스프링 MVC는 다음 파라미터를 지원

  • HttpEntity: HTTP header, body 정보를 편리하게 조회

    • 메시지 바디 정보를 직접 조회
    • 요청 파라미터를 조회하는 기능과 관계 없음 @RequestParam X, @ModelAttribute X
  • HttpEntity는 응답에도 사용 가능

    • 메시지 바디 정보 직접 반환
    • 헤더 정보 포함 가능
    • view 조회X
  • HttpEntity 를 상속받은 다음 객체들도 같은 기능을 제공

  • RequestEntity

    • HttpMethod, url 정보가 추가, 요청에서 사용
  • ResponseEntity

    • HTTP 상태 코드 설정 가능, 응답에서 사용
  • @RequestBody

    • 메시지 바디 정보를 직접 조회(@RequestParam X, @ModelAttribute X)
    • HttpMessageConverter 사용 -> StringHttpMessageConverter 적용 *
  • @ResponseBody
    • 메시지 바디 정보 직접 반환(view 조회X)
    • HttpMessageConverter 사용 -> StringHttpMessageConverter 적용

요청 파라미터 vs HTTP 메시지 바디
요청 파라미터를 조회하는 기능: @RequestParam , @ModelAttribute HTTP 메시지 바디를 직접 조회하는 기능: @RequestBody

  1. HTTP message body에 데이터를 직접 담아서 요청
  • HTTP API에서 주로 사용, JSON, XML, TEXT - 데이터 형식은 주로 JSON 사용
  • POST, PUT, PATCH

@RequestBody 객체 파라미터

  • @RequestBody HelloData data

  • @RequestBody 에 직접 만든 객체를 지정할 수 있음

  • HttpEntity , @RequestBody 를 사용하면 HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 우리가 원하는 문자나 객체 등으로 변환해줌

  • HTTP 메시지 컨버터는 문자 뿐만 아니라 JSON도 객체로 변환해줌

// @RequestBody는 생략 불가능

HTTP 응답 - 정적 리소스, 뷰 템플릿

스프링(서버)에서 응답 데이터를 만드는 방법은 크게 3가지

  1. 정적 리소스
    웹 브라우저에 정적인 HTML, css, js를 제공할 때는, 정적 리소스를 사용
  • 정적 리소스 경로
src/main/resources/static

다음 경로에 파일이 들어있으면

src/main/resources/static/basic/hello-form.html

웹 브라우저에서 다음과 같이 실행하면 됨

http://localhost:8080/basic/hello-form.html

정적 리소스는 해당 파일을 변경 없이 그대로 서비스하는 것

  1. 뷰 템플릿 사용
    웹 브라우저에 동적인 HTML을 제공할 때는 뷰 템플릿을 사용

    뷰 템플릿을 거쳐서 HTML이 생성되고, 뷰가 응답을 만들어서 전달하는 것

    뷰 템플릿 경로

src/main/resources/templates

뷰 템플릿 생성

src/main/resources/templates/response/hello.html
  • String을 반환하는 경우 - View or HTTP 메시지
    @ResponseBody 가 없으면 response/hello 로 뷰 리졸버가 실행되어서 뷰를 찾고, 렌더링
  • @ResponseBody 가 있으면 뷰 리졸버를 실행하지 않고, HTTP 메시지 바디에 직접 response/hello 라는 문자가 입력
  • Thymeleaf 스프링 부트 설정
    build.gradle에 다음과 같음 라이브러리 추가
`implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'`
  1. HTTP 메시지 사용
    HTTP API를 제공하는 경우에는 HTML이 아니라 데이터를 전달해야 하므로, HTTP 메시지 바디에 JSON 같은 형식으로 데이터를 실어 보냄
  • @RestController
    @Controller 대신에 @RestController 애노테이션을 사용하면, 해당 컨트롤러에 모두 @ResponseBody 가 적용됨. 따라서 뷰 템플릿을 사용하는 것이 아니라, HTTP 메시지 바디에 직접 데이터를 입력. 이름 그대로 Rest API(HTTP API)를 만들 때 사용하는 컨트롤러임.

HTTP 메시지 컨버터

스프링 MVC는 다음의 경우에 HTTP 메시지 컨버터를 적용함.

  • HTTP 요청: @RequestBody , HttpEntity(RequestEntity) ,
  • HTTP 응답: @ResponseBody , HttpEntity(ResponseEntity) ,

HTTP 메시지 컨버터는 HTTP 요청, HTTP 응답 둘 다 사용됨

  • canRead() , canWrite() : 메시지 컨버터가 해당 클래스, 미디어타입을 지원하는지 체크
  • read() , write() : 메시지 컨버터를 통해서 메시지를 읽고 쓰는 기능

스프링 부트 기본 메시지 컨버터

 0 = ByteArrayHttpMessageConverter
 1 = StringHttpMessageConverter
 2 = MappingJackson2HttpMessageConverte
  • ByteArrayHttpMessageConverter : byte[] 데이터를 처리

    • 클래스 타입: byte[] , 미디어타입: / ,
      요청 예) @RequestBody byte[] data
      응답 예) @ResponseBody return byte[] 쓰기 미디어타입 application/octet-stream
  • StringHttpMessageConverter : String 문자로 데이터를 처리

    • 클래스 타입: String , 미디어타입: /
      요청 예) @RequestBody String data
      응답 예) @ResponseBody return "ok" 쓰기 미디어타입 text/plain
  • MappingJackson2HttpMessageConverter : application/json

    • 클래스 타입: 객체 또는 HashMap , 미디어타입 application/json 관련
      요청 예) @RequestBody HelloData data
      응답 예) @ResponseBody return helloData 쓰기 미디어타입 application/json 관련
  • HTTP 요청 데이터 읽기
    HTTP 요청이 오고, 컨트롤러에서 @RequestBody , HttpEntity 파라미터를 사용. 메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead() 를 호출.
    canRead() 조건을 만족하면 read() 를 호출해서 객체 생성하고, 반환

  • HTTP 응답 데이터 생성
    컨트롤러에서 @ResponseBody , HttpEntity 로 값이 반환
    메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite() 를 호출
    canWrite() 조건을 만족하면 write() 를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성한다.

요청 매핑 헨들러 어뎁터 구조

HTTP 메시지 컨버터는 핸들러 어댑터 쪽에서 사용됨.

  • 요청의 경우 @RequestBody 를 처리하는 ArgumentResolver 가 있고, HttpEntity 를 처리하는 ArgumentResolver 가 있음.
    이 ArgumentResolver 들이 HTTP 메시지 컨버터를 사용해서 필요한 객체를 생성하는 것.
  • 응답의 경우 @ResponseBody 와 HttpEntity 를 처리하는 ReturnValueHandler 가 있음.
    여기에서 HTTP 메시지 컨버터를 호출해서 응답 결과를 만듦.
profile
백엔드 개발자를 꿈꾸는 대학생입니다

1개의 댓글

comment-user-thumbnail
2023년 7월 28일

정리가 잘 된 글이네요. 도움이 됐습니다.

답글 달기