미완성

미완성) 스프링 MVC 요약

꾸준함의 미더덕 2024. 8. 30. 13:51

# 서블릿 이전

* 서블릿이 존재하기 이전에 개발자가 기존 서버에서 처리해야했던 업무
- 서버 TCP/IP 연결 대기, 소켓 연결
- HTTP 요청 메시지 파싱해서 읽기
- POST 방식, /save URL인지
- Content-Type 확인
- HTTP 메시지 바디 내용 파싱
- 저장 프로세스 실행
- 비즈니스 로직 실행  ->  데이터베이스에 저장 요청 — 서블릿이 비즈니스 로직 제외하고 전부 대신해 준다.
- HTTP 응답 메시지 생성
- HTTP 시작 라인 생성
- Header 생성
- 메시지 바디에 HTML 생성
- TCP/IP에 응답 전달, 소켓종료

 



# 서블릿 (HTTP 지원 + 멀티쓰레드 지원)
- HTTP 관련 기술 + 멀티쓰레드 기술을 지원해줘서 개발자가 비즈니스 로직 구현에 집중할 수 있게 해주는 기술임!

@WebServlet(name=“helloServlet”, urlPatterns=“/hello”)
public class HelloServlet extends HttpServlet{

	@Override
	protected void servied(HttpServletRequest request, HttpServletResponse reponse){
    // 애플리케이션 로직
   }
}

- urlPatterns의 URL이 호출되면 서블릿 코드가 실행
- 개발자는 HTTP스펙을 매우 편리하게 사용가능

- HTTP 요청시
- WAS는 Request, Respones 객체를 새로 만들어서 서블릿 객체를 호출함
- WAS는 Responos객체에 담겨 있는 내용으로 HTTP 응답 정보를  생성

 



# 서블릿 컨테이너
- 개발자가 코드로 작성한 서블릿 클래스를 서블릿 컨테이너가 객체로 생성, 호출, 관리를 해준다.
- 톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 함
- 서블릿 객체는 싱글톤으로 관리
- 최초 로딩 시점에 서블릿 객체를 미리 만들어두고 재활용(HttpServletRequest, HttpServletResponse는 요청시 생성 - 요청 내용이 각각 다르므로)
- 동시 요청을 위한 멀티쓰레드 처리 지원

## 동시 요청 - 멀티 쓰레드
### 쓰레드
- 애플리케이션 코드를 하나하나 순차적으로 실행하는 것은 쓰레드
- 자바 메인 메서드를 처음 실행하면 main이라는 이름의 쓰레드가 실행
- 쓰레드는 한 번에 하나의 코드 라인만 수행
- 동시처리가 필요하다면 쓰레드를  추가로 생성

- 요청 마다 쓰레드 생성시 당점
- 생성비용이 비싸서 응답속도 늦어짐
- 컨텍스트 스위칭 비용 : 사실 코어 하나가 작동하는 것이기 때문에 비용 발생
- 쓰레드 생성에 제한이 없으면 CPU, 메모리 임계점을 넘어서 서버가 죽을 수도 있음
— > 쓰레드풀로 보완

### 쓰레드 풀
-  톰캣은 최대 200개 기본 설정
- 쓰레드풀의 적정 숫자는 상황에 따라 다르다.
- 성능 테스트 : 툴을 사용하여 성능 테스트 아파치 ab, 제이티머, nGrinder

### WAS의 멀티쓰레드 지원
- 멀티쓰레드의 부분은 WAS가 처리해주므로 개발자는 멀티쓰레드 관련 코드를 신경쓰지 않아도 됨
- 싱글톤 객체(서블릿, 스프링빈)은 주의해서 사용

 



# 스프링 웹플럭스
- 비동기 넌 블러킹
- 최소 쓰레드로 최대 성능 - 컨텍스트 스위칭 비용 효율
- 함수형 스타일로 개발하여 동시처리 코드 효율화
- 서블릿 기술 사용X

 



# HttpServletRequest - 개요
- 서블릿 컨테이너는 HTTP 요청 메시지를 개발자 대신에 파싱하고 결과를 HttpServletRequest 객체에 담아 제공함

- HttpServletRequest 객체는 추가로 여러가지 부가기능도 함께 제공함
- 임시 저장소 기능 : 해당 HTTP요청이 시작부터 끝날 때까지 유지되는 임시 저장소
— request.setAttribute(name, value);
— request.getAttriute(name);
- 세션관리 기능
— request.getSession();

 

 




#Http 요청 데이터 - 개요

 


[베스트 프랙티스 관점에서 이해하자]
- GET : 메시지 바디 없이 URL의 쿼리파라미터에 데이터 포함해서 전달
- POST - HTML Form : 메시지 바디에 쿼리 파라미터 형식으로 전달(Content-Type : application/x-www-form-urlencoded)
- POST&PUT&PATCH - HTTP message body 에 직접 담아서 요청 : 형식은 주로 JSON  

 



# HTTP Parameter- 쿼리 파라미터

- 주로 GET

/**
 * GET - 쿼리 파라미터 & POST- x-www-form-urlencoded  
 * 요청 형식이 같기 때문에 서블릿에서 동일하게 받을 수 있다 !! (parameter데이터인지 body데이터인지는 다르지만)
 * 
 * 1. 쿼리 파라미터
 * http://localhost:8080/request-param?username=hello&age=20
 * 2. HTML 폼데이터 
 * 요청 url: http://localhost:8080/request-param
 * content-type: application/x-www-form-urlencoded
 * message body: username=hello&age=20
 *

@WebServlet(name=“requestParamServlet”, urlPatterns=“/request-param”)
public class HelloServlet extends HttpServlet{

	@Override
	protected void servied(HttpServletRequest request, HttpServletResponse reponse){
		// 전체 파라미터 조회
		request.getParameterNames();
		// 단일 파라미터 조회
		String username = request.getParameter(“username”);
		String age = request.getParameter(“age”);
		// 이름이 같은 복수 파라미터 조회 ex) username=hello&username=kim
        // 하지만 중복으로 보내는 경우 거의 없다!
		String[] usernames = request.getParameterValues(“username”);
   }
}

 

 

# HTTP Message Body

- HTTP 메시지 바디의 데이터를 InputStream을 사용해서 직접 읽을 수 있음 

 


## HTTP Message Body - contentType :  application/x-www-form-urlencoded

- 기본적으로 데이터가 body를 통해 전송되므로 메시지 바디를 직접 읽어서 데이터를 가져올 수도 있음

-> 하지만 HttpServletRequest에서 getParameter(), getParameterValues()로 받을 수가 있음! (쿼리 파라미터와 데이터 형식이 같이 때문에)

-> 보통 편리한 방식인 HttpServletRequest#GetParameter()를 사용

 

- 메시지 바디에 쿼리 파라미터 형식으로 데이터를 전달 username=hello&age=20   

- 위에서 GET요청을 받았던 서블릿 메서드로 동일하게 받을 수가 있다.

 

 

## HTTP Message Body - contentType : text/plain

@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // body 데이터를 byte 코드로 바로 얻을 수 있음
        ServletInputStream inputStream = request.getInputStream();
        // byte to String
        // 항상 byte <-> String 변환 시 어떤 인코딩인지 알려줘야함
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        System.out.println(messageBody);
        response.getWriter().write("ok");
    }
}

 

 

## HTTP Message Body - contentType : application/json

@WebServlet(name = "requestBodySosnServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {
    private ObjectMapper objectMapper;
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
    }
}

 

 

 

# HTTP 응답데이터 - API JSON

- applicaion/json은 스펙상 urf-8형식을 사용하도록 정의되어 있음

- 그래서 스펙상 charset=utf-8같은 추가 파라미터를 지원하지 않음 

-> application/json;charset-utf-8 같은 것은 무의미

-> 하지만 reponse.getWriter();사용하면 추가 파라미터를 자동으로 추가함

-> response.getOutputStream()으로 출력하면 문제 없음