스프링MVC

Seung jun Cha·2022년 6월 16일
0
post-thumbnail

1.HTTP요청 데이터

  • HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법을 알아보자

1-1 GET 쿼리 파라미터

  • 메시지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달
  • 쿼리 파라미터는 URL에 다음과 같이 ? 를 시작으로 보낼 수 있다. 추가 파라미터는 & 로 구분하면 된다.
    ex)http://localhost:8080/request-param?username=hello&age=20
    username(파라미터이름) - hello(값)

1-2 POST HTML Form

  1. 주로 웹 페이지에서 사용자가 입력한 데이터를 서버로 전송하는 데 사용된다

  2. HTTP 메시지 바디에 쿼리 파라미터 형식으로 인코딩되어 전달됩니다.

  3. 서버가 값을 받는 형식은 GET 메서드의 쿼리 파라미터 방식과 유사하게 key-value 쌍으로 전달됩니다.

  4. 다만, POST 메서드를 사용할 경우, 데이터는 URL에 노출되지 않고 HTTP 메시지 바디에 포함되어 전송됩니다.

  5. 폼 데이터는 application/x-www-form-urlencoded 또는 multipart/form-data 형식으로 전송된다

1-3 API 메시지 바디(단순 텍스트)

1-4 API 메시지 바디 - JSON

  1. JSON.parse() : 일반 문자열도 객체화 됨
    ( parse("{}") -> list / parse("null") -> 진짜 null)

객체 -> stringfy -> 문자열 -> Parse -> 객체

2. 스프링MVC 개념

2-1 MVC 개념

  • 스프링에서 웹을 개발하기 위한 아키텍처 패턴

(1)Model : 비즈니스 로직을 실행하고 DB와의 상호작용을 담당한다. 그리고 필요한 데이터를 모델 객체에 저장하여 뷰와 컨트롤러로 전달한다.
@ModelAttribute, @Vaild 등 데이터의 유효성 검사를 지원

(2)View : 비즈니스 로직의 실행 결과를 전달받아 동적으로 화면을 만들거나 정직 리소스를 표시한다. 다양한 템플릿 엔진이 사용될 수 있다.

(3)Controller : 클라이언트 요청을 처리하고, 비즈니스 로직을 호출하며, 뷰를 선택하여 데이터를 전달한다.

  • 서버와 클라이언트는 HTTP를 사용해 요청과 응답을 주고 받음

  • WAS, DB에 장애가 발생했을 때 WEB서버가 오류화면 제공가능

2-2 서블릿

  • 서블릿은 웹 애플리케이션의 핵심 구성 요소 중 하나로, 클라이언트의 HTTP 요청을 처리하고 동적인 웹 컨텐츠를 생성하는 자바 클래스
  • 개발자가 핵심 비즈니스 로직 구현에만 집중할 수 있게 전후 단계를 자동으로 처리해줌
    • 전단계는 HTTP 요청을 받아 파싱, 세션 관리 등이있고, 후단계는 응답 컨텐츠를 생성하고 클라이언트에게 반환 등이 있다.
  • Http요청, 응답정보를 쉽게 사용할 수 있게 HttpServeletRequest, HttpServeletResponse 제공
    => 서블릿 컨테이너인 WAS에서 싱글톤으로 서블릿 관리

2-3 쓰레드

클라이언트 요청 - 쓰레드 할당 - 서블릿을 호출
애플리케이션 코드 하나씩 순차적으로 실행, 한번에 하나의 코드라인만 실행하며 동시처리가 필요하면 쓰레드를 추가로 생성
WAS가 멀티쓰레드 부분을 처리해주므로 싱글쓰레드를 다루듯이 코딩

  • 쓰레드 생성의 장단점
    • 장점 : 동시요청 처리가능, 쓰레드 하나가 지연되어도 나머지는 정상작동
    • 단점 : 쓰레드 생성비용, 스위칭비용, CPU와 메모리의 한계로 서버가 죽을 수 있음 (이를 보완하기 위해 쓰레드풀을 사용)

3. 스프링MVC 구조

3-1 MVC 작동원리, 순서

  • http요청이 들어오면 DispacherServlet의 doDispacher 메서드가 호출됨
    • 스프링 부트는 DispacherServlet을 서블릿으로 자동으로 등록하면서 모든 경로( urlPatterns="/" )에 대해서 매핑한다.
  1. 핸들러 조회와 매핑 : Dispacher Servlet이 url정보를 받아서 어떤 핸들러를 사용할 것인지 결정(매핑)
  1. 해당하는 핸들러를 처리할 수 있는 어댑터 조회

  2. 어댑터를 실행하면서 handle메서드를 실행

  3. ModelAndView 반환 : 핸들러가 반환하는 정보를 어댑터가 ModelAndView로 변환해서 Model에 담아 View의 논리이름을 반환(html파일이름)

  4. 뷰 리졸버 호출

  5. 뷰 리졸버를 통해 랜더링 및 뷰 반환 : Dispacher Servlet이 뷰 이름을 리졸버에게 전달하고 뷰 리졸버는 미리 설정된 경로와 확장자를 가지고 물리이름으로 바꾼 후 뷰 객체를 반환

4. 스프링MVC 기능

4-1 @Controller

클래스레벨이 붙어있으면 빈으로 등록하면서 핸들러 매핑정보로 인식한다.
(매핑정보로 인식되는 것은 나중에 매핑이 필요할 때 서블릿이 탐색을 함)

  • @Controller : 클라이언트의 request를 처음으로 받아주는 곳, View를 반환하기 위해 사용 , service에서 필요한 값이 DB에 있는지 DAO를 통해 확인을 하고 값의 유무와 결과에 따라 어떤 view를 보여줄 것인지 선택
    (Data를 반환하려면 @ResponseBody사용)

4-2 @RestController

  • Controlelr + 메서드레벨의 ResponseBody => 클래스의 전체 메서드에 @ResponseBody를 적용
    return의 값으로 뷰를 가져오는 것이 아닌 JOSN형태의 문자로 반환되어 나옴

4-3 @RequestParam

  • @RequestParam(value = “파라미터이름”, required = ) 타입 변수명
    • http요청 파라미터를 받아서 가져와서 변수에 넣어줌(쿼리파라미터, Post form와 똑같음)
    • 변수명과 파라미터 이름이 동일하면 @RequestParam의 value는 생략가능, required도 필수값이 아님
      (요청파라미터가 객체타입이 아닌 단순타입이라면 @RequestParam 어노테이션까지 생략이 가능하지만 직관성이 떨어진다)
    • 해당하는 값이 없어도 어플리케이션이 작동가능하게 하려면 required = false로 설정
  1. @RequestParam(required=true, false) : true가 기본값, false인 경우 값을 입력하지 않으면 null이 들어감(->int 등 기본형인 경우 Integer 등 객체형으로 바꾸어 주어야 null이 들어갈 수 있음)
  2. @RequestParam(defaultValue = " ") : 요청파라미터로 null이 아닌 아무 값도 넘어오지 않았을 때빈문자인 경우에 들어갈 기본값
    defaultValue가 설정되어 있는 경우 required=false 설정은 의미가 없음(기본값이 항상 들어가기때문에)

@RequestParam, @ModelAttribute, @PathVriable 모두 스프링이 자동으로 형변환을 해줌

파라미터를 Map에 저장해두고 get으로 가져올 수도 있음(Map<String,Object> ParamMap)

4-4 @ModelAttribute

  • @ModelAttribute(“해당 객체를 이용하기 위해 뷰에 전달할 이름”) + 객체
    주로 HTML 폼으로부터 전송된 데이터를 수신하는 데 사용됩니다.
    =>HTTP 요청파라미터(URL쿼리스트링, POST form을 다룰 때 사용)
    =>필드 단위로 적용되므로 특정필드에 타입오류가 발생해도 나머지 필드는 정상처리 가능
    =>컨버전 서비스 자동 적용
    => DAO가 하는 기능을 수행한다? DAO는 DB에 접근하여 데이터를 삽입, 수정, 삭제 등을 하는 객체로 MVC에서는 model이 이 기능을 수행한다.
    => 어떤 컨트롤러를 호출하던지 서버의 시간을 호출하고 싶으면 글로번 컨트롤러(@ContorllerAdvice - 공통적인 예외처리나 로깅을 찍을 때 사용) 클래스에서 메서드로 적용
  1. @ModelAttribute가 붙은 객체를 자동으로 생성

  2. 생성된 객체에 http요청 파라미터 또는 입력폼에서 넘어온 값을 객체의 속성과 자동으로 바인딩
    (파라미터 이름과 객체 or 객체안의 객체의 속성이름이 동일한 것끼리 바인딩)하고 setter를 호출해 세팅 (set이 없으면 값이 설정되지 않고 데이터 타입도 맞아야함)

  3. 바인딩 된 값이 설정된 객체가 자동으로 Model객체에 추가되고 뷰까지 전달됨
    (Model파라미터도 필요없음, model.attribute를 자동으로 실행)
    (검증오류가 발생했을 때, 입력폼에 값이 그대로 남아있는 이유는 값이 입력된 객체가 뷰로 넘어갔기 때문)

  4. @ModelAttribute(“뷰에 전달할 객체의 이름”) 을 생략하면 객체의 클래스명의 첫글자를 소문자로 바꾼 이름이 자동으로 들어가서 전달됨(ex Item -> “item”)
    ->해당 객체의 이름으로 뷰에서 활용됨(th:object=“${..}”)

  5. @ModelAttribute까지도 생략이 가능하다. (추천하지는 않음)

4-5 @PathVariable

  • 경로변수(url경로에 {변수}를 넣음 = Url경로를 템플릿화)
    @PathVariable의 변수명과 파라미터명이 같으면 @PathVariable 파라미터명은 생략가능
    @PathVariable(“ ”) 변수명
    ex)@PathVariable("username") String username
    ex)@GetMapping("http://localhost:8080/request-param/{username}")

4-6 @PostMapping의 consumes, produces

  • consumes : HTTP 요청의 Content-Type 헤더를 기반으로 미디어 타입을 매핑한다. 클라이언트가 서버에 요청값을 보낼 때, 해당 메시지의 데이터타입
    ex) @PostMapping(Url = " " , consume = "application/json") -> Http요청의 Content-Type 헤더타입이 json인 경우에만 해당 url로 메서드를 호출가능(만약 맞지 않으면 HTTP 415 상태코드 반환)

  • produces : HTTP 요청의 Accept 헤더를 기반으로 미디어 타입으로 매핑한다 , 서버가 클라이언트에게 응답값을 보낼 때, 해당 메시지의 데이터타입
    만약 맞지 않으면 HTTP 406 상태코드(Not Acceptable)을 반환

4-7 @RequestBody, @ResponseBody

  • Http메시지바디를 통해 직접 데이터가 넘어오는 경우에는 @RequestParam, @ModelAttribute를 사용할 수 없다(바이트코드로 넘어옴) @RequestParam, @ModelAttribute는 요청파라미터를 조회하는 기능임

  • HttpEntity<>를 상속 받은 RequestEntity<>, ResponseEntity<>가 있음

    • RequestEntity<> : HttpMethod, url 정보가 추가, 요청에서 사용 -> 파라미터에 @RequestBody
    • ResponseEntity<> : HTTP 상태 코드 설정 가능, 응답에서 사용 -> 메서드레벨에 @ResponseBody
      Http메시지컨버터는 Http메시지바디를 읽어서 문자나 객체로 변환해주는 역할
  • @RequestBody

    • 클라이언트가 서버로 데이터를 JSON, XML, 또는 기타 형식으로 보낼 때 사용됩니다. 특히 RESTful 웹 서비스에서 API를 설계할 때 매우 유용합니다
  1. HTTP 메시지 바디를 직접 읽음: HTTP 요청의 바디 데이터를 읽어옵니다.

  2. HttpMessageConverter를 사용한 변환: HttpMessageConverter를 통해 JSON 또는 XML 데이터를 자바 객체로 변환합니다.

  3. 파라미터: 이 애노테이션이 붙은 파라미터는 HTTP 메시지 바디의 내용을 읽어와서 해당 타입의 자바 객체로 변환됩니다. 그리고 매핑된 메서드 파라미터로 전달됩니다

  4. Content-Type: 클라이언트가 요청할 때 Content-Type을 application/json 등으로 설정해야 합니다.
    비동기 처리: 주로 비동기 요청에서 사용됩니다.

-> @RequestBody는 생략불가능(생략하면 @ModelAttribute가 적용되어 요청파라미터로 처리됨
->이 어노테이션이 붙은 파라미터에는 Http 바디의 문자가 그대로 전달된다

@PostMapping("/example")
public ResponseEntity<ExampleResponse> exampleMethod(@RequestBody ExampleRequest request) {
    // request는 HTTP 바디의 JSON 데이터를 자바 객체로 변환한 것
    return ResponseEntity.ok(new ExampleResponse());
}

}
  • 과정
  1. 클라이언트가 폼에 데이터를 입력하고 JSON 형식으로 서버에 전송합니다. (자바스크립트나 자바의 라이브러리를 사용해서 JSON 형식으로 변환)

  2. 컨트롤러 메서드는 @RequestBody를 사용하여 요청 바디의 JSON 데이터를 자바 객체로 변환합니다. (HttpMessageConverter 사용)

  3. 서비스 계층에서 회원가입 비즈니스 로직을 처리합니다.

  • @ResponseBody : 메서드레벨에 사용, 자바 메서드의 반환 값을 HTTP 응답 바디에 직접 작성하도록 합니다. 이를 통해 JSON 또는 XML 형식으로 데이터를 클라이언트에 전송할 수 있습니다.
    자바객체를 HTTP 요청의 본문(Body)내용으로 매핑하여 클라이언트로 전송한다. return값이 문자로 반환됨(retuen View x), 전체 객체단위로 적용되므로 컨버터 작동이 성공해서 객체가 만들어져야 다음 단계로 넘어갈 수 있음
    HTTP 상태코드를 변경하지 않아도 되는상황에 API통신을 할 때 @ResponseBody를 사용
    HTTP 상태 코드도 변경해야할 때는 ResponseEntity(@ResponseBody랑 기능은 같음)

4-8 @RequestPart

  • @RequestPart를 사용할 때, 파일 업로드를 처리할 경우 MultipartFile 타입의 매개변수를 선언할 수 있습니다.
    이 경우, Spring MVC는 MultipartResolver를 통해 HTTP 요청의 파일 파트를 처리합니다. MultipartResolver는 파일 업로드를 위한 전용 핸들러로, 들어온 파일을 MultipartFile 객체로 변환하여 매개변수로 전달합니다.

  • @RequestPart를 사용하여 JSON 데이터와 같은 다른 타입의 파트를 처리할 때는 HttpMessageConverter가 사용됩니다. HttpMessageConverter요청 본문에서 JSON 데이터를 추출하고 이를 Java 객체로 변환하는 역할을 합니다. 이 경우, JSON 데이터는 @RequestPart에 지정된 매개변수 타입으로 변환됩니다.

5. RedirectAttribute

  1. redirect:/url : 반복적으로 POST가 호출되는 상황을 방지, post를 처리하는 컨트롤러와 redirect되어 들어온 url을 get방식으로 처리하는 컨트롤러 2개가 작동한다.
    (1) post 방식으로 데이터처리를 요청하면 controller A에서 데이터를 처리하고 브라우저에는 다른 주소로 redirect응답
    (2) 브라우저는 이동해야하는 redirect 주소를 받고 get방식으로 해당 url을 호출
    (3) controller B가 get방식으로 데이터를 처리하고 응답메시지 전송

  2. RedirectAttributes: 그냥 redirect을 하면 기존의 요청데이터가 다 사라지는데 기존의 데이터를 다 살리면서 redirect하고 싶으면 RedirectAttributes를 사용한다.
    (1) addAttribute() : 리다이렉트할 URL에 쿼리스트링으로 데이터가 넘어감
    (2) addFlashAttribute : 일회용으로만 뷰에 데이터를 전달하고 삭제되는 값을 지정(새로고침하면 값이 사라짐), addFlashAttribute가 addAttribute를 호출하면 세션에 저장했다가 redirect 되고나서 세션에 저장된 값을 가지고 옴

  • Post 후에 새로 고침 문제를 해결하려면 상품 저장 후에 뷰 템플릿으로 이동하는 것이 아니라, 상품 상세 화면으로 리다이렉트를 호출해주면 된다.
    RedirectAttributes 를 사용하면 URL 인코딩도 해주고, pathVarible , 쿼리 파라미터까지 처리해준다.
    • pathVariable 바인딩: {itemId}
    • 바인딩이 안된 나머지는 쿼리 파라미터로 처리: ?status=true
  • redirect : 다음 문자열이 "/"로 시작하면 웹 어플리케이션을 기준으로 이동 경로를 생성하고, 그렇지 않으면 현재 경로를 기준으로 상대경로를 사용한다.
@PostMapping("/add")
public String addItemV6(Item item, RedirectAttributes redirectAttributes) {
 	Item savedItem = itemRepository.save(item);
 	redirectAttributes.addAttribute("itemId", savedItem.getId());
 	redirectAttributes.addAttribute("status", true);
 	return "redirect:/basic/items/{itemId}";
}
@RequestMapping("/members")

      return "redirect:/members/login";
=> localhost:/members/login 

      return "redirect:members/login";
=> localhost:/members/members/login

0개의 댓글