(스프링 MVC1) 서블릿

짜스의 하루 ·2024년 2월 29일

Hello 서플릿

스프링이 자동으로 내 패키지를 포함한 모든 하위패키지에 있는 서플릿을 찾아 자동으로 서플릿 등록을 해주기 위해 @ServletComponentScan 어노테이션을 추가한다.

@ServletComponentScan // 서블릿 자동 등록
public class ServletApplication {

서플릿 등록하기

서플릿 등록하기

  • 서플릿을 등록하기 위해 클래스 앞에 @WebServlet 어노테이션 추가한다.
// name: 서블릿 이름, urlPatterns: URL 매핑
// "/hello" 이 호출되면 서블릿 컨테이너는 해당 메서드 실행
@WebServlet(name = "helloServlet", urlPatterns = "/hello")

서비스 메서드 추가
ctrl + O 단축키를 누르면 쉽게 생성할 수 있음.

@Override
protected void service(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {

퀴리 파라미터로 request 요청을 받기
--> 쿼리 파라미터를 읽는 코드를 작성한다.

String username = request.getParameter("username");

http://localhost:8080/hello?username=kim 에 들어가고 쿼리 파라미터로 받은 값을 출력해보면 정상적으로 쿼리 파라미터 값을 받은 것을 확인할 수 있다.

response 응답 메세지

response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().write("hello " + username); // HTTP 메시지 바디에 write

서플릿 컨테이너 동작 방식


HttpServletRequest

HttpServletRequest 개요

HTTP 요청 메시지를 파싱한 결과를 HttpServletRequest 객체에 담아 제공하여, HTTP 요청 메시지를 편리하게 조회할 수 있다.

HTTP 요청 메시지

POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded

username=kim&age=20
  • START LINE
    : HTTP 메소드, URL, 쿼리, 스트링, 스키마, 프로토콜
  • 헤더
    : 헤더 정보(Host, Content-Type..)
  • 바디
    : form 형식의 파라미터, message body 데이터에 직접 조회

HttpServletRequest의 부가기능
임시 저장소 기능 세션 관리 기능

  • 저장: request.setAttribute(name, value)
  • 조회: request.getAttribute(name)

세션 관리 기능

  • request.getSession(creat:true)

HttpServletRequest - 기본 사용법

서블릿 어노테이션을 추가한다

@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }

START LINE 정보

request.getMethod() // 메서드
request.getProtocol() // 프로트콜
request.getScheme() // 스키마
request.getRequestURL() // 요청 url
request.getRequestURI()  // 요청 uri
request.getQueryString() // 쿼리 파라미터
request.isSecure() // 보안(https)

헤더 정보
HTTP 요청 메시지의 모든 헤더의 내용을 출력하기 위한 메서드를 만들어 내용을 확인한다.

request.getHeaderNames().asIterator().forEachRemaining(headerName -> System.out.println(headerName + " : " + headerName)));

모든 정보 말고도 원하는 헤더의 내용을 확인할 수 있다.

request.getServerName() // 이름
request.getServerPort() // 포트

request.getLocales().asIterator() // 언어
                .forEachRemaining(locale -> System.out.println("locale = " + locale));
request.getLocale()

if (request.getCookies() != null) { // 쿠키
            for (Cookie cookie : request.getCookies()) {
                System.out.println(cookie.getName() + ": " + cookie.getValue());
            }
}

request.getContentType() // content 타입
request.getContentLength() // content 길이
request.getCharacterEncoding() // 인코딩

기타 정보
네트워크 커넥션등에 대한 정보

request.getRemoteHost()
request.getRemoteAddr()
request.getRemotePort()

request.getLocalName()
request.getLocalAddr()
request.getLocalPort()

HTTP 요청 데이터 - 개요

주로 3가지 방법을 사용한다

1. GET - 쿼리 파라미터

  • /url?username=hello&age=20
  • 메시지 바디 없이 URL의 쿼리 파라미터에 데이터를 포함해서 전달
  • 예) 검색, 필터, 페이징 등에서 많이 사용하는 방식

2. POST - HTML Form

  • content-type : application/x-www-form-urlencoded
  • 메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20
  • 예) 회원가입, 상품 주문, HTML Form 사용

3. HTTP message body에 데이터를 직접 담아서 요청

  • HTTP API 에서 주로 사용, JSON, XML 등등
  • 데이터 형식은 주로 JSON을 사용
  • POST, PUT, PATCH를 사용

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

전달 데이터

  • username=hello
  • age=20

메시지 바디 없이 URL의 쿼리 파라미터를 사용해서 데이터를 전달해보자

쿼리파라미터는 URL에 다음과 같이 ?를 시작으로 보낼 수 있으며,
추가 파라미터는 &로 구분하면 된다.
http://localhost:8080/request-param?username=hello&age=20

서버에서는 HttpServletRequest가 제공하는 다음 메서들을 통해 쿼리 파라미터를 편리하게 조회할 수 있다.

쿼리 파라미터 조회 메서드

  1. 전체 파라미터 조회
 System.out.println("[전체 파라미터 조회] - start");
        request.getParameterNames().asIterator().forEachRemaining(paramName -> 
                System.out.println(paramName + " : " + request.getParameter(paramName)));
        System.out.println("[전체 파라미터 조회] - end");
  1. 단일 파라미터 조회
System.out.println("[단일 파라미터 조회] - start");
        String username = request.getParameter("username");
        String age = request.getParameter("age");

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

복수 파라미터에서 단일 파라미터 조회
username=hello&username=kim과 같이 파라미터 이름은 하나인데, 값이 중복이면 어떻게 될까?
--> request.getParameter()는 하나의 파라미터 이름에 대해서 단 하나의 값만 있을 때 사용해야 한다.
지금처럼 중복일 때에는 request.getParamValues()를 사용해야 한다.

참고) 중복일 때, request.getParameter()를 사용하면, request.getParameterValue()의 첫번째 값을 반환한다.


HTTP 요청 데이터 - POST HTML Form

이번에는 HTML의 Form을 사용해서 클라이언트에서 서버로 데이터를 전송해보자
주로 회원 가입, 상품 주문 등에서 사용하는 방식이다

특징

  • content type : application/x-www-form-urlencoded
  • 메시지 바디에 쿼리 파라미터 형식으로 데이터를 지원한다. username=hello&age=20

hello-form.html 생성

실행해보자

POST의 HTML Form을 전송하면 웹 브라우저는 다음 형식으로 HTTP 메시지를 만든다. (웹 브라우저 개발자 모드 확인)

application/x-www-form-urlencoded형식은 앞서 GET에서 살펴본 쿼리 파라미터 형식과 같다. 따라서 쿼리 파라미터 조회 메서드를 그대로 사용하면 된다.

클라이언트(웹 브라우저) 입장에서는 두 방식에 차이가 있지만, 서버 입장에서는 둘의 형식이 동일하므로, request.getParameter()로 편리하게 구분 없이 조회할 수 있다.

정리하자면,
request.getParameeter()는 GET URL 쿼리 파라미터 형식도 지원하고, POST HTML Form 형식 둘다 지원한다.

참고
content-type은 HTTP 메시지 바디의 데이터 형식을 지정한다.
GET URL 쿼리 파라미터 형식 으로 클라이언트에서 서버로 데이터를 전달할 때는 HTTP 메시지 바디를 사용하지 않기 때문에 content-type이 없다.

POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기 때문에
바디에 포함된 데이터가 어떤 형식인지 content-type을 꼭 지정해야 한다. 이렇게 폼으로 데이터를 전송하는 형식을 application/x-www-form-urlencoded라 한다

Postman을 활용한 테스트

간단한 테스트를 하기 위해선 Postman을 사용하자

를 입력하면
결과를 확인할 수 있다


HTTP 요청 테이터 - API 메시지 바디 - 단순 텍스트

HTTP message body에서 데이터를 직접 담아서 요청

  • HTTP API에서 주로 사용, JSON, XML, TEXT
  • 데이터 형식은 주로 JSON 사용
  • PUT, POST, PATCH

먼저 가장 단순한 텍스트 메시지를 HTTP 메시지 바디에 담아서 전송하고 읽어보자
HTTP메시지 바디의 데이터를 inputStream을 사용해서 직접 읽을 수 있다.

 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");
        
    }
  • 참고로, inputStream()은 byte 코드를 반환한다.
    byte코드를 읽을 수 있게 문자(String)으로 보려면, 문자표 (Charset)를 지정해주어야 한다. 여기서는 UTF-8 Charset으로 지정해주었다.

Postman을 사용해서 테스트를 해보자


가 출력되는 것을 알 수 있다.


HTTP 요청 데이터 - API 메시지 바디 - JSON

JSON 형식 파싱 추가
JSON 형식으로 파싱할 수 있게 객체를 하나 생성한다.

  • Lombok 이 제공하는 @Getter, @Setter 덕분에 Get, Set 메서드를 자동 생성해준다.
@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {

    //JSON 결과를 파싱해서 객체로 변환하기 위해 JSON 변환 라이브러리를 추가한다
    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.getUsername() = " + helloData.getUsername());
        System.out.println("helloData.getAge() = " + helloData.getAge());


    }
}
  • JSON 결과를 파싱해서 객체로 변환하기 위해 JSON 변환 라이브러리를 추가한다.
private ObjectMapper objectMapper = new ObjectMapper();
  • JSON 변환 라이브러리로 메시지 Body를 파싱할 객체를 읽고, 객체의 getter를 사용하여 값들을 출력한다.
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class)
  • Postman 을 사용해 JSON 형식의 HTTP요청 메시지를 보내고 출력 값을 보면 정상적으로 작동한다.


HttpServletResponse - 기본 사용법

HttpServletResponse 역할

  • HTTP 응답 메시지 생성 : HTTP 응답코드 지정, 헤더 생성, 바디 생성
  • 편의 기능 제공: Content-Type, 쿠키, Redirect

HTTP 응답 메시지 생성

HTTP 응답 메시지에 넣을 값들을 작성한다

//[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");

http://localhost:8080/response-header 에 들어가면
위의 작성한 응답 데이터를 확인할 수 있다.

편의 기능 제공

  1. Content 편의 메서드
 private void content(HttpServletResponse response) {
        // response.setHeader("Content-type", "text/plain;charset=utf-8");
        response.setContentType("text/plain");
        response.setCharacterEncoding("utf-8");
    }
  1. 쿠키 편의 메서드
 private void cookie(HttpServletResponse response) {
        //response.setHeader("Set-Cookie", "myCookie=good; Max-Age=600");
        Cookie cookie = new Cookie("myCookie", "good");
        cookie.setMaxAge(600);//600초
        response.addCookie(cookie);
    }
  1. redirect 편의 메서드
 private void redirect(HttpServletResponse response) throws IOException {
        response.sendRedirect("/basic/hello-form.html");
    }
  • redirect()를 실행시키면, 새로고침을 눌렀을 때,
    로 창이 바뀌는 것을 알 수 있다

HTTP 응답 데이터 - 단순 텍스트, HTML

  • 단순 텍스트 응답: (writer.println("OK");)
  • HTML 응답
  • HTTP API - MessageBody JSON 응답

HttpServletResponse - HTML 응답

@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>");
    }
}

응답 메시지의 헤더 값을 설정해둔다

response.setContentType("text/html");
respinse.setCharacterEncoding("utf-8");

message body로 HTML 응답을 보내준다

PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<body>");
writer.println(" <div>안녕?</div>");
writer.println("</body>");
writer.println("</html>");

http://localhost:8080/response-html 에 들어가면,

이렇게 응답 데이터가 정상적으로 보내진 것을 확인할 수 있다.

HTTP 응답으로 HTML을 반환할 떄, Content-type을 text/html로 지정하면 된다.


HTTP 응답 데이터 - API JSON

@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");
        
        HelloData helloData = new HelloData();
        helloData.setUsername("kim");
        helloData.setAge(20);
        
        //객체를 JSON 형식으로 변환하기 위해, JSON 변환 라이브러리 사용
        //{"username":"kim","age":20}
        String result = objectMapper.writeValueAsString(helloData);
        response.getWriter().write(result);
        
    }
}

헤더 값을 설정해준다

response.setContentType("application/json")

username, age를 넣어서 HelloData 객체를 만든다

HelloData helloData = new HelloData();
helloData.setUsername("kim");
helloData.setAge(20);

객체를 JSON 형식으로 변경하기 위해, JSON 변환 라이브러리인 ObjectMapper를 사용한다.

private ObjectMapper objectMapper = new ObjectMapper();
...
String result = objectMapper.writeValueAsString(helloData);
response.getWriter().write(result);

http://localhost:8080/response-json 에 들어가면

정상적인 응답 데이터가 보내진 것을 확인할 수 있다.

profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글