주로 다음 3가지 방법을 사용한다.
GET - 쿼리 파라미터
POST - HTML Form
HTTP message body에 데이터를 직접 담아서 요청
메시지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달하자.
예) 검색, 필터, 페이징등에서 많이 사용하는 방식
쿼리파라미터는 URL에 다음과같이 ?
를 시작으로 보낼 수 있다.추가 파라미터는 &
로 구분하면 된다.
http://localhost:8080/request-param?username=hello&age=20
서버에서는 HttpServletRequest
가 제공하는 다음 메서드를 통해 쿼리 파라미터를 편리하게 조회할 수 있다.
쿼리 파라미터 조회 메서드
String username = request.getParameter("username"); //단일 파라미터 조회
Enumeration<String> parameterNames = request.getParameterNames(); //파라미터 이름들
모두 조회
Map<String, String[]> parameterMap = request.getParameterMap(); //파라미터를 Map으로
조회
String[] usernames = request.getParameterValues("username"); //복수 파라미터 조회
예시
/**
* 1. 파라미터 전송 기능
* http://localhost:8080/request-param?username=hello&age=20
* <p>
* 2. 동일한 파라미터 전송 가능
* http://localhost:8080/request-param?username=hello&username=kim&age=20 */
@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");
/*
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String paramName = parameterNames.nextElement();
System.out.println(paramName + "=" +
request.getParameter(paramName));
} */
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"); System.out.println("request.getParameter(username) = " + username);
String age = request.getParameter("age");
System.out.println("request.getParameter(age) = " + age);
System.out.println();
System.out.println("[이름이 같은 복수 파라미터 조회]"); System.out.println("request.getParameterValues(username)"); String[] usernames = request.getParameterValues("username"); for (String name : usernames) {
System.out.println("username=" + name);
}
response.getWriter().write("ok");
}
}
결과
직접 url에 접속해서 실행해보면 결과는 다음과 같다.
http://localhost:8080/request-param?username=hello&age=20
요청 URL: http://localhost:8080/request-param content-type: application/x-www-form-urlencoded
message body: username=hello&age=20
application/x-www-form-urlencoded
형식은 앞서 GET에서 살펴본 쿼리 파라미터 형식과 같다. 따라서 쿼 리 파라미터 조회 메서드를 그대로 사용하면 된다.
클라이언트(웹 브라우저) 입장에서는 두 방식에 차이가 있지만, 서버 입장에서는 둘의 형식이 동일하므로, request.getParameter()
로 편리하게 구분없이 조회할 수 있다.
content-type은 HTTP 메시지 바디의 데이터 형식을 지정한다.
GET URL 쿼리 파라미터 형식으로 클라이언트에서 서버로 데이터를 전달할 때는 HTTP 메시지 바디를 사용하 지 않기 때문에 content-type이 없다.
POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기 때문에 바디에 포함된 데이터가 어떤 형식인지 content-type을 꼭 지정해야 한다. 이렇게 폼으로 데이터를 전송하는 형 식을application/x-www-form-urlencoded
라 한다.
이런 간단한 테스트에 HTML form을 만들기는 귀찮다. 이때는 Postman을 사용하면 된다.
Postman 테스트 주의사항 POST 전송시
Body x-www-form-urlencoded
선택
Headers에서 content-type: application/x-www-form-urlencoded
로 지정된 부분 꼭 확인
html form 방식으로 post요청을 보내게 되면 위에 쿼리 파라미터와 똑같은 방식으로 response body에 담아 데이터를 보내기 때문에 위 자바코드를 재활용해도 된다
위처럼 request-param에 html form으로 post요청을 보내게 되면 아래와 같은 결과가 나온다.
postman으로 request 바디에 텍스트를 써서 보낸다.
@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//메시지 바디의 내용을 바이트 코드로 바로 얻을 수 있음
ServletInputStream inputStream = request.getInputStream();
//String으로 변환
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
response.getWriter().write("ok");;
}
}
위처럼 InputStream으로 얻은 바이트 코드를 String으로 변환해서 Body를 출력하며 아래와 같은 결과가 나온다.
JSON 형식 전송
POST http://localhost:8080/request-body-json
content-type: application/json
message body: {"username": "hello", "age": 20}
결과: messageBody = {"username": "hello", "age": 20}
@Getter @Setter
public class HelloData {
private String username;
private int age;
}
위처럼 데이터를 설정한다.
getter, setter는 lombok을 이용한다.
@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);
//objectMapper로 json 데이터를 꺼내봄
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
System.out.println("helloData name = " + helloData.getUsername());
System.out.println("helloData age = " + helloData.getAge());
response.getWriter().write("ok");
}
}
위 코드처럼 String으로 받은 json을 Jackson 라이브러리의 ObjectMapper를 사용해서 파싱한다.
그렇게 해서 json데이터의 키로 객체와 매핑하여 데이터를 담아 사용한다.
HTTP 응답 메시지 생성
편의 기능 제공
@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet {
@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");
content(response);
}
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); //(생략시 자동 생성)
}
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);
}
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");
}
}
위는 헤더, 헤더의 쿠키, Location 등 편하게 세팅하는 방법의 코드이다.
HTTP 응답 메시지는 주로 다음 내용을 담아서 전달한다.
writer.println("ok");
)HttpServletResponse - 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: text/html;charset=utf-8
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>");
}
}
@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("kim");
data.setAge(20);
//{"username":"kim","age":20}
String result = objectMapper.writeValueAsString(data);
response.getWriter().write(result);
}
}
HTTP 응답으로 JSON을 반환할 때는 content-type을 application/json
로 지정해야 한다.
Jackson 라이브러리가 제공하는 objectMapper.writeValueAsString()
를 사용하면 객체를 JSON 문자로 변경할 수 있다.