내가 공부한것을 올리며, 중요한 단원은 저 자신도 곱씹어 볼겸 상세히 기록하고 얕은부분들은 가겹게 포스팅 하겠습니다.
5. HTTP 요청 데이터 - POST HTML Form
이번 시간에는 HTML의 Form을 이용해서 클라이언트에서 서버로 데이터를 전달하는 방법을 공부하였다.
● 특징
- content-type: application/x-www-form-urlencoded
- 메시지 바디에 쿼리 파리미터 형식으로 데이터를 전달한다. username=hello&age=20
우선 간단한 HTML 하나를 src/main/webapp/basic/hello-form.html 에 생성해보자.
<!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>
스프링 부트를 실행한 후, http://localhost:8080/basic/hello-form.html 로 접속해 보자.
username 과 age 를 입력하는 부분이 있다. 각각 test, 25라 적은후 전송 버튼을 눌러주었다.
전송 버튼을 누르면 다음과 같은 HTTP 메시지를 서버에 전달해주게 된다.
- 요청 URL: http://localhost:8080/request-param
- content-type: application/x-www-form-urlencoded
- message body: username=test&age=25
그림으로 보면 다음과 같다.
POST 방식은 GET과는 다르게 context-type: application/x-www-form-urlencoded 이 추가되어 있다.
또한 message body부분에는 쿼리 파라티터같은 형식으로 데이터가 담겨있다.
=> username=test&age=25
따라서 쿼리 파라미터 조회 메서드를 그대로 재사용할 수 있다.
클라이언트 입장에서는 보낼때 사용하는 GET, POST 둘간에 차이가 있지만, 서버 입장에서는 둘의 형식이 동일하므로request.getParameter()를 사용해서 인자를 추출할수 있다.
이제 메시지를 전달받을 /request-param 의 코드를 살펴보자.
@WebServlet(name = "RequestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse 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("단인 파라미터 조회");
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("이름이 같은 복수 파라미터 조회");
String[] usernames = request.getParameterValues("username");
for (String name : usernames) {
System.out.println("username = " + name);
}
response.getWriter().write("ok");
}
}
결과는 다음과 같다.
원하는 결과를 출력받을 수 있게되었다.
● content-type은 HTTP 메시지 바디의 데이터 형식을 지정한다.
- GET URL 쿼리 파라미터 형식으로 클라이언트에서 서버로 데이터를 전달할 때는 HTTP 메시지 바디를 사용하지 않기 때문에 content-type이 없다.
- POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기 때문에 바디에 포함된 데이터가 어떤 형식인지 content-type을 꼭 지정해야 한다. 이렇게 폼으로 데이터를 전송하는 형식을 application/x-www-form-urlencoded 라 한다.
6. HTTP 요청 데이터 - API 메시지 바디 - 단순 텍스트
● HTTP message body에 데이터를 직접 담아서 요청한다.
- HTTP API에서 주로 사용, JSON, XML, TEXT
- 데이터 형식은 주로 JSON 사용
- POST, PUT, PATCH
일반적으로 단순 텍스트 보단 JSON 형태로 데이터를 보내지만, 우선 TEXT를 보내는것부터 확인해 보자.
@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(); // body 데이터를 바이트로 추출
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
response.getWriter().write("ok");
}
}
request.getInputStream()메서드는 byte 코드를 반환한다.
byte 코드를 우리가 읽을 수 있는 문자(String)로 보려면 문자표 (Charset)를 지정해주어야 한다. 여기서는 UTF_8 Charset을 지정해주었다.
이제 Postman을 사용하여 데이터를 보내보자.
간단하게 hello! 라는 문자열을 보냈다.
콘솔창에 결과로 messageBody = hello 가 출력되었다.
7. HTTP 요청 데이터 - API 메시지 바디 - JSON
드디어 JSON 형태로 데이터를 전송해보는 시간이다!
● JSON 형식 전송
- POST방식으로 http://localhost:8080/request-body-json 에 데이터를 보내면 된다.
- content-type: application/json
- message body: {"username": "hello", "age": 20} => 메시지 바디 부분에 포함된 JSON 데이터
- 결과: messageBody = {"username": "hello", "age": 20}
● JSON 형식 파싱 추가
JSON 형식의 데이터가 오면, 이 데이터를 객체로 바꾸기 위한 class를 하나 만들자.
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class HelloData {
private String username;
private int age;
}
lombok이 제공하는 @Getter, @Setter 를 사용했다. getter 와 setter를 애노테이션 프로세스를 통하여 자동 생성해 준다.
코드가 정말 간단해졌다.
이제 JSON을 받은 서블릿 코드를 작성해 보자.
@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);
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
System.out.println("helloData.getUsername = " + helloData.getUsername());
System.out.println("helloData.getAge = " + helloData.getAge());
response.getWriter().write("OK");
}
}
위에서 데이터를 저장할 HelloData class를 만들었다. 어떻게 HelloData 객체에 전달받은 데이터를 저장할까?
=> ObjectMapper()를 이용하면 된다.
이전과 같이 getInputStream()으로 바이트 코드를 전달받은 후, StreamUtils를 통하여 String으로 전달받는다.
이 String 정보를 objectMapper.readValue() 메서드의 인자로 전달하여 helloData 객체를 생성하면 된다.
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
JSON 결과를 파싱해서 사용할 수 있는 자바 객체로 변환하려면 Jackson, Gson 같은 JSON 변환 라이브러리를 추가해서 사용해야 한다.
스프링 부트로 Spring MVC를 선택하면 기본으로 Jackson 라이브러리( ObjectMapper )를 함께 제공한다.
이번에는 HTML 이 아닌! Postman을 사용하여 데이터를 보내보자!
- POST http://localhost:8080/request-body-json
- content-type: application/json (Body -> raw, 가장 오른쪽에서 JSON 선택)
- message body: {"username": "hello", "age": 20}
결과는 다음과 같다.
추가로 HTML Form 데이터도 메시지 body를 통하여 데이터를 전송하기 때문에 직접 읽을 수 있다.
하지만 이미 이를 위한 getParameter()라는 편리한 메서드가 제공하기 때문에 이를 사용하면 된다.
8. HttpServletResponse - 기본 사용법
● HTTP 응답 메시지 작성하기
- HTTP 응답코드 지정
- 헤더 생성
- 바디 생성
● 편의 기능 제공
- Content-type, 쿠기, Redirect
우선 가장 간단하게 Header 정보만 추가하여 반환해보자.
@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// status-line
response.setStatus(HttpServletResponse.SC_OK);
// response-headers
response.setHeader("Content-Type", "text/plain;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("my-header", "hello");
// message body
PrintWriter writer = response.getWriter();
writer.println("OK");
}
}
반환받은 메시지의 Header를 열어보면 다음과 같다.
위 코드에서 추가했던 부분들이 모두 Header 정보에 들어갔다.
또한 우리가 정의한 my-header 또한 추가된것을 확인할수 있다.
● content()라는 메서드를 만들어서 확인해 보자.
@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// status-line
response.setStatus(HttpServletResponse.SC_OK);
// response-headers
// response.setHeader("Content-Type", "text/plain;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("my-header", "hello");
// header 편의 메서드
content(response);
// message body
PrintWriter writer = response.getWriter();
writer.println("OK");
}
private void content(HttpServletResponse response) {
// Content-Type: text/plain;charset=utf-8
// Content-Length: 2
// response.setHeader("Content-Type", "text/plain;charset=utf-8")
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
// response.setContentLength(2); //(생략시 자동 생성)
}
}
content()메서드 안에서 setContentType()으로 contentType을 지정하였으며,
setCharacterEncoding() 메서드를 통해서 인코딩을 지정해 주었다.
따라서 Service()메서드에서 원래 지정하던 부분은 주석처리 하였다.
// response.setHeader("Content-Type", "text/plain;charset=UTF-8");
추가적으로 ContentLength는 생략하면 자동으로 생성하여 추가해 준다. 원한다면 직접 추가할 수 있다.
response.setContentLength(2); //(생략시 자동 생성)
● Cookie() 메서드를 추가해 보자.
@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// status-line
response.setStatus(HttpServletResponse.SC_OK);
// response-headers
// response.setHeader("Content-Type", "text/plain;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("my-header", "hello");
// header 편의 메서드
content(response);
cookie(response);
// message body
PrintWriter writer = response.getWriter();
writer.println("OK");
}
private void content(HttpServletResponse response) {
// 생략
}
private void cookie(HttpServletResponse response) {
// Set-Cookie: myCookie=good; Max-Age=600;
// response.setHeader("Set-Cookie", "myCookie=good; Max-Age=600");
Cookie cookie = new Cookie("myCookie", "good");
cookie.setMaxAge(600); //600초
response.addCookie(cookie);
}
}
반환받은 response 메시지를 보면 다음과 같다.
Cookie가 설정된것을 알수 있다. 우리가 지정한 myCookie가 설정되어있다.
이후 새로고침을 하여 request를 보내게 되면 request정보에 Cookie가 전달되는것을 알 수 있다.
● redirect()메서드를 추가했다
다음 코드를 살펴보자.
@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// status-line
response.setStatus(HttpServletResponse.SC_OK);
// response-headers
// response.setHeader("Content-Type", "text/plain;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("my-header", "hello");
// header 편의 메서드
content(response);
redirect(response);
// message body
PrintWriter writer = response.getWriter();
writer.println("OK");
}
private void content(HttpServletResponse response) {
// 생략
}
private void redirect(HttpServletResponse response) throws IOException {
//Status Code 302
//Location: /basic/hello-form.html
//response.setStatus(HttpServletResponse.SC_FOUND); //302
//response.setHeader("Location", "/basic/hello-form.html");
response.sendRedirect("/basic/hello-form.html");
}
}
"/response-header" 로 접속하면 sendRedirect()메서드를 통하여 "hello-form.html"로 이동하게 된다.
처음 /response-header로 요청후, response 응답으로 302를 받게된다. 다음 사진을 확인해 보자.
또한 Location으로 리다이렉트할 URL이 포함되어 있다.
이 메세지를 받은 Client는 리다이렉트 하게된다.
9. HTTP 응답 데이터 - 단순 텍스트, HTML
HTTP 응답 메시지는 주로 다음 내용을 담아서 전달한다.
- 단순 텍스트 응답 => 앞에서 살펴봄 ( writer.println("ok"); )
- HTML 응답
- HTTP API - MessageBody JSON 응답
우선 HTML응답부터 확인해 보자. 다음 코드를 살펴보자.
@WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
public class ResponseHtmlServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Content-type
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<body>");
writer.println(" <div>안녕?</div>");
writer.println("</body>");
writer.println("</html>");
}
}
결과는 다음과 같다.
HTTP 응답으로 HTML을 반환할 때는 content-type을 text/html 로 지정해야 한다.
HTML이 정상적으로 출력되었다.
10. HTTP 응답 데이터 - API JSON
이번에는 HTTP응답 데이터를 JSON으로 전달해보자!
다음 코드를 살펴보자.
@WebServlet(name = "responseJsonServlet", urlPatterns = "/response-json")
public class ResponseJsonServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Content-Type: application/json
response.setHeader("content-type", "application/json");
response.setCharacterEncoding("utf-8");
HelloData data = new HelloData();
data.setUsername("zbqmgldjfh");
data.setAge(20);
//{"username":"zbqmgldjfh","age":20}
String result = objectMapper.writeValueAsString(data);
response.getWriter().write(result);
}
}
위의 코드를 보면 이전에 사용한 HelloData 클래스 객체를 생성한 후, 값을 지정하고, ObjectMapper를 이용하여 알맞은 JSON string문자열로 바꿔준다.
이후 이를 출력하면 다음과 같은 결과를 얻을 수 있다.
'BackEnd > Spring MVC' 카테고리의 다른 글
[Spring] MVC 프레임워크 만들기 - 1 (0) | 2022.02.19 |
---|---|
[Spring] 서블릿, JSP, MVC 패턴 (0) | 2022.02.17 |
[Spring] 서블릿 - 1 (0) | 2022.02.13 |
[Spring] 웹 애플리케이션 이해 (0) | 2022.02.12 |
[Spring] 스프링 MVC 프레임워크 (0) | 2022.01.31 |
댓글