[Spring MVC 1] - HTTP 요청 데이터
HTTP 요청 메세지를 통해 클라이언트에서 서버로 데이터를 전달하는 3가지 방법
- GET 쿼리 파라미터
- POST-HTML Form
- HTTP API 메세지 바디
HTTP 요청 데이터 - GET 쿼리 파라미터
- /url ?username=rosieposie&age=22
- 메세지 바디없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
- 예) 검색, 필터, 페이징 등에서 많이 사용하는 방식
@WebServlet(name="requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
System.out.println("[전체 파라미터 조회] -start");
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> System.out.println("paramName = "+request.getParameter(paramName)));
System.out.println("[전체 파라미터 조회] -end");
System.out.println();
System.out.println("[단일 파라미터 조회] -start");
String username = request.getParameter("username");
String age = request.getParameter("age");
System.out.println("username = "+username);
System.out.println("age = "+age);
System.out.println();
System.out.println("[이름이 같은 복수 파라미터 조회] - start");
String[] usernames = request.getParameterValues("username");
for(String name : usernames){
System.out.println("username = "+name);
}
System.out.println("[이름이 같은 복수 파라미터 조회] - end");
response.getWriter().write("ok");
}
}
RequestParamServlet이라는 클래스를 만들고, 위와 같이 코드 작성하고 서비스를 띄운다.
https://dev-rosiepoise.tistory.com/10 서블릿 만들기는 이전 포스팅 참고!
http://localhost:8080/request-param?username=rosieposie&age=22&username=rose 이렇게 요청을 하면
결과
[전체 파라미터 조회] -start
paramName = rosieposie
paramName = 22
[전체 파라미터 조회] -end
[단일 파라미터 조회] -start
username = rosieposie
age = 22
[이름이 같은 복수 파라미터 조회] - start
username = rosieposie
username = rose
[이름이 같은 복수 파라미터 조회] - end
** 복수 파라미터에서 단일 파라미터 조회
request.getParameterValues()를 사용하여 배열로 꺼내서 사용하고, request.getParameter()사용시에는 request.getParameterValues()의 첫번째 값을 반환한다.
** response.getWriter()를 통해 writer 객체를 가지고 와서 해당 객체를 통해 write메소드를 이용하여 response body message를 생성하여 응답
HTTP 요청 데이터 - POST HTML Form
- content-type: application/x-www-form-unlencoded -----> 컨텐트 타입은 웹브라우저가 만들어준다.
- 웹 브라우저가 생성한 요청 HTTP 메세지
POST /save HTTP/1.1
Host: localhost:8080
Content-Type:application/x-www-form-urlencoded
username=rosieposie&age=22
- 메세지바디에 쿼리파라미터 형식으로 데이터를 전달 username=rosieposie&age=22
- 예) 회원가입, 상품 주문, HTML Form 사용
- 내용은 쿼리파라미터 (get방식)과 동일하기 때문에 reqeust.getParameter로 꺼낼 수 있음
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/request-param" method="post">
username: <input type="text" name="username"/>
age: <input type="text" name="age"/>
<button type="submit">전송</button>
</form>
</body>
</html>
webapp에 basic 폴더 생성하고 hello-form.html 파일 생성하여 위와 같이 코드 작성
서비스를 띄우고 http://localhost:8080/basic/hello-form.html에서 내용을 작성하고 전송버튼을 클릭한다.
POST의 HTML Form을 전송하면 웹 브라우저는 다음 형식으로 HTTP 메시지를 만든다
- 요청 URL : http://localhost:8080/request-param
- content-type : application/x-www-form-urlencoded
- message body : username=rosieposie&age=100
application/x-www-form-urlencoded 형식은 GET 쿼리 파라미터 형식과 같다. 쿼리 파라미터 조회 메서드를 그대로 사용해도 된다.
클라이언트(웹 브라우저) 입장에서는 두 방식에 차이가 있지만, 서버입장에서는 둘의 형식이 동일(message body 부분)하므로 reqeust.getParameter를 사용할 수 있다.
** content-type은 HTTP 메세지 바디의 데이터 형식을 지정한다
GET URL 쿼리 파라미터 형식으로 클라이언트에서 서버로 데이터 전달을 할 때는 HTTP 메세지 바디 방식을 사용하지 않기 때문에 content-type이 없고, POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기 때문에 바디에 포함된 데이터가 어떤 형식인지 content-type을 꼭 지정해야 한다. 이렇게 폼으로 데이터를 전송하는 형식을 application/x-www--form-urlencoded라고 한다
결과
username=rosiepoise&age=100]
[전체 파라미터 조회] -start
paramName = rosiepoise
paramName = 100
[전체 파라미터 조회] -end
[단일 파라미터 조회] -start
username = rosiepoise
age = 100
[이름이 같은 복수 파라미터 조회] - start
username = rosiepoise
[이름이 같은 복수 파라미터 조회] - end
HTTP 요청 데이터 - API 메세지 바디 - 단순 텍스트
- HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에 주로 사용, json, xml, text
- 데이터 형식은 주로 json 사용
- POST, PUT, PATCH
@WebServlet(name="requestBodyStringServlet", urlPatterns = "/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {
@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);
response.getWriter().write("ok");
}
}
RequestBodyStringServlet 이라는 클래스를 생성하고 서비스를 띄운다
- getInputStream을 사용하면 메세지바디 내용을 바이트 코드로 얻을 수 있음 (inputStream은 byte코드를 반환)
- 바이트코드를 스트링으로 변환을 해야하는데 인코딩 타입을 알려줘야 함 ----> UTF-8
포스트맨으로 post, raw-text 형식으로 설정하고 메세지를 보내면 위와 같이 응답을 받음을 확인 할 수 있음
결과
hi!!!!
HTTP 요청 데이터 - API 메세지 바디 - json
- JSON 형식 전송
- POST http://localhost:8080/request-body-json
- content-type: "application/json"
- message body : {"username"="rosieposie", "age":100}
- 결과 messageBody = {"username"="rosieposie", "age":100}
@Getter @Setter
public class HelloData {
private String username;
private int age;
}
JSON 형식으로 파싱할 수 있도록 객체를 생성 --> hello.servlet.basic.HelloData
lombok을 사용하여 getter와 setter를 생성한다.
@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {
private 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);
response.getWriter().write("ok");
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
System.out.println("helloData.username = "+helloData.getUsername());
System.out.println("helloData.age = "+helloData.getAge());
response.getWriter().write("ok");
}
}
RequestBodyJsonServlet 이라는 클래스를 생성하고 서비스를 띄운다
- HelloData로 변환시키기 위해서는 라이브러리가 필요함 (스프링부트는 기본 json라이브러리를 제공 : jackson)
결과
messageBody = {"username":"rosieposie", "age":100}
helloData.username = rosieposie
helloData.age = 100
당연하게 여겼던 것들을 하나씩 비교하고 자세히 들여다보니 생각보다 나는 모르고 있는게 많구나를 느꼈다. 비단 코드 뿐만이아니라 우리가 편리해지기 위해 자동화되고 간소화된 모든것들이 이런 패턴화로 이루어져있고, 후자에 익숙해져버린 나는 굳이? 라는 이유로 전자를 이해하지 않으려한다는 것이다. 직접 장을 보러가는 대신 마켓컬리나 쿠팡을, 직접 칼질이나 손질이 필요한 야채나 채소를 구입하기 보다는 손질 되어져 있고 이미 조리화된 음식을 소비하는 것 등등 인간을 위한 자동화나 간소화가 본질을 들여다 보면 결코 우리를 위함이 아님을 조금씩 느끼고 있다. 그러므로 바보가 되기 싫으면.. 공부해라 로지포지..ㅋ
@ 스프링 MVC 1편 - 백엔드 웹개발 by 김영한을 참조하고 있습니다.