728x90
프로젝트 생성
- Packing을 반드시 War로 설정할 것 → 추후에 JSP를 사용하기 위해 필요
- 인텔리제이가 커뮤니티버전일 경우 build.gradle 파일에 providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 를 지워야한다.
- Gradle로 바꿔야한다.
📌 ServletApplication 클래스
package hello.servlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan // 서블릿 자동 등록
@SpringBootApplication
public class ServletApplication {
public static void main(String[] args) {
SpringApplication.run(ServletApplication.class, args);
}
}
- @ServletComponentScan
- 스프링 부트는 서블릿을 직접 등록해서 사용할 수 있도록 애노테이션 형식으로 지원한다.
📌 HelloServlet 클래스
package hello.servlet.basic;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "helloServlet", urlPatterns = "/hello") // /hello 로 오면 실행이 된다.
public class HelloServlet extends HttpServlet { // 서블릿은 HttpServlet을 상속 받아야 한다.
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// http 요청이 오면 WAS 안에 있는 서블릿 컨테이너가 request, response 객체를 만들어서 서블릿에 던져준다.
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/pain"); // Http 메시지의 헤더 정보에 들어간다.
response.setCharacterEncoding("utf-8"); // Http 메시지의 헤더 정보에 들어간다.
response.getWriter().write("hello " + username); // Http 메시지 바디에 메시지가 들어간다.
}
}
// http://localhost:8080/hello?username=김
// 접속후 출력된 콘솔 메시지
HelloServlet.service
request = org.apache.catalina.connector.RequestFacade@416d1ba
response = org.apache.catalina.connector.ResponseFacade@3e03d467
username = 김
- 서블릿 클래스는 HttpServlet 클래스를 상속 받아야한다.
- HttpServlet은 서블릿이 웹 상에서 HTTP 프로토콜을 이용해 서비스를 처리하기 위해 반드시 상속 받아야하는 클래스다.
- 즉, 모든 서블릿 클래스의 상위 클래스는 HttpServlet 클래스이어야 한다.
- @WebServlet 서블릿 애노테이션
- name : 서블릿 이름
- urlPatterns : URL 매핑
- 해당 URL으로 접근시 service() 메서드가 호출된다.
- HttpServlet 클래스를 상속 받은 후에 인텔리제이 기능인 '컨트롤 + o' 를 눌러서 service 를 친다. 그리고 접근제어어자가 protect 인 service() 메서드를 가져온다.
- protected void service(HttpServletRequest request, HttpServletResponse response)
- request.getParameter() 메서드를 통해 HTTP 요청의 쿼리 파라미터값을 얻는다.
- 단일 파라미터만 가능하다.
- 단계
- 1) @WebServlet으로 이름, 연결 url 지정
- 2) HttpServlet 상속
- 3) protected 접근 지시자를 갖는 service 메서드를 오버라이딩한다.
- 비즈니스 로직 작성
HttpServletRequest 클래스
- Http 프로토콜의 request 정보를 서블릿에게 전달하기 위한 목적으로 사용한다.
- Header 정보, Parameter, Cookie, URI, URL 등의 정볼르 읽어들이는 메서드를 가진 클래스
- JSP(View)로 부터 Controller로 데이터를 보냈을 때, HttpServletRequest 객체 안에 데이터들이 들어가게 된다.
🔍 HttpServletRequest 역할
- 서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 HTTP 요청 메시지를 파싱한다.
- 그리고 그 결과를 HttpServletRequest 객체에 담아서 제공한다.
- HttpServletRequest를 사용해서 HTTP request message의 다양한 정보를 조회할 수 있다.
- start-line
- headers
- body
- HttpServletRequest 객체는 임시 저장소 기능도 제공한다.
- 해당 HTTP 요청이 시작부터 끝날 떄 까지 유지되는 임시 저장소다.
- 데이터 저장 : request.setAttribute(String name, Object value)
- 데이터 조회 : request.getAttribute(String name)
- 세션 관리 기능도 지원한다.
- request.getSession(creat : true)
✔ 참고
- HttpServletRequest, HttpServleResponse를 사용할 때 가장 중요한 점은 이 객체들이 HTTP 요청 메시지, HTTP 응답 메시지를 편리하게 사용하도록 도와주는 객체라는 점이다.
- 따라서 이 가능에 대해 깊이있는 이해를 하려면 HTTP 스펙이 제공하는 요청, 응답 메시지 자체를 이해해야 한다.
🔍 HttpServletRequest 클래스의 주요 메서드
메서드 | 설명 |
getParameterNames() | 현재 요청에 포함된 매개변수 이름을 열거 형태로 넘겨준다. |
getParameter(String name) | 문자열 name과 같은 이름을 가진 매개변수 값을 가져온다. 반환타입이 String 타입이다. 클라이언트의 HTML 페이지에서 필요한 정보를 얻는데 사용한다. |
getParameterValues(String name) | 문자열 name과 같은 이름을 가진 매개변수 값을 배열 형태로 가져온다. ( 주로 checkbox, mutilple list 등에 사용 ) |
getCookies() | 모든 쿠키 값을 javax.servlet.http.Cookie의 배열 형태로 가져온다. |
getMethod() | 현재 요청이 Get인지, Post인지 파악해서 가져온다. |
getSession() | 현재 세션 객체를 가져온다. |
getRemoteAddr() | 클라이언트의 IP 주소를 알려준다. |
getProtocol() | 현재 서버의 프로토콜을 문자열 형태로 알려준다. |
setCharacterEncoding() | 현재 JSP로 전달되는 내용을 지정한 캐리터셋을로 변환해 준다. HTML 폼에서 한글을 입력할 때 정상적으로 처리하려면 반드시 필요하다. |
getAttribute(String name) | setAttribute() 메서드를 통해 HttpServletRequest 객체 안에 저장된 데이터를 가져온다. 단, setAttribute() 메서드의 속성을 통한 설정이 없으면 null 값을 리턴한다. 반환타입이 Object 타입이기에, 주로 빈 객체나 다른 클래스를 받아올 때 사용된다. |
setAttribute(String name, Object o) | 클라이언트로부터 받은 데이터를 HttpServletRequest 객체안에 데이터를 저장할 때 쓰인다. 데이터를 꺼내올 때는 getAttribute() 메서드를 사용한다. |
🔍 HTTP request message 정보 조회
📌 RequestHeaderServlet 클래스
package hello.servlet.basic.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
printStartLine(request);
// printHeaders1(request);
printHeaders2(request);
printHeaderUtils(request);
printEtc(request);
response.getWriter().write("ok");
}
// start line 정보
private 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://loclahost:8080/request-header
System.out.println("request.getRequestURL() = " + request.getRequestURL());
// /request-test
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 printHeaders1(HttpServletRequest request) {
System.out.println("--- Headers - start ---");
Enumeration<String> headerNames = request.getHeaderNames();// Http 요청 메시지에 있는 모든 헤더 정보를 다 꺼낸다.
while(headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println(headerName + " : " + request.getHeader(headerName));
}
System.out.println("--- Headers - end ---");
System.out.println();
}
// Header 모든 정보 (요즘 방식)
private void printHeaders2(HttpServletRequest request) {
System.out.println("=== Headers - start ===");
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println(headerName + " : " + request.getHeader(headerName)));
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()); // Accept-Language 중 우선순위가 가장 높은 언어를 반환
System.out.println();
System.out.println("[cookie 편의 조회]");
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
System.out.println("cookie.getValue() = " + 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 ---"); // 기타 정본느 HTTP 메시지 정보가 아니다.
// 요청에 대한 정보 (메시지 정보가 아닌 네트워크 정보)
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();
}
}
✔ start-line 정보
// start line 정보
private 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://loclahost:8080/request-header
System.out.println("request.getRequestURL() = " + request.getRequestURL());
// /request-test
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 printHeaders1(HttpServletRequest request) {
System.out.println("--- Headers - start ---");
Enumeration<String> headerNames = request.getHeaderNames();// Http 요청 메시지에 있는 모든 헤더 정보를 다 꺼낸다.
while(headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println(headerName + " : " + request.getHeader(headerName));
}
System.out.println("--- Headers - end ---");
System.out.println();
}
// Header 모든 정보 (요즘 방식)
private void printHeaders2(HttpServletRequest request) {
System.out.println("=== Headers - start ===");
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println(headerName + " : " + request.getHeader(headerName)));
System.out.println("=== Headers - end ===");
System.out.println();
}
✔ Header 편리한 조회
// Hearder 편리한 조회
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()); // Accept-Language 중 우선순위가 가장 높은 언어를 반환
System.out.println();
System.out.println("[cookie 편의 조회]");
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
System.out.println("cookie.getValue() = " + 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 ---"); // 기타 정본느 HTTP 메시지 정보가 아니다.
// 요청에 대한 정보 (메시지 정보가 아닌 네트워크 정보)
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();
}
- 기타 정보는 HTTP 메시지 정보가 아니다.
HttpServletResponse 클래스
- 서블릿은 HttpServletResponse 객체에 Content Type, 응답코드, 응답 메시지 등을 담아서 전송한다.
🔍 HttpServletRequest 클래스의 주요 메서드
메서드 | 설명 |
setContentType(type) | 문자열 형태의 type에 지정된 MIME Type으로 Content Type을 지정한다. |
setHeader(name, value) | 문자열 name의 이름으로 문자열 value 값을 헤더로 설정한다. |
setDateHeader(name, date) | 문자열 name의 이름으로 date에 설정된 밀리세컨드 시간 값을 헤더에 설정한다. |
sendRedirect(url) | 클라이언트 요청을 다른 페이지로 보낸다. |
🔍 Http 요청 메시지 로그로 확인하기
logging.level.org.apache.coyote.http11=debug
- application.properties 파일에 logging.level.org.apache.coyote.http11=debug 를 적고 서버를 다시 시작한다.
- 그 후 웹 브라우저를 통해 서버에 요청할 경우 서버가 웹 브라우저한테 받은 HTTP 요청 받은 메시지를 출력한다.
- 운영서버에 이렇게 모든 요청 정보를 다 남기면 성능저하가 발생할 수 있으므로 개발 단계에서만 적용한다.
서블릿 동작 원리
🔍 동작 원리
💡 1단계
- 스프링부트가 실행이 되면 내장된 톰켓 서버를 실행시킨다.
- 내장 톰켓 서버는 내부에 서블릿 컨테이너를 가지고 있다.
- 톰켓 서버가내부의 서블릿 컨테이너를 통해 요청 URL에 해당되는 서블릿 객체를 호출한다.
💡 2단계
- HTTP 요청 메시지를 기반으로 생성된 HttpServletRequest, HttpServletResponse 객체를 만든다.
- 생성된 두 객체는 서블릿 객체의 service() 메서드의 파라미터 값으로 넘겨주고 메서드를 실행한다.
- service() 메서드의 로직에 의해 HTTP 응답 메시지(HTTP Response Message)가 작성된다. 그렇게 작성된 HTTP 응답 메시지는 웹 브라우저로 전달된다.
✔ 웹 브라우저가 서버한테 보낸 HTTP 요청 메시지 / 서버가 웹 브라우저한테 보내는 HTTP 응답 메시지
- 참고로 HTTP 응답에서 Content-Length는 웹 애플리케이션 서버가 자동으로 생성해준다.
welcome 페이지 만들기
🔍 HTML 문서
📌 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li><a href="basic.html">서블릿 basic</a></li>
</ul>
</body>
</html>
📌 basic.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li>hello 서블릿
<ul>
<li><a href="/hello?username=servlet">hello 서블릿 호출</a></li>
</ul>
</li>
<li>HttpServletRequest
<ul>
<li><a href="/request-header">기본 사용법, Header 조회</a></li>
<li>HTTP 요청 메시지 바디 조회
<ul>
<li><a href="/request-param?username=hello&age=20">GET -
쿼리 파라미터</a></li>
<li><a href="/basic/hello-form.html">POST - HTML Form</a></
li>
<li>HTTP API - MessageBody -> Postman 테스트</li>
</ul>
</li>
</ul>
</li>
<li>HttpServletResponse
<ul>
<li><a href="/response-header">기본 사용법, Header 조회</a></li>
<li>HTTP 응답 메시지 바디 조회
<ul>
<li><a href="/response-html">HTML 응답</a></li>
<li><a href="/response-json">HTTP API JSON 응답</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
</html>
👀 참고 자료
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1
https://kimmy100b.github.io/jsp%20servlet/2020/02/13/JSP-Servlet-05/
728x90
'[ Spring ] > SpringMVC 1편' 카테고리의 다른 글
[Spring] HttpServletResponse / 응답 데이터 전달하는 방법 (0) | 2022.02.15 |
---|---|
[Spring] HttpServletRequest / HTTP 요청 데이터를 얻는 3가지 방법 (0) | 2022.02.15 |
[Spring] 자바 웹 기술 역사 (0) | 2022.02.12 |
[Spring] 서버 사이드 렌더링(SSR), 클라이언트 사이드 렌더링(CSR) (0) | 2022.02.11 |
[Spring] HTML, HTTP API (0) | 2022.02.11 |