본문 바로가기
BackEnd/java spring

[Spring MVC] HttpServletRequest, HttpServletResponse

by kkkdh 2023. 3. 6.
728x90

HttpServletRequest의 역할

HTTP request message를 개발자가 직접 parsing 해서 사용해도 되지만, 매우 불편한 과정일 것이다.

 

이러한 일련의 과정을 서블릿이 대신 맡아 HTTP request message를 편리하게 사용할 수 있도록 새로운 객체를 만들어 parsing 한 정보를 관리하는데, 이 객체가 바로 HttpServletRequest이다.

 

  • START LINE
    • HTTP method
    • URL
    • query string
    • schema, protocol
  • Header
    • 헤더 조회
  • Body
    • form 형식의 데이터 조회
    • json과 같이 message body를 통한 데이터 직접 조회

위의 정보들을 편리하게 조회할 수 있도록 도울 뿐만 아니라 여러가지 부가 기능도 함께 제공한다.

 

임시 저장소

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

세션 관리 기능

  • request.getSession(create: default is true)
  • 세션 객체를 조회할 수도 있다.

HTTP request data

HTTP request message를 통해 client에서 server로 데이터를 전달하는 방법은 거의 다음 3가지 방식을 따른다.

  • GET - query parameter
    • /url?param1=1&param2=2
    • message body 사용하지 않고, url 자체에 데이터를 담아서 전달한다.
    • 예) 검색, 필터, 페이징 등에서 많이 사용하는 데이터 요청 방식
  • POST - HTML form
    • content-type: application/www-form-urlencoded
    • message body에 query parameter 형식으로 전달한다. username=hello?age=26
    • PUT, PATCH method는 form data 전송 불가능 (스펙에 따라서)
    • 예) 회원 가입, 상품 주문, HTML form 사용
  • HTTP message body 자체에 데이터를 담아 전달 (with json or xml...)
    • HTTP API에서 주로 사용하는 방식 (REST API는 HTTP API에 포함되는 개념)
    • 데이터 형식은 요즘에는 주로 json을 사용
    • POST, PUT, PATCH 등의 HTTP method와 함께 사용되는 방식

client의 데이터 전달 방식은 위의 세 가지에서 벗어나지 않는다.


HttpServletRequest 객체를 이용한 request message data 접근

다양한 get[*]() method를 이용해서 HTTP request message의 header, start-line, body 정보를 다룰 수 있다.

HTTP request message start-line information 가져오기
HTTP request message header information 가져오기

이렇게 start-line, header part로 넘어온 정보들에 접근할 수 있다.

 

GET method에 따른 query parameter 데이터 접근

getParameter method를 이용하면, query parameter로 전달된 데이터에 접근할 수 있다.

이렇게 getParameter method를 이용해서, query parameter에 넘겨온 값에 직접 접근할 수 있다.

http://localhost:8080/request-param?username=kang&age=20

이렇게 조회하면, username에 대해 kang이, age에 대해서는 20이 출력될 것이다.

 

같은 key를 갖는 query parameter를 여러 개 전달하는 경우, 내부 우선순위에 따라 앞에 위치한 parameter 값을 가져온다.

 

만약 이름이 같은 여러 개의 parameter가 전달되고, 전체를 조회하고 싶은 경우에는 getParameterValues method를 사용하면 된다.

getParameterValues를 이용한 같은 이름의 복수 파라미터 값 조회

보통 중복으로 보내는 경우는 거의 없기 때문에, 중복으로 보내는 상황에서는 getParameterValues를 사용해야 함을 인지하고 있도록 하자.

http://localhost:8080/request-param?username=hello&age=20&username=hello2

위와 같은 url에 따른 GET 요청을 보낸다면,

결과는 이렇게

 

POST method에 따른 form data 다루기

post 방식으로 전송해서 request message body로 데이터가 전달된다고 해도 query parameter와 같은 형식으로 전달되기 때문에, 기존에 작성했던 코드에서의 getParameter method를 이용해 data를 조회할 수 있다.

따로 POST method에 따른 요청을 처리하는 코드를 구현하지 않았다.

다만, 몇 가지 차이점이 있다.

  • content-type이 application/www-form-urlencoded이다.
  • message body에 query parameter 형식으로 데이터를 전달한다. → 그래서 getParameter method를 사용 가능

postman을 이용해 테스트 해보자!
같은 결과를 얻을 수 있다.

추가적인 코드 구현 없이, GET에서 query parameter에 접근하는 방식과 동일하게 HTML form에 담겨 전송된 데이터에 접근할 수 있음을 확인할 수 있었다.


API message body

요즘에는 JSON 양식으로 데이터를 전달하는 것이 표준에 해당한다. legacy system에서 간간히 XML을 사용하지만, 대부분 JSON 양식으로 데이터 전달.

 

단순 문자열 전송 처리

일단 간단하게 util package에서 제공하는 input stream을 이용해 message body로 넘어오는 양식 없는 문자열 데이터를 다음과 같이 읽어볼 수 있었다.

인코딩 타입을 UTF-8로 지정하고, 입력받은 message body를 위의 코드로 그대로 읽어올 수 있었고, response message에 실릴 데이터는 "ok"가 전달되도록 간단하게 작성된 코드이다.

실행 결과

JSON 형식의 데이터 처리

  • HTTP method: POST
  • Content-Type: application/json
  • message body: {"username": "kang", "age": 26}

위와 같은 형태로 서버에 데이터를 전달한다.

json에 데이터 전달할 때 큰따옴표로 감싸는 게 규칙이다.

그리고 보통 json 형태로 전달된 데이터를 객체로 만들어서 받아오기 때문에, 다음과 같이 객체를 먼저 설계한다.

lombok을 이용한 getter, setter 생성과 toString method를 overriding 했다.

Spring에서 기본으로 jackson이라는 json 관련 라이브러리를 제공해 준다.

jackson 라이브러리가 제공하는 ObjectMapper를 이용하면, 입력받은 json 형식의 데이터를 손쉽게 객체에 바인딩할 수 있다. (parsing과 binding을 도맡아서 해주는 느낌)

똑같인 ServletInputStream을 이용해 message body에 실려온 데이터를 입력받고, ObjectMapper의 readValue method를 이용해서 json 타입 데이터를 객체에 바인딩했다.

출력 결과

당연히 post method로 form data를 전송하는 경우에도, 직접 스트림을 이용한 데이터 분석이 가능하지만, getParameter method를 servlet이 기본으로 제공하기 때문에, 굳이 이렇게 할 이유는 없다!


HttpServletResponse 객체를 이용한 response message 다루기!

HttpServletResponse의 역할 → HTTP response message의 생성!

  • HTTP status code 지정
  • header 생성
  • body 생성

편의 기능 제공

  • Content-Type 지정
  • Cookie 전달
  • Redirect

response 객체의 setHeader, setStatus method를 이용해 response message에 실릴 header, status code 등의 정보를 손쉽게 세팅할 수 있다.

response message의 header들

bad request로 날릴 수도 있다.

다음과 같은 다양한 method를 활용해 header에 들어갈 정보를 간편하게 세팅할 수도 있다.

setHeader method를 사용하지 않고도, 편리하게 세팅이 가능

또한 Cookie 객체를 생성해 response message에 cookie를 생성해서 보낼 수도 있다. (프로젝트에서 위와 같이 활용해서 jwt를 cookie로 만들어 보내는 방식의 구현을 한 바가 있다)

 

또 위와 같이 sendRedirect method를 활용해 setStatus + setHeader method를 이용해 구현하던 redirection 기능을 간편하게 구현할 수 있는 method 또한 지원한다.

두 방식 모두 동일한 결과를 구현해준다.

redirection 또한 HttpServletResponse 객체를 활용해 간편하게 구현할 수 있었다.

 

HttpServletResponse 객체를 이용한 데이터 전달

문자열을 데이터로 보내거나, HTML 문서를 보내는 경우 앞서 사용한 PrintWriter 객체를 이용하면 된다.

위의 예시는 html tag를 직접 자바 코드로 작성해서 전달하는 형태의 예시이다.

 

Content-Type: text/html, charset=utf-8로 message header에 작성되도록 설정해야 HTML 문서로 전달된다.

 

결과는 다음과 같았음

이렇게 소스를 보면, HTML 문서로 전달되었음을 확인 가능

이번에는 JSON 형태로 response body가 전달되도록 코딩해 보자.

아까 만든 이 객체를 재활용
application/json으로 content-type 설정하고, ObjectMapper를 사용해서 이번에는 객체를 json 형식으로 변경한다. (writeValueAsString method 활용)

위와 같이 ObjectMapper method(jackson library가 제공)를 활용해 다음과 같은 결과를 얻을 수 있었다.

이렇게 간단한 과정도 Spring MVC를 사용하면, 어노테이션만 추가해도 알아서 바인딩해주는 더 간단한 프로세스로 바뀐다.

 

참고: application/json content-type은 스펙상 utf-8 형식을 사용하는 것으로 정의되어 있다고 한다. 따라서 스펙에서 charset=utf-8과 같은 추가 파라미터를 지원하지 않는다고 한다. 따라서 application/json;charset=utf-8은 의미 없는 파라미터를 추가한 것이 된다.
response.getWriter()를 사용하면, 추가 파라미터를 자동으로 추가하는데, 이때에는 response.getOutputStream()을 이용해 직접 stream을 만들어 출력하면, 이런 문제가 없다고 한다.

 

정리!

  • HttpServletRequest 객체는 request message의 parsing을 담당하고, 사용자가 request message를 간단하게 사용할 수 있도록 돕는다.
  • HttpServletResponse 객체는 response message의 생성을 돕는 객체로 다양한 메서드를 제공한다.
  • 두 객체를 이용해서 servlet이 담당하는 부분 외의 비즈니스 로직 구현에만 집중할 수 있는 환경이 조성된다.
  • Spring MVC를 사용하게 되면, 더 편리하게 두 객체가 제공하는 기능들을 사용할 수 있다.
  • form-data로 데이터 전달하는 경우 query parameter와 동일한 형태로 데이터를 전달한다.
    (ex. username=kang&age=20)
728x90

댓글