[Spring][스프링 MVC 1편] 서블릿 기초 사용법

2023. 2. 8. 12:00공부/Spring

728x90

본 포스팅은 김영한 강사님의 인프런 강의 "스프링 MVC 1편"을 정리한 포스팅입니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com

본격적인 MVC 강의에 앞서 과거에 사용하던 servlet에 대해서 간단하게 알아두는 편이 MVC를 제대로 이해하는 것에 도움이 된다고 한다.

 

웹 서버와 WAS

 

웹 서버 : http 기반으로 동작. html, css 이미지 같은 정적 리소스 제공. ex)  NGINX, APACHE

 

WAS : http 기반으로 동작. 애플리케이션 로직 실행. 동적 html, JSON, MVC 등등 ex) Tomcat, Undertow

 

WAS는 정적 리소스를 제공할 수도 있지만 부하가 걸릴 것을 대비하여 웹 서버가 정적 리소스를 제공하도록 하는 편이 좋다.

서블릿(Servlet)

http를 기반으로 통신을 할 때 모든 요청이 동일한 기능을 하는 부분이 있다.

 

HTTP 요청을 파싱하여 어떤 요청인지 파악하는 기능과 HTTP 응답을 만들어서 전달하는 부분이다.

 

모든 요청마다 이러한 부분을 구현하면 비효율적이기 때문에 서블릿에서 이러한 기능을 편리하게 사용할 수 있도록 제공한다.

 

서블릿은 서블릿 컨테이너에서 관리하고 request와 response를 쉽게 관리할 수 있도록 한다.

 

서블릿의 형태는 아래와 같다.

 

@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
}

해당 url로 요청을 넣으면 실행된다. req는 요청, resp는 응답에 관한 기능을 수행한다.

 

Http 요청 데이터 파싱

 

1. GET 쿼리 스트링

 

url에 쿼리 스트링을 사용하여 key-value 쌍을 전달한다.

 

ex) http://localhost:8080/hello?name=chulsoo&age=20

 

서블릿에서는 req.getParameter(key)를 통해 key에 해당하는 value를 가져올 수 있다.

 

getParameter는 무조건 String으로 가져오므로 다른 타입을 원한다면 변환을 해줘야한다.

 

메시지 바디가 존재하지 않는다.

 

2. POST html form

<form action="/request-param" method="post">
  <input type="text" name="username" />
  <input type="text" name="age" />
  <button type="submit">전송</button>
</form>

html form 안에 input 태그의 속성 값으로 name을 넣으면 name이 key가 되고 그 안의 값이 value가 된다.

 

메시지 바디 안에 쿼리 스트링과 비슷한 형태로 들어가게 되고 서블릿에서도 getParamter 메소드로 value를 가져올 수 있다.

 

3. POST 메시지 바디 안에 직접 데이터 넣기

 

메시지 바디 안에 데이터를 넣는다.

 

다음은 메시지 바디 안에 문자를 직접 넣을 때의 코드이다.

 

서블릿에서는 먼저 req.getInputStream 메소드를 사용하여 inputStream을 가져온다.

ServletInputStream inputStream = req.getInputStream();

문자로 바꿀 때는 StreamUtils의 copyToString을 사용한다.

String s = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

 첫 번째 인자로 가져온 inputStream을 두 번째 인자로 타입을 적어준다.

다음은 JSON을 메시지 바디로 넣어줄 때의 파싱 방법이다.

 

먼저 객체를 만들어준다.

@Getter
@Setter
public class HelloData {
    private String username;
    private int age;
}

일단 문자로 변경한다.

ServletInputStream inputStream = req.getInputStream();
StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

 이후 ObjectMapper를 사용해서 객체로 변화할 수 있다.

ObjectMapper objectMapper = new ObjectMapper();
HelloData helloData = objectMapper.readValue(s, HelloData.class);
System.out.println("username = " + helloData.getUsername());
System.out.println("age = " + helloData.getAge());

objectMapper의 readValue 메소드의 첫 번째 인자에 변환한 문자열을, 두 번째 인자에 반환 객체 타입을 넣어준다.

 

Http 응답 데이터 생성

1. http 상태 코드를 넣는다. (직접 코드를 넣기보단 HttpServletResponse 안의 값 활용)

resp.setStatus(HttpServletResponse.SC_OK);

2. 헤더 설정

resp.setContentType("text/plain"); //일반 텍스트 : text/plain, html : text/html JSON : application/json
resp.setCharacterEncoding("utf-8");
resp.setContentLength(2); //생략해도 됨

3. 쿠키 사용 시 설정

Cookie cookie = new Cookie("name", "chulsoo"); //원하는 key-value 쌍
cookie.setMaxAge(600); //초 단위 유효기간
resp.addCookie(cookie); //response에 추가

4. 바디 추가

PrintWriter writer = resp.getWriter();
writer.println("hello world");

html을 반환하고 싶다면 contentType을  text/html로 바꾸고 writer.println으로 태그들을 직접 String으로 넣으면 된다.

 

일반 문자열과 html을 반환하는 방법은 비슷하지만 JSON 형식으로 반환하고 싶다면 추가 작업을 진행해야한다.

 

반환할 객체를 ObjectMapper를 사용하여 문자열로 변환해야한다.

HelloData hello = new HelloData("chulsoo" ,20);
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsBytes(hello).toString();

이후 이 문자열을 write 해주면 된다.

PrintWriter writer = resp.getWriter();
writer.write(s);

<전체 코드>

@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(HttpServletResponse.SC_OK);
        resp.setContentType("text/plain"); //일반 텍스트 : text/plain, html : text/html JSON : application/json
        resp.setCharacterEncoding("utf-8");

        Cookie cookie = new Cookie("name", "chulsoo"); //원하는 key-value 쌍
        cookie.setMaxAge(600); //초 단위 유효기간
        resp.addCookie(cookie); //response에 추가

        HelloData hello = new HelloData("chulsoo" ,20);
        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writeValueAsBytes(hello).toString();

        PrintWriter writer = resp.getWriter();
        writer.write(s);


    }
}
728x90