성장일기

내가 보려고 정리하는 공부기록

백엔드/스프링 MVC

[Spring MVC] 4. REQUEST와 RESPONSE에 관하여 (HttpServletRequest, HttpServletResponse..) - (1) Request

와나나나 2024. 9. 13. 13:11
728x90

인프런 김영한 강사님의 스프링MVC 강의를 듣고 학습한 내용을 정리한 게시물입니다.

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

 

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

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

www.inflearn.com

 

예전에 서블릿에 대해 간단하게 다루었던 적이 있는데, 자세히는 정리하지 않은 거 같아 정리해보려고 한다.

 

1. 서블릿

서블릿은 간단하게 말하면 http 요청과 응답을 단순화해주는 프로그램이다.

 

 

사용하려면 HttpServlet을 상속받아야 하고, 요청에 사용하냐 응답에 사용하냐에 따라 HttpServletRequest, HttpServletResponse를 사용할 수 있다.

 

요청메시지와 응답메시지를 개발자가 직접 파싱해서, 데이터를 꺼내어오면 힘들텐데 이 과정을 대신 해주는 클래스라고 생각하면 된다. 필요한 정보만 다룰 수 있으니 얼마나 편한가!

 

이 두가지를 자세히 살펴보자.

 


2. HttpServletRequest 

요청메시지를 파싱해주는 클래스이다. 사실 HttpServletRequest은 파싱 뿐만 아니라 저장소기능세션관리 기능도 제공한다.

  • 임시저장소 기능 : HTTP 요청이 시작부터 끝날 떄까지 유지되는 임시 저장소 기능
    • 저장 - request.setAttribute(이름, 값);
    • 조회 - request.getAttribute(이름); // 값이 리턴됨
  • 세션 관리 기능 
    • request.getSession(boolean b); // true: 없으면 생성, false: 없으면 null 반환

 

⚙️ 제공하는 기본 정보 받아오기

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

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse
    response) throws ServletException, IOException {
 		// REQUEST-LINE
        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://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 사용유무


		// Headers
        request.getHeaderNames().asIterator()
		 .forEachRemaining(headerName -> System.out.println(headerName + ": " + request.getHeader(headerName)));
        
        
        // Header 편의 조회
        System.out.println("request.getServerName() = " + request.getServerName()); //Host 헤더
		System.out.println("request.getServerPort() = " + request.getServerPort()); //Host 헤더

 		// [Accept-Language 편의 조회]
        request.getLocales().asIterator() 
        	.forEachRemaining(locale -> System.out.println("locale = " + locale));
 		System.out.println("request.getLocale() = " + request.getLocale());
		
        // [cookie 편의 조회]
		if (request.getCookies() != null) {
 			for (Cookie cookie : request.getCookies()) {
 				System.out.println(cookie.getName() + ": " + cookie.getValue());
 			}
 		}

		// [Content 편의 조회]
 		System.out.println("request.getContentType() = " + request.getContentType());
		System.out.println("request.getContentLength() = " + request.getContentLength());
 		System.out.println("request.getCharacterEncoding() = " + request.getCharacterEncoding());
		
        
    }
}

 

 

헤더 결과

 

헤더 편의 결과

 

상당한 부분의 조회를 제공한다는 것을 알 수 있었다! 

정보의 조회를 알아보았으니, 이제 요청데이터를 어떻게 조회하는지 알아보자

 

 

⚙️HTTP 요청 데이터 받아오기

HTTP 요청 메시지로 클라이언트 -> 서버 데이터를 전달하는 방법은 크게 3가지이다.

 

1. GET 메소드 - 쿼리 파라미터

  • /users?username=gildong&age=10
  • 메시지 바디 없이 URL 쿼리에 데이터 포함해서 전달

2. POST 메소드 - HTML Form (전송할 때)

  • 메시지 바디에 쿼리 파라미터 형식으로 전달 (username=hello&age=30)
  • ex | 회원가입, 상품 주문, HTML Form 사용

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

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

 

자세히 알아보자

 

 

✔️ 1. HTTP 요청 데이터 - GET 쿼리 파라미터

이 방식은 검색, 필터, 페이징에서 많이 쓰는 방식이다. 메시지 바디 없이 다음의 데이터를 전달한다.

- username=gildong

- age=30

 

쿼리 파라미터는 URL에 넣으며, ?뒤에 작성하고 &로 연결하면 된다.

localhost:8080/users?username=gildong&age=30

 

 

이렇게 온 데이터는 아래와 같이 조회할 수 있다.

/**
 * 1. 파라미터 전송 기능
 * http://localhost:8080/request-param?username=hello&age=20
 * 2. 동일한 파라미터 전송 가능
 * http://localhost:8080/request-param?username=hello&username=kim&age=20
 */
@WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
 	@Override
 	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	
        String username = request.getParameter("username"); //단일 파라미터 조회

		Enumeration<String> parameterNames = request.getParameterNames(); //파라미터 이름들 모두 조회

		Map<String, String[]> parameterMap = request.getParameterMap(); //파라미터를 Map으로 조회	

		String[] usernames = request.getParameterValues("username"); //복수 파라미터 조회
    
    }
}

 

 

만약 값이 중복인데, request.gerParameterValues() 가 아닌 request.getParameter() 를 사용하게 되면 첫번째 값을 반환한다.

 

 

✔️ 2. HTTP 요청 데이터 - POST HTML Form

이 형식은 회원가입,  상품 주문 등에서 주로 사용하는 방식이다. 메시지 바디에 쿼리 파라미터 형식으로 데이터를 전달하고, content-type은 application/x-www-form-urlencoded 이다. 쿼리파라미터 EX | username=gildong&age=30

<!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>

 

위 html을 띄웠을 때, username과 age를 입력받게 되고, 그 값이 요청으로 들어올 때 쿼리 파라미터 형식으로 전달된다고 생각하면 된다. input태그의 name에 파라미터명을 지정하면 된다.

 

POST HTML Form 형식의 특징인  application/x-www-form-urlencoded 은 GET 쿼리 파라미터 형식과 같기 때문에 참고하여 그대로 사용하면 된다. 즉, request.getParameter()를 사용하면 된다는 것이다.

 

request.getParameter() 는 GET 쿼리 파라미터 형식과 POST HTML Form 형식을 모두 지원한다 !

 

참고로

content-typeHTTP 메시지 바디의 데이터 형식을 지정한다.
GET 쿼리 파라미터 형식은 URL에 담아 제공하기 때문에 HTTP 메시지 바디를 사용하지 않아 content-type을 지정할 필요가 없지만, POST HTML Form 형식은 HTTP 메시지 바디에 데이터를 담아 보내기 때문에 바디에 들어가는 데이터의 형식을 지정해주어야 한다! 폼으로 데이터를 전송하는 형식을 application/x-www-form-urlencoded 라 한다

 

 

✔️ 3. HTTP 요청 데이터 - API 메시지 바디 _ 단순텍스트

HTTP message body에 쿼리문 형식이 아니라 데이터를 직접 담아 요청을 보낼 수도 있다.

  • HTTP API에서 주로 사용하고 보통 JSON 형식을 가장 많이 사용한다. XML, TEXT 형식도 있다.
  • POST, PUT, PATCH 로 요청한다.

HTTP 바디의 데이터를 InputStream으로 직접 읽을 수도 있다고 한다. 일단은 가장 단순한 텍스트 타입 데이터 요청에 대해 알아보려고 한다.

 

WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-bodystring")
public class RequestBodyStringServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
        // 요청에서 InputStream을 쓸 땐 get메소드를 이용하고, 이는 ServletInputStream 을 반환함
		ServletInputStream inputStream = request.getInputStream(); 
		String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
		System.out.println("messageBody = " + messageBody);

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

 

단순 text타입이므로 conent-type은 text/plain으로 설정한다. 이렇게 하면 content body에 텍스트를 입력할 경우 그대로 받아볼 수 있다. 

 

추가로 inputStream은 byte 코드를 반환하므로 이를 String으로 가져오기 위해서는 문자표 지정이 필요하다. UTF_8로 지정하면 된다.

 

 

✔️ 3. HTTP 요청 데이터 - API 메시지 바디 _ JSON

JSON 형식은 HTTP API에서 가장 많이 사용하는 형식이다.

 

 

특징

  • content-type은 application/json 이다.
  • 결과는 {"username" : "gildong", "age" : 30} 이런식으로 반환된다. 
JSON 이란
JSON은 JavaScript Object Notation (JSON) 의 약자로, Javascript 객체 문법으로 구조화된 데이터를 표현하기 위한 문자 기반의 표준 포맷이다. 

 

JS 공부를 한 적이 있다면 형식 자체는 익숙할 것이다. 이번에는 객체를 직접 만들어서 확인해보자.

 

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

 

/**
 *
 * JSON 형식 전송
 * message body: {"username": "hello", "age": 20}
 *
 */
@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);
		
        	User user = objectMapper.readValue(messageBody, HelloData.class);
		response.getWriter().write("ok");
	}
}

 

message body에  {"username": "hello", "age": 20} 를 넣고 테스트 해주면 된다.

참고로, 저기서 user.getUsername(), user.getAge() 메소드를 사용하면 body에 들어있던 데이터가 들어갔음을 확인할 수 있다.

 


 

글이 길어지고 있어서 HttpServletResponse에 관한 정리는 다음 게시글을 통해 진행할 것이다!