📌 목차
서블릿 사용하기
HttpServletRequest 기본 사용법
HttpServletRequest 개요
HTTP 요청 데이터 - GET 쿼리 파라미터
HTTP 요청 데이터 - POST - HTML Form
HTTP 요청 데이터 - API 메시지 바디 - 단순 텍스트
HTTP 요청 데이터 - API 메시지 바디 - JSON
HttpServletResponse - 기본 사용법
HTTP 응답 데이터 - 단순 텍스트, HTML
HTTP 응답 데이터 - API JSON
사용 프로그램 & 정보
JDK : 11버전
postman
Spring : 2.7.13 버전 , War package , gradle
lombok
// build.gradle
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '2.7.13'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}
group = 'hello'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '11'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
📌 서블릿 사용하기
서블릿은 자바에서 동적 웹페이지를 만들 수 있는 기술이다.
서블릿은 톰캣 같은 웹 애플리케이션 서버를 직접 설치하고, 그 위에 서블릿 코드를 클래스 파일로 빌드해서 올린 다음, 톰캣 서버를 실행하면 된다. 하지만 이 과정은 매우 번거롭다.
스프링 부트는 톰캣 서버를 내장하고 있으므로, 톰캣 서버 설치 없이 편리하게 서블릿 코드를 실행할 수 있다.
// hello.servlet.ServletApplication
@ServletComponentScan // 서블릿 자동 등록
@SpringBootApplication
public class ServletApplication {
public static void main(String[] args) {
SpringApplication.run(ServletApplication.class, args);
}
}
기존의 스프링 실행 코드에서 서블릿 자동 등록 어노테이션을 추가해준다.
//hello.servlet.basic.HelloServlet
@WebServlet(name = "helloServlet" , urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("HelloServlet.service");
System.out.println("request = " + request);
System.out.println("response = " + response);
String username = request.getParameter("username");
System.out.println("username = " + username);
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().write("hello " + username);
}
}
@WebServlet 애노테이션을 통해 서블릿 이름과 url 경로를 지정해줄 수 있다.
서블릿을 사용하기 위해서는 항상 HttpServlet 클래스를 상속 해야한다.
이후 service 클래스를 오버라이딩을 하고 구현을 해준다
HttpServletRequest request, HttpServletResponse response
이때 두개의 파라미터가 존재하는데 이 파라미터를 통해 여러가지 메서드를 사용할 수 있다.
위와같이 localhost 에 쿼리파라미터형식으로 http 요청메시지를 보내면 response.getWriter().write() 를 통해 응답메시지를 받을 수 있다.
resource/application.properties 경로에 logging.level.org.apache.coyote.http11=debug 내용을 추가하면 http 요청 메시지 로그를 콘솔창에서 확인할 수 있다.
📌 HttpServletRequest 기본 사용법
위와같은 http 요청 메시지를 분석하고 파싱해서 직접 응답메시지를 만들기에는 매우 어렵다. 따라서 HttpServletRequest 객체를 통해 관리가 가능하다.
HttpServletRequest 가 제공하는 기능과 메서드를 사용해보자.
//hello.servlet.basic.request.RequestHeaderServlet
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
printStartLine(request);
printHeaders(request);
printHeaderUtils(request);
printEtc(request);
}
private static void printStartLine(HttpServletRequest request) {
System.out.println("--- REQUEST-LINE - start ---");
System.out.println("request.getMethod() = " + request.getMethod()); //GET
System.out.println("request.getProtocol() = " + request.getProtocol()); //HTTP/1.1
System.out.println("request.getScheme() = " + request.getScheme()); //http
// http://localhost:8080/request-header
System.out.println("request.getRequestURL() = " + request.getRequestURL());
// /request-header
System.out.println("request.getRequestURI() = " + request.getRequestURI());
//username=hi
System.out.println("request.getQueryString() = " + request.getQueryString());
System.out.println("request.isSecure() = " + request.isSecure()); //https 사용 유무
System.out.println("--- REQUEST-LINE - end ---");
System.out.println();
}
//Header 모든 정보
private void printHeaders(HttpServletRequest request) {
System.out.println("--- Headers - start ---");
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println(headerName + ": " + headerName));
request.getHeader("host"); // 하나의 정보만 출력하기
System.out.println("--- Headers - end ---");
System.out.println();
}
//Header 편리한 조회
private void printHeaderUtils(HttpServletRequest request) {
System.out.println("--- Header 편의 조회 start ---");
System.out.println("[Host 편의 조회]");
System.out.println("request.getServerName() = " + request.getServerName()); //Host 헤더
System.out.println("request.getServerPort() = " + request.getServerPort()); //Host 헤더
System.out.println();
System.out.println("[Accept-Language 편의 조회]");
request.getLocales().asIterator()
.forEachRemaining(locale -> System.out.println("locale = " + locale));
System.out.println("request.getLocale() = " + request.getLocale());
System.out.println();
System.out.println("[cookie 편의 조회]");
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
System.out.println(cookie.getName() + ": " + cookie.getValue());
}
}
System.out.println();
System.out.println("[Content 편의 조회]");
System.out.println("request.getContentType() = " + request.getContentType());
System.out.println("request.getContentLength() = " + request.getContentLength());
System.out.println("request.getCharacterEncoding() = " + request.getCharacterEncoding());
System.out.println("--- Header 편의 조회 end ---");
System.out.println();
}
private void printEtc(HttpServletRequest request) {
System.out.println("--- 기타 조회 start ---");
System.out.println("[Remote 정보]");
System.out.println("request.getRemoteHost() = " + request.getRemoteHost()); //
System.out.println("request.getRemoteAddr() = " + request.getRemoteAddr()); //
System.out.println("request.getRemotePort() = " + request.getRemotePort()); //
System.out.println();
System.out.println("[Local 정보]");
System.out.println("request.getLocalName() = " + request.getLocalName()); //
System.out.println("request.getLocalAddr() = " + request.getLocalAddr()); //
System.out.println("request.getLocalPort() = " + request.getLocalPort()); //
System.out.println("--- 기타 조회 end ---");
System.out.println();
}
}
--- REQUEST-LINE - start ---
request.getMethod() = GET
request.getProtocol() = HTTP/1.1
request.getScheme() = http
request.getRequestURL() = http://localhost:8080/request-header
request.getRequestURI() = /request-header
request.getQueryString() = username=hello
request.isSecure() = false
--- REQUEST-LINE - end ---
--- Headers - start ---
host: host
connection: connection
cache-control: cache-control
sec-ch-ua: sec-ch-ua
sec-ch-ua-mobile: sec-ch-ua-mobile
sec-ch-ua-platform: sec-ch-ua-platform
upgrade-insecure-requests: upgrade-insecure-requests
user-agent: user-agent
accept: accept
sec-fetch-site: sec-fetch-site
sec-fetch-mode: sec-fetch-mode
sec-fetch-user: sec-fetch-user
sec-fetch-dest: sec-fetch-dest
accept-encoding: accept-encoding
accept-language: accept-language
cookie: cookie
--- Headers - end ---
--- Header 편의 조회 start ---
[Host 편의 조회]
request.getServerName() = localhost
request.getServerPort() = 8080
[Accept-Language 편의 조회]
locale = ko
locale = en
locale = en_US
request.getLocale() = ko
[cookie 편의 조회]
Idea-96a4e784: a6ebb691-6e80-4c17-b4b9-b0441d2e4999
Idea-e27941a4: a6ebb691-6e80-4c17-b4b9-b0441d2e4999
[Content 편의 조회]
request.getContentType() = null
request.getContentLength() = -1
request.getCharacterEncoding() = UTF-8
--- Header 편의 조회 end ---
--- 기타 조회 start ---
[Remote 정보]
request.getRemoteHost() = 0:0:0:0:0:0:0:1
request.getRemoteAddr() = 0:0:0:0:0:0:0:1
request.getRemotePort() = 49398
[Local 정보]
request.getLocalName() = 0:0:0:0:0:0:0:1
request.getLocalAddr() = 0:0:0:0:0:0:0:1
request.getLocalPort() = 8080
--- 기타 조회 end ---
위와같은 아주 자세한 정보를 확인할 수 있다.
요청의 형식이 GET 방식이고 프로토콜, 링크 , 포트 , 언어 , 쿠기 , 인코딩 등과 같은 정보를 HttpServletRequest 객체를 통해 알 수 있다.
📌 HttpServletRequest 개요
HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전송하는 방법은 3가지가 있다.
GET : 쿼리 파라미터/url?username=hello&age=20 URL 의 쿼리 파라미터를 통해 전달POST : HTML formcontent-type: application/x-www-form-urlencodedHTTP : message bodyHTTP API 에서 주로 사용 , JSON , XML , TEXTPOST , PUT , PATCH 요청만 사용가능📌HTTP 요청 데이터 - GET 쿼리 파라미터
username = hello , age = 20 이라는 데이터를 클라이언트에서 서버로 전송해보자.서버에서는 HttpServletRequest 가 제공하는 메서드를 통해 쿼리파라미터를 편리하게 조회할 수 있다.
//hello.servlet.basic.request.RequestParamServlet
/**
* 1. 파라미터 전송 기능
* http://localhost:8080/request-param?username=hello&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");
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("age = " + age);
System.out.println("username = " + username);
System.out.println("[이름이 같은 복수 파라미터 조회] ");
String[] usernames = request.getParameterValues("username");
for (String name : usernames) {
System.out.println("name = " + name);
}
response.getWriter().write("ok");
}
}
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> System.out.println(paramName + "=" + request.getParameter(paramName)));
// 전체 조회
String username = request.getParameter("username");
String age = request.getParameter("age");
// 단일 조회
이터레이터를 통해 전체 조회가 가능하고 getParameter 메서드를 통해 단일 조회가 가능하다
만약 username=hello&username=kim 처럼 중복 파라미터가 존재한다면 가장 왼쪽의 파라미터 하나만 조회가 되고 중복파라미터가 필요하다면 getParameterValues 를 통해 조회가 가능하다.
📌 HTTP 요청 데이터 - POST HTML Form
이번에는 회원가입에 주로 사용되는 HTMP Form 형식으로 데이터를 전송해보자.
<!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>
content-type 는 application/x-www-form-urlencoded 이다.
이 형식은 앞서 GET 에서 살펴본 쿼리 파라미터 형식과 똑같다.
따라서 쿼리 파라미터 조회 메서드를 그대로 사용하면 된다.
📌 HTTP 요청 데이터 - API 메시지 바디 - 단순 텍스트
HTTP 메시지 바디의 데이터를 InputStream 을 사용해서 직접 읽을 수 있다.
// hello.servlet.basic.request.RequestBodyStringServlet
@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 = " + messageBody);
response.getWriter().write("ok");
}
}
getInputStream() 메서드는 바이트 코드를 반환하기 때문에 문자로 보기 위해서는 utf-8 형식으로 변환해주어야 한다.
📌 HTTP 요청 데이터 - API 메시지 바디 - JSON
이번에는 http api 에서 주로 사용하는 json 형식으로 데이터를 전달해보자.
// hello.servlet.basic.HelloData
@Getter @Setter
public class HelloData {
private String username;
private int age;
}
json 형식으로 데이터를 파싱할 수 있게 클래스를 만들어 준다. 이때 lombok 을 사용하면 getter,setter 를 애노테이션으로 대체할수있다.
//hello.servlet.basic.request.RequestBodyJsonServlet;
@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.username = " + helloData.getUsername());
System.out.println("helloData.age = " + helloData.getAge());
response.getWriter().write("ok");
}
}
json 결과를 파싱해서 사용할 수 있는 자바 객체로 변환하려면 Jackson,Gson 같은 변환 라이브러리를 사용해야하는데 Spring boot 에서는 Jackson 라이브러리에서 ObjecyMapper 을 제공한다.
postman 으로 http 요청 메시지를 보내면 json 형식의 데이터를 조회하는것을 확인할 수 있다.
📌 HttpServletResponse - 기본 사용법
이번에는 http 응답 메시지를 작성해보자.
// hello.servlet.basic.reponse.ResponseHeaderServlet;
@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);
redirect(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); //(생략시 자동 생성)
}
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");
}
}
먼저 response.setStatus(HttpServletResponse.SC_OK) 를 통해 상태 코드를 지정할 수 있다. OK 는 200 을 의미하는데 상수로 적어도 무관하다.
response.setHeader("Content-Type", "text/plain;charset=utf-8) 와 같이 setHeader 메서드를 톨해 Content-Type 를 지정할 수 있다.
쿠키를 통해 생명주기와 인코딩 설정을 할 수 있으며 리다이렉트 기능을 제공한다.
📌 HTTP 응답 데이터 - 단순 텍스트, HTML
HTTP 에서 응답 데이터를 HTML 로 해보자. 단순 텍스트는 writer.println("ok") 와 같은 형식으로 응답할 수 있다.
// hello.servlet.basic.reponse.ResponseHtmlServlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@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>");
}
}
위와같이 html 코드를 응답메시지로 사용할 수 있다. 실제 화면에서는 html 코드가 보이지 않는다.
📌 HTTP 응답 데이터 - API JSON
이번에는 json 형식의 데이터를 응답메시지로 보내보자. 이때 content-type 는 application/json 로 지정해야한다. Jackson 라이브러리가 제공하는 objectMapper.writeValueAsString() 를 사용하면 객체를 json 문자로 변경할 수 있다.
//hello.servlet.basic.reponse.ResponseJsonServlet;
@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.setContentType("application/json");
response.setCharacterEncoding("utf-8");
HelloData helloData = new HelloData();
helloData.setUsername("kim");
helloData.setAge(20);
// {"username" : "kim" , "age":20}
String result = objectMapper.writeValueAsString(helloData);
response.getWriter().write(result);
}
}
위와같은 json 형식의 데이터를 응답함을 확인할 수 있다.
지금까지 Servlet 을 통해 http 요청메시지와 응답메시지에 대해 알아보았다.