온라인 강의/Spring Framework
[스프링 MVC 1편] 서블릿
코드몬스터
2024. 5. 8. 20:55
728x90
Hello 서블릿
- 만들어보자.
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
System.out.println("req = " + req);
System.out.println("res = " + res);
String username = req.getParameter("username");
System.out.println("username = " + username);
res.setContentType("text/pain");
res.setCharacterEncoding("utf-8");
res.getWriter().write("hello" + username);
}
}
HttpServletRequest
개요
HTTP 요청 메세지를 파싱한다.
그 결과를 HttpServletRequest 객체에 담아서 제공.
- Start Line
- HTTP 메소드
- URL
- 쿼리 스트링
- 스키마, 프로토콜
- 헤더
- 헤더 조회
- 바디
- form 파라미터 형식 조회
- message body 데이터 직접 조회
사용 방법
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
printHeaders(req);
printEtc(req);
}
private void printHeaders(HttpServletRequest request) {
/* 방법 1.
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println("headerName = " + headerName);
}
*/
// 방법 2.
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println("headerNames = " + headerName));
}
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();
}
}
HTTP Request(요청)
개요
- GET - 쿼리 파라미터
- /url?username=hello&age=20
- 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
- 예) 검색, 필터, 페이징등에서 많이 사용하는 방식
- POST - HTML Form
- content-type: application/x-www-form-urlencoded
- 메시지 바디에 쿼리 파리미터 형식으로 전달 username=hello&age=20
- 예) 회원 가입, 상품 주문, HTML Form 사용
- HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용, JSON, XML, TEXT
- 데이터 형식은 주로 JSON 사용
- POST, PUT, PATCH
GET - 쿼리 파라미터
전달 데이터
- username=hello
- age=20
메세지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달하자.
쿼리 파라미터는 URL에 "?" 를 시작으로 보낼 수 있고 "&"로 추가파리머트를 구분하면 된다.
- http://localhost:8080/request-param?usernmae=kim&age=20
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-param")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
printGetParam(req);
}
private void printGetParam(HttpServletRequest request) {
System.out.println("전체 파라미터 조회 start");
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> System.out.println(paramName + " = " + request.getParameter(paramName)));
System.out.println("전체 파라미터 조회 end");
}
}
POST - HTML Form
주로 회원 가입, 상품 주문 등에서 사용하는 방식.
특징
- content-type: application/x-www-form-urlencoded
- 메세지 바디에 쿼리 파라미터 형식으로 데이터를 전달한다.
application/x-www-form-urlencoded 형식은 GET에서 살펴본 쿼리 파라미터 형식과 같다.
클라이언트 입장에서는 두 방식에 차이가 있지만, 서버 입장에서는 둘의 형식이 동일하므로, request.getParameter()로 편리하게 사용 가능.
참고
- GET URL 쿼리 파라미터 형식으로 클라이언트에서 서버로 데이터를 전달할 때는 HTTP 메시지 바디를
사용하지 않기 때문에 content-type이 없다. - POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기
때문에 바디에 포함된 데이터가 어떤 형식인지 content-type을 꼭 지정해야 한다.- content-type:application/x-www-form-urlencoded
API 메세지 바디 - 단순 텍스트
- POST http://localhost:8080/request-body-string
- content-type: text/plain
- message body: hello
- 결과: messageBody = hello
참고
- inputStream은 byte 코드를 반환한다.
- byte 코드를 우리가 읽을 수 있는 문자(String)로 보려면 문자표(Charset)를 지정해주어야 한다.
- 여기서는 UTF_8 Charset을 지정해주었다.
@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");
}
API 메세지 바디 - JSON
- JSON 형식 전송
- POST http://localhost:8080/request-body-json
- content-type: application/json
- message body: {"username": "hello", "age": 20}
- 결과: messageBody = {"username": "hello", "age": 20}
@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");
}
}
HttpServletResponse
기본 사용법
- 만들어보자.
@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
//[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 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");
}
}
HTTP 응답 데이터 - 단순 텍스트, HTML
- HTTP 응답으로 HTML을 반환할 때는 content-type을 text/html 로 지정
HTTP 응답 데이터 - API JSON
- HTTP API - MessageBody JSON 응답
- application/json 은 스펙상 utf-8 형식을 사용하도록 정의되어 있다.
- 스펙에서 charset=utf-8과 같은 추가 파라미터를 지원하지 않는다.
@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);
}