강의 내용이 있기 때문에 출처를 밝힙니다 !
출처 : 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 (인프런 강의)
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의
웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -
www.inflearn.com
1. 클래스 생성
@WebServlet 어노테이션을 활용해 클래스를 서블릿 컨테이너에서 관리하도록 설정한다.
그리고 name, urlPatterns 을 정의한다.
해당 클래스는 HttpServelt 클래스를 상속받도록 하고, protected void service() 메서드를 구현한다.
GET 방식의 쿼리 파라미터를 조회했던 클래스를 똑같이 사용해서 진행해보자.
@WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
... 내부 구현은 여기서 ...
}
}
2. service(HttpServletRequest request, HttpServletResponse response) 내부에서 연습
클래스를 서블릿에 등록했으니, service() 메서드 내부에시 파라미터를 조회할 수 있다 ~
연습 전에 HTML Form 방식을 한 번 살펴보자.
공식 문서 한 번 읽어보기 (https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/POST)
HTML Form 방식으로 요청 데이터를 보낼 때는 3가지 타입의 Content-Type 을 사용할 수 있다.
1. application/x-www-form-urlencoded
&으로 분리되고, "=" 기호로 값과 키를 연결하는 key-value tuple로 인코딩되는 값.
영어 알파벳이 아닌 문자들은 percent encoded 으로 인코딩됩니다.
따라서, 이 content type은 바이너리 데이터에 사용하기에는 적절치 않습니다.
바이너리 데이터에는 multipart/form-data 를 사용해 주세요.
2. multipart/form-data
바이너리 데이터 (이미지 등) 에 사용하는 타입
3. text/plain
단순 텍스트(String) 에 사용하는 타입
즉, application/x-www-form-urlencoded 타입을 사용하면 바디에 요청 값이 담길 뿐 GET 방식의 쿼리 파라미터 방식과
본질적으로 동일하다고 할 수 있다.
GET 방식의 쿼리 파라미터 형식으로 클라이언트에서 서버로 데이터를 전달할 떄는 따로 메세지 바디가 없기 때문에 따로
Content-Type 이 존재하지 않는다. 근데 POST 방식의 HTML Form 형식으로 데이터를 전달할 때에는 메세지 바디에 데이터를
포함해서 보내기 때문에, 포함된 데이터가 어떤 형식인지 Content-Type 을 꼭 지정해줘야 한다 !
그렇다면 포스트맨을 사용해 데이터를 전송해보자.
단순 스트링도 아니고, 바이너리 데이터를 요청 데이터에 담아 서버에 보내는 것이 아니기 떄문에 반드시 요청 데이터의
Content-Type 을 x-www-form-urlencoded 로 설정해야 한다 ...!
Content-Type 을 application/x-www-form-urlencoded 로 설정했다면 쿼리 파라미터 형태로 요청 데이터가 메세지 바디에 담겨
있기 때문에 request.getParameter() 를 활용해 조회할 수 있다.
(위에서 언급했듯 서버에서는 x-www-form-urlencoded 타입을 쿼리 파라미터 방식과 동일한 방식으로 보기 때문에)
System.out.println("[전체 파라미터 조회] 시작");
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> System.out.println(paramName + "=" +
request.getParameter(paramName)));
System.out.println("[전체 파라미터 조회] - 끝");
System.out.println();
System.out.println("[단일 파라미터 조회 - 시작]");
String username = request.getParameter("username");
System.out.println("username = " + username);
String age = request.getParameter("age");
System.out.println("age = " + age);
System.out.println("[단일 파라미터 조회 - 끝]");
System.out.println();
System.out.println("[이름이 같은 복수 파라미터 조회] - 시작");
String[] usernames = request.getParameterValues("username");
for (String name : usernames) {
System.out.println("name = " + name);
}
System.out.println("[이름이 같은 복수 파라미터 조회] - 끝");
}
서버 출력 결과
잘 출력되는 것을 확인할 수 있다.
이번에는 단순 String 조회
먼저 getInputStream() 을 사용해 ServletinputStream 타입으로 요청을 저장한다. (바이트 코드 형태로 저장하는 것)
StreamUtils.copyToString() 을 통해 저장한 바이트 코드를 String 타입으로 변환한다. 이 때 바이트 코드를 String 타입으로 변환하기
위해서는 꼭 인코딩 타입을 지정해줘야 한다 !
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandarcCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
포스트맨을 사용해서 서버에 요청을 보내보자.
계속 언급하지만, POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기 때문에 Content-Type 을 꼭 명시해줘야 한다. 몇 가지의 타입이 있지만 2가지의 Content-Type 을 연습해보도록 하자.
첫 번째로, text/plain 으로 Content-Type 을 명시했을 경우 (raw 선택 후 Text 로 지정하면 알아서 text/plain 으로 타입이 잡힌다.)
서버 출력 결과
클라이언트에서 보낸 요청 데이터의 단순 텍스트가 잘 출력되는 것을 확인할 수 있다.
두 번째로, x-www-urlencoded 으로 Content-Type 을 명시했을 경우
서버 출력 결과
클라이언트에서 보낸 요청 데이터가 쿼리 파라미터 형식으로 잘 출력되는 것을 확인할 수 있다.
왜 ? Content-Type 을 application/x-www-form-urlencoded 로 설정했다면 쿼리 파라미터 형태로 요청 데이터가 메세지 바디에 담겨 있기 때문이다. 단순 텍스트도 이렇게 쿼리 파라미터 형태로 데이터가 전송된다. 잊지말자 ㅎ....😵💫 그냥 인코딩이 쿼.리.파.라.미.터로..
이번에는 가장 자주 사용하는 방식인 JSON 형식의 데이터를 메세지 바디에 담아 전송해보자.
새로 서블릿 클래스를 하나 생성하고, JSON 형식의 데이터를 파싱하기 위한 클래스를 하나 더 생성한다.
보통 JSON 형식 데이터는 객체로 파싱해서 해당 객체를 이용하는 방식으로 사용하기 때문이다.
@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
... 내부 구현은 여기서 ...
}
}
package hello.servlet.basic;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class HelloData {
private String username;
private int age;
}
내부 구현을 추가해보자.
메세지 바디를 String 으로 뽑아내야하는데, JSON 이라고 단순 텍스트로 온 요청 데이터를 가져오는 방식과 다르지 않다.
JSON 데이터를 받아서 객체 내부의 데이터로 파싱하기 위해서는 ObjectMapper 객체의 도움이 필요하다.
objectMapper.readValue() 메서드를 사용해 JSON 데이터를 담고 있는 변수와 파싱하고 싶은 객체를 인자로 넣어 사용하면 된다.
사실 ObjectMapper 를 이용해 데이터를 파싱할 때 파싱하고 싶은 객체에 Setter 가 없어도 private 한 변수에 잘 파싱된다.
왜냐면, ObjectMapper 는 JSON 데이터가 객체에 파싱될 때 Getter를 통해서 JSON 데이터와 매핑할 필드 이름을 인식하고,
Setter가 있으면 Setter를 호출해 값을 파싱하지만, Setter가 없으면 필드에 직접 입력하기 때문이다. (무섭다)
@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
System.out.println("helloData.getUsername = " + helloData.getUsername());
System.out.println("helloData = " + helloData.getAge());
response.getWriter().write("ok");
}
}
역시 포스트맨을 사용해서 요청을 보내보자.
raw 선택 후 JSON 을 선택하고 JSON 형식으로 메세지 바디 내부를 잘 채워주자.
서버 출력 결과
메세지 바디와 파싱한 객체의 값이 모두 잘 출력된 것을 확인할 수 있다.
그냥 인강만 들었을 때는 궁금한게 딱히 생기지 않았는데, 이렇게 정리하려고 포스팅 하다보니 머리 속에 정말 많은 물음표가 생겼다.
공식 문서도 뒤적이고 필요한 부분은 인강도 다시 들어보고 커뮤니티 질문 글도 확인하며 정리하니 확실히 예전보다 HTML Form 방식을 이해할 수 있었다. 두고두고 봐야겠다 .. ☺️
'Servlet' 카테고리의 다른 글
FrontController 를 통한 MVC 패턴 구조 개선 [2] (0) | 2022.04.03 |
---|---|
FrontController 를 통한 MVC 패턴 구조 개선 [1] (0) | 2022.04.03 |
Servlet 에 MVC 패턴 도입하기 (0) | 2022.04.03 |
[GET] 클라이언트 요청 쿼리 파라미터를 서버로 전달하기 (0) | 2022.03.30 |