본문 바로가기
스프링

[스프링] 스프링 MVC

by moonstal 2022. 6. 9.

스프링 MVC - 구조

  1. 핸들러 조회
  2. 핸들러 어댑터 조회
  3. 핸들러 어댑터 실행
  4. 핸들러 실행
  5. ModeelAndView 반환
  6. viewResolver 호출
  7. View반환
  8. render 호출

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

  • HandlerMapping(ex.스프링 빈의 이름으로 핸들러를 찾을 수 있는 핸들러 매핑)
    • RequestMappingHandlerMapping
  • HandlerAdapter(핸들러를 실행할 수 있는 핸들러 어댑터 필요)
    • RequestMappingHandlerAdapter

뷰 리졸버

  • return new ModelAndView("new-form");
  • BeanNameViewResolver: 빈 이름으로 뷰를 찾아서 반환
  • InternalResourceViewResolver: JSP 처리할 수 있는 뷰 반환

스프링 MVC - 시작

  • @RequestMapping 애노테이션을 사용하는 컨트롤러, 요청 정보 매핑(URL 호출)
  • @Controller : 자동으로 스프링 빈으로 등록(@Component 컴포넌트 스캔 대상)
  • ModelAndView : 모델과 뷰 정보 담아서 반환, mv.addObject("member", member)

스프링 MVC - 컨트롤러 통합

  • 클래스 단위 -> 메서드 단위
  • @RequestMapping 클래스 레벨과 메서드 레벨 조합

스프링 MVC - 실용적인 방식

  • Model 도입
  • ViewName 직접 반환
  • @RequestParam 사용
  • @RequestMapping(value = "/new-form", method = RequestMethod.GET) -> @GetMapping

스프링 MVC - 기본 기능

로깅

  • 로그 선언
    • private Logger log = LoggerFactory.getLogger(getClass());
    • @Slf4j
  • 로그 호출: log.info("hello")
  • 로그 출력 포멧: 시간, 로그 레벨, 프로세스 ID, 쓰레드 명, 클래스명, 로그 메시지
  • LEVEL: TRACE > DEBUG(개발 서버) > INFO(운영 서버) > WARN > ERROR
  • application.properties
    • logging.level.root=info(전체 로그 레벨)
    • logging.level.hello.springmvc=debug(hello.springmvc 패키지와 하위 로그 레벨)

요청 매핑

  • @Controller: 반환 값 String-> 뷰 이름으로 인식

  • @RestController: HTTP 메시지 바디에 바로 입력

  • HTTP 메서드 매핑 축약: @GetMapping(value = "/mapping-get-v2")

  • PathVariable(경로 변수)

    //@PathVariable 의 이름과 파라미터 이름이 같으면 생략 가능
    @GetMapping("/mapping/{userId}")
    public String mappingPath(@PathVariable("userId") String userId)
    public String mappingPath(@PathVariable String userId)
    
    //PathVariable 사용 - 다중
    @GetMapping("/mapping/users/{userId}/orders/{orderId}")
    public String mappingPath(@PathVariable String userId, @PathVariable Long orderId)
  • 미디어 타입 조건 매핑

    // HTTP 요청 Content-Type, consume
    @PostMapping(value = "/mapping-consume", consumes = "application/json")
    
    //HTTP 요청 Accept, produce
    @PostMapping(value = "/mapping-produce", produces = "text/html")

요청 매핑 - API

  • 회원 목록 조회: GET /users
  • 회원 등록: POST /users
  • 회원 조회: GET /users/{userId}
  • 회원 수정: PATCH /users/{userId}
  • 회원 삭제: DELETE /users/{userId}

HTTP 요청 - 기본, 헤더 조회

  public String headers(
      HttpServletRequest request,
      HttpServletResponse response,
      HttpMethod httpMethod,
      Locale locale,
      @RequestHeader MultiValueMap<String, String> headerMap,
      @RequestHeader("host") String host,
      @CookieValue(value = "myCookie", required = false) String cookie
   )

HTTP 요청 파라미터

  • 요청 파라미터(request parameter) 조회
    • request.getParameter("username");
    • public String requestParam(@RequestParam("username") String username)
    • public String requestParam(@RequestParam String username)// 파라미터이름==변수이름 ("username") 생략가능
    • public String requestParam(String username) //단순타입 @RequestParam 생략가능(required=false)
    • @RequestParam(required = true, defaultValue = "guest") 기본값
    • @RequestParam Map<String, Object> paramMap / @RequestParam MultiValueMap
  • HTTP 요청 파라미터 - @ModelAttribute
    • public String modelAttribute(@ModelAttribute Data Data)
    • public String modelAttribute(Data Data)//@ModelAttribute 생략

HTTP 요청 메시지

  • HTTP 요청 메시지 - 단순 텍스트

    1. ServletInputStream inputStream = request.getInputStream();
       String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
       response.getWriter().write("ok");
    
    2. public void requestBodyString(InputStream inputStream, Writer responseWriter)
       String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
       responseWriter.write("ok");
    
    3. public HttpEntity<String> requestBodyString(HttpEntity<String> httpEntity)
       String messageBody = httpEntity.getBody();
       return new HttpEntity<>("ok");
    
    4. @ResponseBody
       public String requestBodyString(@RequestBody String messageBody)
       return "ok";
  • HTTP 요청 메시지 - JSON

    1. private ObjectMapper objectMapper = new ObjectMapper(); 
       public void requestBodyJson(HttpServletRequest request, HttpServletResponse response)
       ServletInputStream inputStream = request.getInputStream();
       String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
       Data data = objectMapper.readValue(messageBody, Data.class);
    
    2. @ResponseBody
       public String requestBodyJson(@RequestBody String messageBody)
       Data data = objectMapper.readValue(messageBody, Data.class);
    
    3. @ResponseBody
       public String requestBodyJson(@RequestBody Data data)
       //@RequestBody 생략 불가(application/json)<->@ModelAttribute
    
    4. @ResponseBody
       public String requestBodyJson(HttpEntity<Data> httpEntity)
       Data data = httpEntity.getBody();
    
       @ResponseBody
       public String requestBodyJson(@RequestBody Data data)
       return data; //응답도 가능
    
-  HttpEntity , @RequestBody -> HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 문자나 객체 등으로 변환


### HTTP 응답 

- 정적 리소스: 웹 브라우저에 정적인 HTML, css, js(src/main/resources/static)
- 뷰 템플릿: 웹 브라우저에 동적인 HTML(src/main/resources/templates)
- HTTP 메시지 사용: 데이터 전달
- 뷰 템플릿 호출
  1. ModelAndView mav = new ModelAndView("response/hello").addObject("data", "hello!");
    return mav;
  2. return "response/hello";
  3. Void 반환 요청 URL(/response/hello) 참고->templates/response/hello.html
    
    
  • HTTP 응답 - HTTP API, 메시지 바디에 직접 입력
    1. response.getWriter().write("ok");
    2. return new ResponseEntity<>("ok", HttpStatus.OK);
    3. @ResponseBody return "ok";
    4. return new ResponseEntity<>(helloData, HttpStatus.OK);
    5. @ResponseStatus(HttpStatus.OK)
       @ResponseBody
       return helloData;
    6. @RestController=@Controller+@ResponseBody

HTTP 메시지 컨버터

  • HTTP의 BODY에 문자 내용 직접 반환
  • @ResponseBody 사용: viewResolver 대신 HttpMessageConverter 동작
  • 대상 클래스 타입과 미디어 타입 체크
  • 기본 문자처리: StringHttpMessageConverter(text/plain)
  • 기본 객체처리: MappingJackson2HttpMessageConverter(application/json)
  • byte[] 데이터 처리: ByteArrayHttpMessageConverter(application/octet-stream)
  • HTTP 요청: @RequestBody , HttpEntity(RequestEntity)
  • HTTP 응답: @ResponseBody , HttpEntity(ResponseEntity)

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

  • RequestMappingHandlerAdapter -> ArgumentResolver의 supportsParameter() -> HTTP 메시지 컨버터 사용 파라미터의 값(객체) 생성-> 컨트롤러(핸들러) -> ReturnValueHandler-> HTTP 메시지 컨버터 사용->응답 결과

스프링 MVC - 웹 페이지 만들기

  • 상품 도메인 개발: Item(상품 객체), ItemRepository(상품 저장소)

    //컨트롤러
    @GetMapping
    public String items(Model model) {
        List<Item> items = itemRepository.findAll();
        model.addAttribute("items", items);
        return "basic/items";
     }
    
    //타임리프(서버사이드 렌더링)
    <html xmlns:th="http://www.thymeleaf.org">
    th:href="@{/css/bootstrap.min.css}"
    th:onclick="|location.href='@{/basic/items/add}'|"
    <tr th:each="item : ${items}">
        <td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
        <td><a href="item.html" th:href="@{|/basic/items/${item.id}|}"th:text="${item.itemName}">상품명</a></td>
        <td th:text="${item.price}">10000</td>
        <td th:text="${item.quantity}">10</td>
    </tr>
    //상품 등록 컨트롤러
    1. (@ModelAttribute("item") Item item, Model model)
       model.addAttribute("item", item); //자동 추가, 생략 가능
    
    2. (@ModelAttribute Item item)// name 생략 가능,
       model.addAttribute("item", item); //자동 추가, 생략 가능, 첫글자 소문자
    
    3. public String addItem(Item item) 전체 생략
    
### 리다이렉트
- 리다이렉트: return "redirect:/basic/items/{itemId}";
- PRG Post/Redirect/Get: 중복 등록 방지
- RedirectAttributes: URL 인코딩, pathVarible, 쿼리 파라미터 처리

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

타임리프

```
링크
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1

'스프링' 카테고리의 다른 글

검증  (0) 2022.06.17
타임리프  (0) 2022.06.16
[스프링] MVC 프레임워크  (0) 2022.06.09
[스프링] 서블릿, JSP, MVC 패턴  (0) 2022.06.09
[스프링] 웹 애플리케이션 이해, 서블릿  (0) 2022.06.09