서블릿

고동현·2024년 4월 14일
0

스프링 MVC

목록 보기
2/13

Hello 서블릿

우선 서블릿을 사용하려면 스프링 부트가 지원하는 서블릿 컴포넌트 스캔을 사용해야 한다.

왜 사용해야되냐? URL 요청이 들어오면 해당 서블릿을 찾아야하는데 서블릿 컨테이너에 서블릿을 등록해놓고, 여기서 찾기 위해서이다.

스프링부트는 직접 서블릿을 등록 및 사용할 수 있도록 @ServletComponentScan을 지원한다.


이 애노테이션을 통해 내가 작성한 서블릿들을 알아서 찾아서 컨테이너에 넣어준다.

서블릿 등록하기

@WebServlet 에노테이션을 통해서 서블릿 등록을 해준다.
name이 helloServlet이고 url Patterns가 /hello로 설정하였다.
그래서 이러한 url패턴으로 들어오는경우 helloServlet이 실행된다.

그래서 이 서블릿이 호출되면 service라는 메서드가 호출되는데,
우리가 이전에 앞에서 Client가 요청을 보내면 이 요청에 맞게, HttpRequest,HttpResponse객체가 생성된다고 하였다.
여기서 해당하는 객체들이 service파라미터의 request,response에 들어가게 된다.

실제로 작동되는지 찍어보면, 정상적으로 출력이 된다.

우리가 그러나 요청을 쿼리파라미터 형식으로 보내고 싶을 때도 있다.
예를 들어, localhost:8080/hello?username=kim 이런식으로 말이다.

그래서 HttpServletRequest를 사용하면 쿼리 파라미터에 있는 data를 쉽게 가져올 수 있다.
만약에, 서블릿의 이런 기능이 없다면,

HTTP요청메시지를 get인지 post인지 content-type부터 일일히 다 파싱해서 가져와야 할 것이다. -> 서블릿이 전부 다 대신해줌


그리고 contenttype을 text로 설정, 그리고 인코딩을 할때 utf-8버전을 쓴다고 한다.
인코딩 버전을 설정하는 이유가, 일본어나 한국어는 아스키 코드에 포함되지 않는 문자가 있기 때문에, 그냥 보내면 외계어처럼 깨진다. 당연히 웹 클라이언트쪽에서는 없는 문자니까 어떻게 표현할지 모르는것이다.

그래서 일반적으로 대부분 웹 브라우저는 utf-8버전을 사용하기 때문에 맞춰 주는것이다.

실행결과

서블릿 컨테이너 동작 방식설명

스프링 부트가 실행되면서, 우선 내장 톰켓 서버를 띄운다.
그러면서 아까 맨처음에 서블릿 컴포넌트 스캔을 돌리면서, 우리가 작성했던 서블릿들을 전부 뒤져서 서블릿 컨테이너에 생성해준다.


그 다음에 localhost:8080/hello라는 요청을 클라이언트가 보내면, 이 http 요청 메시지를 기반으로 request,response객체를 생성하고,
서블릿 컨테이너에 파라미터로 담아서 던진다.
그러면 helloServlet에서 처리를 하고, response객체를 바탕으로 http응답을 생성하고 반환한다.

HttpServletRequest-기본사용법

Client가 Http 요청 메시지를 보내면,

이건 단순히 문자열이다. 만약 서블릿이 없다면, 개발자가 일일히 파싱해서 사용해야할 것이다.
그러나, 서블릿을 통해 http메시지를 쉽게 이해할 수 있다.

기본사용법

아래의 설명하는 메소드들은, 특정한 로직이 있는게 아니라, 그저 HttpServlet의 기능들이다.
고로, 특별한 설명 없이 필요할때마다 찾아서 쓰자.

printStartLine

request.getQuerString을 통해서 username=hi를 가져올 수 있다.

printHeaders

헤더정보를 가져오는것이다.

printHeaderUtils

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

printEtc

  • 지금까지 설명한것들은 서블릿의 특정한 기능들을 나열한 것이다.
    이제 본격적으로 HTTP 요청 데이터를 어떻게 조회하는지 알아보자.

HTTP요청 데이터 - 개요

이제 그럼, 어떻게 클라이언트가 서버로, HTTP요청을 보낼때 Data를 포함시켜 보낼지 알아 보겠다.

예를 들어, 이런상황을 가정해볼 수 있겠다.
id가 1번인 user를 조회->id값을 서버로 전달해야함
상품을 등록 -> 상품 이름, 상품 가격, 상품 원산지 등등을 전달해야함

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

GET-쿼리 파라미터
/url?username=hello&age=20
메시지 바디 없이, URL의 쿼리파라미터에 데이터를 포함해서 전달.
ex). 검색, 필터, 페이징

POST-HTML Form
Data가 HTML Form형식으로 전달되는것을 말한다.

그림과 같이, HTML Form에 username,age를 입력받는 곳이 있고, 이 HTML Form에서 입력받은 값으로 HTTP 메시지를 만들어 전송한다.

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

HTTP message body에 직접 데이터를 담아서 요청
HTTP API에서 주로 사용, JSON

하나씩 알아보자

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

다음 데이터를 클라이언트에서 서버로 전송해보자.

  • username:kim
  • age:20

메시지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달 할 것이다.
쿼리파라미터는 URL에 ?를 시작으로 보낼 수 있다. 추가 쿼리 파라미터는 & 로 구분하면된다.

전체 파라미터조회

request.getPrameterNames로 가져올 수 있는데, 이터레이터를 통해 forEach로 전부 가져와서 출력하였다.

단일파라미터 조회

단일파라미터 조회는 단순하게 key에 해당하는 것을 파라미터로 getParameter를 호출하면된다.

이름이 같은 복수 파라미터 조회
만약에, username=kim,username=go 이런식으로 이름이 동일한데 value가 2개 있으면 어떻게할까?
단순히, getParameter로는 안될것이다. 그럼 kim을 가져올지 go를 가져올지 결정하지 못하니까 오류가 발생한다.
이런경우에는 getParameterValues로 가져오면된다.
반환형은 String타입의 배열이다.

HTTP 요청 데이터 - Post Html Form

이번에는 HTML의 Form을 통해서 클라이언트에서 서버로 데이터를 전송하는 방식을 알아보겠다.

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

HTML Form

여기서 봐야할것은 action이 /request-param인것이다.
그러면 post형식의 /request-parm 형식의 url을 가진 서블릿을 호출하게 된다.

이렇게 Post의 HTML Form을 전송하면 웹브라우저는 다음 형식으로 HTTP메시지를 만든다.

  • 요청 URL : http:/localhost:8080/request-param
  • content-type : application/x-www-form-urlencoded
  • message body : username=hello&age=20

그럼 여기서 두가지 의문이 들것이다.

  1. content-type이 왜 필요한가?
  2. 아까 껀 get이고 이번껀 HTML Form형태의 post 방식인데 동일한 서블릿을 사용해도 되는가?
  1. 우리는 HTTP Body에다가 데이터 형식을 넣는게 두가지 방식이 있다고 했다.
    하나는 이번에 하는것처럼 HTML Form형태를 사용해서 쿼리파라미터 형식을 넣는것,
    다른하나는 JSON형식을 넣는것,
    그래서 이것을 구분짓기 위해서 HTML Form형태를 사용해서 쿼리파라미터 형식을 메시지 바디에 넣어줬다면, content-type : application/x-www-form-urlencoded 로 설정하고 뒤에서 나오겠지만
    Json이면, application/json이다.

  2. 결국 application/x-www-form-urlencoded 형식은 앞에서 본 Get의 쿼리파라미터 형식과 동일하다.
    그러므로 쿼리파라미터 조회 메서드를 그대로 사용하면 된다.
    물론, 클라이언트 입장에서는 두 방식에 차이가 있다. HTML Form을 사용하느냐, URL에 Data를 포함해서 넘기느냐
    그러나, 서버의 입장에서는 둘의 형식이 동일하므로, request.getParameter()로 구분없이 조회가 가능하다.

    정리하자면, reuqest.getParameter()는 Get URL 쿼리 파라미터 형식도 지원하고, Post HTML Form형식도 둘다 지원한다.

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

이번에는 HTTP API에서 주로 사용하는 JSON형식으로 데이터를 전달 해 보자.

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

key에 해당하는 username과 age가 있다.

RequestBodyJsonServlet
이제 서블릿을 등록하고 사용해보자.

우선 여기서 쓰인 ObjectMapper는 일단 넘어가고,
request.getInputStream메서드로 바디에 있는 내용을 가져 오고,
이걸 utf-8버전으로 string으로 변환해야한다.
여기에 있는 inputstream은 바이트 코드이기때문에, 바이트코드를 문자로 바꾸려면, 어떤 버전으로 변환하는지 명시해야한다.

여기서 sout으로 messageBody를 해주면,
message boyd: {"username": "hello","age":20}
으로 나온다.

그런데 아까 말했듯이, JSON은 어쨋든 그냥 Text형식이다. 객체로 사용하기 위해서 이 문자열을 파싱해줘야만 한다.

고로, Json결과를 파싱해서 사용할 수 있는 자바 객체로 변경하려면, Jackson과 같은 Json변환 라이브러리를 추가해서 사용한다.
스프링 MVC를 선택하면 Jackson라이브러리(objectMapper)를 제공한다.

그래서 ObjectMapper.readValue를 통해서 Json형식을 자바 객체로 만든다.

HttpServletResponse - 기본사용법

HttpServletResponse는 HTTP응답 메시지를 생성하는 역할을 담당한다.

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

HttpServletResponse

서블릿 등록을 한뒤에,
status-line
response.setStatus 메서드를 통해 상태를 지정할 수 있다.
200이라고 적어도 되지만, HttpServletResponse.SC_OK를 사용하면 명확한 의미를 알 수 있어서 좋다.

response-headers
그다음, setHeader메서드를 통해서,
Content-Type,Cache-Control,Pragma등으로 헤더를 세팅할 수 있고, 또 임의의 헤더를 생성도 가능하다.

Header 편의 메서드

앞에서 reqsponse-header처럼 setHeader등으로 일일히 헤더를 세팅할 수 있지만,setContentType과 setCharacterEncoding등으로, 주석처리 부분을 생략해도 자동 생성된다.


쿠키에서는 쿠키를 만들고 setmaxAge로 expire기간을 정한다음에 addCookie메서드를 통해서 쿠키 설정이 가능하다.

redirect같은 경우에 response.sendRedirect 메서드에 redirect할 파일명을 작성하면, 자동으로 redirect까지 된다.

여기까지는 그냥 HttpServletResponse의 기능들이고, 필요하면 더 찾아서 쓰면된다.

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

우리가 HTTP요청 데이터를 3가지 방식으로 서버로 보냈다.
그러면, 서버에서 우리한테 줄때도, 3가지 방식이 대체로 있는데

  1. 단순 텍스트 응답
  2. HTML Form 응답
  3. HTTP API-JSON 응답

이렇게 3가지가 있다.
1번 같은 경우에는 앞에서 writer.println("ok");로

이렇게 단순문자열이 반환되어 찍히는 것을 볼 수 있었다.

이제는 HTML FORM형식을 반환하는 방법을 알아 보겠다.

ResponseHtmlServlet

우선 Content-type인코딩 버전을 설정하는게 제일 중요하다.
왜냐하면, 내가 text/html로 content-type을 설정을 해야지만, 클라이언트 입장에서 아 얘가 HTML FORM을 보냈구나 하고,html file을 정상적으로 렌더링 한다.
여기서 렌더링할때, utf-8버전으로 인코딩을 하여, 한글이 깨지지 않게 하였다.

그다음에 뭐 writer에서 println으로 HTML 형식으로 써주면 끝이다.

응답결과가 마치 안녕이라는 문자열을 찍어준거 같지만,
검사로 들어가서 확인해보면,

응답이 html form형태로 온것을 확인 할 수 있다.

HTTP 응답 데이터 - API JSON

이제는 JSON형식을 반환해보자.

ResponseJsonServlet

Json형식도 마찬가지도 ContentType을 application/json으로 설정을 해야 판단이 가능하다.

흠... Json형식이니까 contentType을 application/json으로 설정한다? 이렇게 이해해도 괜찮긴한데,
만약 아에 이런 contentType이라는 개념이 없다고 생각해보자.

그럼 내가 메세지 바디에, 일반 문자열, HTML FORM ,JSON이렇게 보냈을때, 이게 클라이언트가 띡 문자열로 이루어진것을 보고, 뭔줄알고 렌더링을 하겠는가?
만약에 HTML FOrm을 보냈는데 문자열로 그냥 띡 렌더링을 하면, 태그들까지 </ div>이런것도 다보일것이다. 위에서 안녕만 나오지 않은것처럼.

그래서 이 문자열을 잘 파싱할 수 있게 type을 지정해주는것이다.

data라른 객체를 만든뒤에 반환하려면 ObjectMapper를 사용해서 writeValueAsString을 사용하면, 객체를 Json문자로 변경이 가능하다.

그러면 이런생각이 든다. 그냥 반환형을 public HelloData service 이런식으로 만들고 return data로 그냥 객체 반환해주면 안되나?

이걸 스프링 MVC에서는 지원한다.
그래서 나중에
public HelloData(){
return data;
}
하면 data 객체를 JSON형식으로 만들어서 반환해준다.

뒤에서 어차피 알아볼 것이다.

profile
항상 Why?[왜썻는지] What?[이를 통해 무엇을 얻었는지 생각하겠습니다.]

0개의 댓글