[Spring] MVC 1편 - 02. 서블릿

54049 단어 서블릿SpringMVCMVC

이 글은 스프링 [스프링 MVC 1편]을 듣고 정리한 내용입니다

📌 프로젝트 생성

  • 환경 세팅
  • Packing: War (주의)
    • JSP 실행하기 위해서 필요함
  • 메인 클래스 실행하고, localhost:8080에 Whitelabel Error Page 나오면 정상 동작
  • Gradle대신에 InteliJ 에서 자바 직접 실행하는 설정
  • 롬복 적용(plugint 롬복 설치, Annotation Processor)
  • Postman 설치

📌 Hello 서블릿

  • 서블릿 등록하기
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") // name: 서블릿 이름, urlPatterns: URL 매핑
public class HelloServlet extends HttpServlet {

    @Override // HTTP 요청을 통해 URL이 호출되면 서블릿 컨테이너는 다음 메서드(service)를 실행한다.
    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"); // http 헤더 정보 - content type
        response.setCharacterEncoding("utf-8");// http 헤더 정보 - content type
        response.getWriter().write("hello " + username); //http 메시지 바디에 데이터가 들어감
    }
}
  • HTTP 요청 로그로 확인하기
logging.level.org.apache.coyote.http11=debug  
  • 다음설정을 추가하면 서버가 받은 HTTP 요청 메세지를 확인 할 수 있다.

서블릿 컨테이너 동작 방식

  • 내장 톰캣 서버 생성


  • welcome 페이지 추가(index.html)

  • 학습할 내용 안내 페이지 추가(basic.html)


📌 HttpServletRequeset - 개요

HttpServletRequest 역할

  • 서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 HTTP 요청 메시지를 파싱한다.
  • 그리고 그 결과를 HttpServletRequest 객체에 담아서 제공한다.

HTTP 요청 메시지

 POST /save HTTP/1.1
  Host: localhost:8080
  Content-Type: application/x-www-form-urlencoded
  username=kim&age=20
  • 시작 라인
    • HTTP 메소드
    • URL
    • 쿼리 스트링
    • 스키마, 프로토콜
  • 헤더
    • 헤더 조회
  • 바디
    • form 파라미터 형식 조회
    • message body 데이터 직접 조회
  • HttpServletRequeset 객체는 추가로 다음 여러가지 부가기능도 제공한다.

    임시 저장소 기능

  • 해당 HTTP 요청이 시작부터 끝날 때까지 유지되는 임시 저장소 기능
    • 저장: request.setAttribute(name,value)
    • 조회: request.getAttribute(name)

중요

  • HttpServletRequest, HttpServletResponse 객체들은 HTTP 요청,응답 메세지드를 편리하게 사용하도록 도와주는 개체이다
  • HTTP 스펙이 제공하는 요청, 응답 메시지를 잘 이해해야한다.

📌 HttpServletRequest - 기본 사용법

  • HttpServletRequest가 제공하는 기본 기능들을 조회 해본다.
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인 service를 만들어야 한다.
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        printStartLine(request);
        printHeaders(request);
        printHeaderUtils(request);
        printEtc(request);


    }

    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://localhost: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 printHeaders(HttpServletRequest request) {
        System.out.println("--- Headers - start ---");

   /*   Enumeration<String> headerNames = request.getHeaderNames();
      while (headerNames.hasMoreElements()) {
          String headerName = headerNames.nextElement();
          System.out.println(headerName + ": " + request.getHeader(headerName));
      }
*/
        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());

        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();
    }

    // 기타 정보
    // 기타정보는 HTTP 메시지의 정보는 아니다
    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();
    }


}
  • 이렇게 HttpServletRequest를 이용하여 HTTP 메시지의 시작라인, header 정보를 조회해보았다.
  • 이제 HTTP 요청 데이터 조회하는 방법을 보자

📌 HTTP 요청 데이터 - 개요

  • HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법은 이 3가지가 전부이다!
  1. GET - 쿼리 파라미터
    ex) /url?username=hello&age=24
    • 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
      사용) 검색, 필터, 페이징 등등
  2. POST- HTML Frorm
    ex) content-type: application/x-www-form-urlencoded
    • 메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=24
      사용) 회원 가입, 상품 주문, HTML Form
  3. HTTP message body에 데이터를 직접 담아서 요청
    • HTTP API에서 주로 사용 -> JSON, XML, TEXT
    • 데이터 형식은 주로 JSON 사용
      • POST, PUT, PATCH
  • POST - HTML Form 예시

📌 HTTP 요청 데이터 - 1.GET 쿼리 파라미터

  • 쿼리 파라미터 조회 메서드
String username = request.getParameter("username"); //단일 파라미터 조회 
Enumeration<String> parameterNames = request.getParameterNames(); //파라미터 이름들 모두 조회
Map<String, String[]> parameterMap = request.getParameterMap(); //파라미터를 Map 으로 조회
String[] usernames = request.getParameterValues("username"); //복수 파라미터 조회
  • 전체, 단일, 복수 파라미터 전송
package hello.servlet.basic.request;

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;
import java.util.Enumeration;

/**
 * 1. 파라미터 전송 기능
 * http://localhost:8080/request-param?username=hello&age=20
 *
 * 2. 동일한 파라미터 전송 가능하다
 * http://localhost:8080/request-param?username=hello&age=20&username=hello2
 */
@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("username = " + username);
        System.out.println("age = " + age);
        System.out.println();

        //이름이 같은 복수 파라미터 조회
        System.out.println("[이름이 같은 복수 파라미터 조회]");
        String[] usernames = request.getParameterValues("username");
        for (String name : usernames) {
            System.out.println("name = " + name);
        }
        System.out.println();


        response.getWriter().write("ok");


    }
}
  • 복수 파라미터에서 단일 파라미터 조회
    • 하나의 파라미터에 대해 여러 값이 있으면 request.getParamterValues() 사용해야 한다.
    • 중복일 때 request.getParameter() 사용하면 첫번째 값을 반환한다.

📌 HTTP 요청 데이터 - 2. POST HTML Form

  • 주로 회원가입, 상품 주문 등에서 사용
  • contet-type: application/x-www-form-urlencoded
  • 메시지 바디에 쿼리파라미터 형식으로 데이터 전달한다.
    ex) username=hello&age=20
  • 서버입장에서는 앞의 GET 쿼리 파라미터 방식과 POST HTML Form 방식 둘의 형식이 동일하다.
  • requset.getParameter()는 GET URL 쿼리 파라미터 형식도 지원하고, POST HTML Form형식도 지원한다.

*참고

  • content-type: HTTP 메시지 바디의 형식을 지정한다
  • GET URL 쿼리 파라미터 방식에서는 메시지 바디를 사용 안하므로, content-type이 없다
  • POST HTML Form 방식에서는 메시지 바디에 데이터를 포함해서 보내므로 데이터가 어떤 형식인지 content-type를 지정해야 한다.
    (즉 포스트맨에서 body의 x-www-form-urlencoded 선택해야함)
    - 폼으로 데이터를 전송하는 형식을 application/x-www-form-urlencoded라 한다.

📌 HTTP 요청 데이터 - 3. API 메시지 바디

단순텍스트 방식

쓰다가말음 이어쓰자 ..

좋은 웹페이지 즐겨찾기