[강의 정리] SpringBoot를 이용한 서블릿에 대하여..

이성원·2024년 1월 19일
0

스프링 MVC

목록 보기
1/2
post-thumbnail

😶 서블릿을 사용하기 위해서 스프링 부트의 환경 구성을 해주기 위해 @ServletComponentScan이 필요하다

예제 코드


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

}
  • @SpringBootApplication을 지정하여 서블릿을 직접 등록하여 사용 할 수 있다.

예제 코드


package hello.servlet.basic;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@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("request = " + request);

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

        System.out.println("username = " + username);

        response.setContentType("text/plain");
        response.setCharacterEncoding("utf-8");
        response.getWriter().write("hello " + username);
    }
}
  • @WebServlet(name = "helloServlet", urlPatterns = "/hello") 을 통하여 name에는 서블릿 이름 urlPatterns에는 url 매핑을 지정할 수 있다.
  • HTTP 요청이 와 지정한 url과 매핑이 되면 protected void service(HttpServletRequest request, HttpServletResponse response) 의 메서드를 실행 할 수 있다.

실행 결과

Console

  • url을 매핑하면 response로 hello world가 출력되고, 콘솔에는 request와 response가 출력된다.

동작 방식

  • Spring Boot는 내장 톰켓 서버를 생성하고 서블릿 컨테이너 내에 매핑 서블릿을 생성한다.
  • Http 요청이 들어오면 request 객체와 response 객체를 생성하여 helloServlet에게 넘겨 준다
  • helloServlet이 종료되면 reponse를 웹 브라우저에게 반환한다

HttpServletRequest

  • HttpServletRequest 란 Http 요청 메세지를 개발자가 직접 파싱해도 되지만, 개발자가 편리하게 사용할 수 있도록 개발자 대신에 Http 요청 메세지를 파싱한다. 그 결과를 HttpServletRequest객체에 담아서 제공한다.
  • HttpServletRequest는 StrartLine, 헤더, 바디 등 여러가지를 편리하게 관리, 조회 할 수 있다.

HttpServletRequest - 기본 사용법

관련 코드


package hello.servlet.basic.request;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

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

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        printStartLine(req);
        printHeaders(req);
        printHeaderUtils(req);
        printEtc(req);
    }
 


}

startLine


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-header
        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();
    }
  • Http 메세지의 시작 라인을 알 수 있다. (프로토콜, 메서드, 스키마 ...)
--- REQUEST-LINE - start ---
request.getMethod() = GET
request.getProtocol() = HTTP/1.1
request.getScheme() = http
request.getRequestURL() = http://localhost:8080/request-header
request.getRequestURI() = /request-header
request.getQueryString() = username=hello
request.isSecure() = false
--- REQUEST-LINE - end ---

요청 헤더 정보


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 = " + headerName);
//        }
        request.getHeaderNames().asIterator()
                        .forEachRemaining(headerName -> System.out.println(headerName + ": " + headerName));



        System.out.println("--- Headers - end ---");
        System.out.println();
    }
--- Headers - start ---
host: localhost:8080
connection: keep-alive
cache-control: max-age=0
sec-ch-ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_0) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/
webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
sec-fetch-site: none
sec-fetch-mode: navigate
sec-fetch-user: ?1
sec-fetch-dest: document
accept-encoding: gzip, deflate, br
accept-language: ko,en-US;q=0.9,en;q=0.8,ko-KR;q=0.7
--- Headers - end ---

HTTP 요청 데이터 - 개요

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

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

  • 주로 API, JSON, XML 등등
  • 데이터 형식은 주로 JSON을 사용한다.

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

  • 다음과 같은 쿼리로 HTTP 요청 http://localhost:8080/request-param?username=hello&age=20
  • HttpServletRequest가 제공하는 메서드로 쿼리 파라미터 편리하게 조회

조회 메서드

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 jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

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

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

        for (String name : usernames) {
            System.out.println("username = " + name);
        }


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

    }
}

결과

[전체 파라미터 조회] - start
username=hello
age=20
[전체 파라미터 조회] - end
[단일 파라미터 조회]
request.getParameter(username) = hello
request.getParameter(age) = 20
[이름이 같은 복수 파라미터 조회]
request.getParameterValues(username)
username=hello

-위의 사진 처럼 파라미터의 이름은 하나인데 값이 두개 인 경우는 request.getParameterValues() 를 사용한다. 중복일떄 request.getParameter()를 사용하면 request.getParameterValues()의 첫번째 값을 반환한다.

HTTP 요청 데이터 - POST HTML Form

Http Form은 주로 회원가입, 상품 주문에서 사용하는 방식이다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/request-param" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
</body>
</html>

Form을 전송 시 Http message

  • concontent-type: application/x-www-form-urlencoded

  • message body: username=hello&age=20

  • 서버 입장에선 request.getParameter()로 조회 가능 즉 GET url 형식도 지원, Post Html Form 형식도 지원

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

관련 코드

package hello.servlet.basic.request;

import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {

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

  • Postman으로 API 메세지 바디에 text로 보낼 시 데이터를 읽을 수 있음

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

-Postman으로 Json 데이터 {"username": "hello", "age": 20}을 보낸 경우

JSON 형식 파싱 추가

package hello.servlet.basic;

import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class HelloData {

    private String username;
    private int age;


}
package hello.servlet.basic.request;

import com.fasterxml.jackson.databind.ObjectMapper;
import hello.servlet.basic.HelloData;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

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

    }
}
  • Postman으로 Http API 메세지에 JSON 데이터 ({"username": "hello", "age": 20})파싱 후

HttpServletResponse - 기본 사용법

HTTP 응답 메세지의 역할은 -> HTTP 응답 코드 지정, 헤더 생성, 바디 생성

관련 코드

package hello.servlet.basic.response;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

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

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

//        content(response);
        cookie(response);
        redirect(response);

        PrintWriter writer = response.getWriter();
        writer.print("ok");


    }

    private void content(HttpServletResponse response) {
//Content-Type: text/plain;charset=utf-8
//Content-Length: 2
//response.setHeader("Content-Type", "text/plain;charset=utf-8");
        response.setContentType("text/plain");
        response.setCharacterEncoding("utf-8");
//response.setContentLength(2); //(생략시 자동 생성)
    }

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

content 메서드

  • response.setContentType("text/plain") : 콘텐트 타입 지정
  • response.setCharacterEncoding("utf-8"): 인코딩 지정

cookie 메서드

  • 쿠키의 기본 정보를 지정 할 수 있다. -> 쿠키 유효기간

redirect 메서드

  • status를 302코드로 지정해 클라이언트에게 redirect를 할 수 있게 해준다.
  • response.sendRedirect("/basic/hello-form.html") 을 사용하면 status 지정과 redirect 주소를 둘 다 사용 할 수있다.

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

✍ 단순 텍스트와 , Html, Json 응답을 할 수 있다.

관련 코드


package hello.servlet.basic.response;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

@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"),response.setCharacterEncoding("utf-8") 콘텐트 타입과 인코딩을 지정한다.
  • 웹 클라이언트에게 html을 전송해 준다.

HTTP 응답 데이터 - API JSON

관련 코드

package hello.servlet.basic.response;

import com.fasterxml.jackson.databind.ObjectMapper;
import hello.servlet.basic.HelloData;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@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 : applicationt / json

        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");

        HelloData helloData = new HelloData();

        helloData.setUsername("kim");
        helloData.setAge(20);

        //{"username" : "kim", "age" : 20}

        String result = objectMapper.writeValueAsString(helloData);

        response.getWriter().write(result);

    }
}
  • 인코딩과 콘텐트 타입을 설정해준다.
  • 객체를 생성하여 값을 넣어주고 objectMapper.writeValueAsString을 사용하여 객체를 JSON 형태로 변경해줘 웹 브라우저에게 response 해준다.
profile
운동과 개발 공부 둘 다 놓치지 말자!

0개의 댓글