@ServletComponentScan
@SpringBootApplication
public class ServletApplication {
public static void main(String[] args) {
SpringApplication.run(ServletApplication.class, args);
}
}
스프링 부트는 서블릿을 직접 등록해서 사용할 수 있도록 @ServletComponentScan
를 지원한다.
@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");//header
response.getWriter().write("hello " + username);//body
}
}
HttpServlet
클래스를 상속받는 클래스를 생성한다.@WebServlet
을 사용name
: 서블릿 이름 지정urlPattrerns
: url 경로를 지정service
메서드를 오버라이딩 하여 원하는 동작을 수행한다.application.properties
에 다음 설정을 추가한다.
logging.level.org.apache.coyote.http11=debug
스프링부트는 내장 톰캣 서버를 실행하면서 서블릿 컨테이너를 실행하고 서블릿을 생성한다.
http 요청이 오면 request, response 객체를 생성하고 지정된 url에 해당하는 서블릿의 service 메서드를 실행한다. service 메서드 내에서 response 객체에 http응답 헤더, 바디 등의 정보를 세팅할 수 있고 종료시 was는 response 객체를 이용하여 Http응답 메시지를 생성하고 이를 전송한다.
서블릿은 개발자가 Http 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 Http 요청 메시지를 파싱한다. 그리고 그 결과를 HttpServletRequest
객체에 담아서 제공한다.
POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
username=kim&age=20
HttpServletRequest
객체를 이용하여 위와 같은 요청 메시지에서 다음과 같은 정보들을 얻을 수 있다.
request.setAttribute(name,value)
request.getAttribute(name)
request.getSession(create: true)
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
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
System.out.println("request.getRequestURL() = " + request.getRequestURL());
System.out.println("request.getRequestURI() = " + request.getRequestURI());
System.out.println("request.getQueryString() = " + request.getQueryString());
System.out.println("request.isSecure() = " + request.isSecure()); //https사용 유무
System.out.println("--- REQUEST-LINE - end ---");
System.out.println();
}
}
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("--- Headers - start ---");
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println(headerName + ": " + headerName));
System.out.println("--- Headers - end ---");
System.out.println();
}
}
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
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();
System.out.println("--- Header 편의 조회 end ---");
System.out.println();
}
}
HTTP 요청 메시지를 통해 클라이언트가 서버로 데이터를 전달하는 방법은 다음과 같다.
쿼리파라미터는 URL 다음에 ?로 시작하여 name과 value를 담을 수 있다. 파라미터는 &로 추가할 수 있다.
http://localhost:8080/reques-param?username=sonny&age=30
서버에서는 HttpServletRequest
가 제공하는 메서드를 통해 쿼리 파라미터를 조회할 수 있다.
request.getParameterNames()
@WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> System.out.println(paramName + "= " + request.getParameter(paramName)));
}
}
request.getParameterNames()
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String age = request.getParameter("age");
System.out.println("username = " + username);
System.out.println("age = " + age);
}
application/x-www-form-urlencoded
username=sonny&age=30
쿼리파라미터 형식의 데이터가 담긴다.서버 입장에서는 GET-쿼리파라미터와 POST-HTML Form의 데이터의 형식이 같으므로 request.getParameter()
을 이용하여 둘다 조회할 수 있다.
다시말해 request.getParameter()
는 GET url 쿼리 파라미터와 POST HTML Form 형식 둘다 지원한다.
@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);
}
InputStream
을 이용하여 직접 읽을 수 있다.
InputStream
은 byte 코드를 반환한다. String으로 변환하려면 StreamUtil.copyToString을 사용하고 UTF-8 CharSet을 지정해주면된다.
먼저 Json 데이터를 파싱하여 매핑할 객체를 생성한다.
@Getter @Setter
public class HelloData {
private String username;
private int age;
}
스프링부트로 Spring MVC를 선택하면 기본으로 Jackson 라이브러리(json데이터 파싱)를 제공한다. Jackson 라이브러리의 ObjectMapper
를 이용하여 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);
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");
}
}
objectMapper.readValue()
의 파라미터에 inputStream에서 읽은 메시지(json)과 매핑할 객체를 전달하면 객체에 데이터를 세팅할 수 있다.
HttpServletResponse는 HTTP 응답 메시지를 생성하는 역할을 한다.
@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);//200
//[Header]
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma","no-cache");
response.setHeader("my-header", "hello");
//[Cookie]
Cookie cookie = new Cookie("myCookie", "good");
cookie.setMaxAge(600); //600초
response.addCookie(cookie);
//[Redirect]
response.sendRedirect("basic/hello-form.html");
//[Body]
PrintWriter writer = response.getWriter();
writer.println("ok");
}
}
@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>");
}
http 응답으로 html을 반환할 때는 content-type을 `text/html``로 지정한다.
@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("sonny");
helloData.setAge(30);
//{"username":"kim, "age",30}
String result = objectMapper.writeValueAsString(helloData);
response.getWriter().write(result);
}
application/json
으로 지정한다.objectMapper.writeValueAsString()
은 객체를 JSON으로 변환한다.