BlueNyang
[멀티캠퍼스] 풀스택 개발자 아카데미 (18) - Servlet/JSP(2)
Java 풀스택 아카데미
· 멀티캠퍼스 JAVA 풀스택 개발자 아카데미 6회차 (18편)

[멀티캠퍼스] 풀스택 개발자 아카데미 (18) - Servlet/JSP(2)

BlueNyangBlueNyang
·
·
약 8분
·
# 부트캠프후기# 멀티캠퍼스it부트캠프# [현대이지웰] JAVA 풀스택 개발자 아카데미 6회차# http-method# character-encoding# mvc-model-1
시리즈·멀티캠퍼스 JAVA 풀스택 개발자 아카데미 6회차(30개의 글)
  • ···
  • 17.[멀티캠퍼스] 풀스택 개발자 아카데미 (17) - Servlet/JSP(1)
  • 18.[멀티캠퍼스] 풀스택 개발자 아카데미 (18) - Servlet/JSP(2)현재
  • 19.[멀티캠퍼스] 풀스택 개발자 아카데미(19) - Servlet/JSP(3)
  • ···

1. 서버와의 대화

저번 글에서는 Servlet과, JSP의 기본 개념을 통해 동적 웹 애플리케이션의 동작 과정에 대한 큰 그림을 그려보았다. 서블릿이 서버에서 실행되는 자바 클래스라는 점과, JSP가 결국 서블릿으로 변환된다는 사실을 알게 되었다. 하지만 "Hello World"만 출력하는 것으로는 사용자와 소통하는 웹 애플리케이션이라고 할 수 없다. 진정한 동적 웹이란 사용자의 입력에 따라 각기 다른 결롸를 보여주는, 즉 '대화'가 가능한 웹을 의미한다.

이번 글에서는 클라이언트(웹 브라우저)가 보낸 데이터를 서버에서 어떻게 받고 처리하는지, 그리고 그 처리 결과를 어떻게 다시 클라이언트에게 보여주는지에 대해 자세히 알아본다. 이를 위해 웹 통신의 핵심 메서드인 GETPOST의 차이점을 명확히 구분하고, 서블릿의 HttpServletRequestHttpServletResponse 객체를 활용하는 구체적인 방법을 다룬다. 이를 통해 단순한 페이지 요청을 넘어, 데이터를 주고받으며 상호작용하는 웹 애플리케이션의 기본을 알게 될 것이다.

또한, 초기 웹 애플리케이션 구조의 하나인 MVC Model 1 아키텍처의 개념과 그 장단점을 파악하여 앞으로 배울 MVC Model 2의 필요성을 자연스럽게 이해하는 것이 목적이다.

2. 요청(Request) 처리

웹 애플리케이션의 가장 기본적인 역할은 사용자의 요청을 받아 그에 맞는 응답을 주는 것이다. 사용자가 로그인 폼에 아이디와 비밀번호를 입력하고 '로그인' 버튼을 누르는 행위, 게시판에서 특정 게시글 제목을 클릭하는 행위 모두 서버로 보내는 '요청'이다. 서버는 이 요청에 담긴 데이터를 올바르게 해석하고 처리할 수 있어야 한다.

2.1. 데이터 전송 방식: GET vs. POST

클라이언트가 서버로 데이터를 전송하는 방식은 여러 가지가 있지만, 가장 대표적인 것이 GETPOST 방식이다. 이 둘의 차이점을 이해하는 것은 웹 개발의 기본 중의 기본이다.

  • GET 방식: 서버로부터 정보를 **조회(Retrieve)**하기 위해 사용되는 메서드이다. 데이터를 URL의 끝에 쿼리스트링(Query String) 형태로 붙여서 전송한다. 예를 들어, http://example.com/search?query=자바와 같은 형태이다.

    • 장점: URL에 데이터가 포함되어 있어 해당 페이지를 북마크하거나 다른 사람에게 링크를 공유하기 용이하다. 또한, 브라우저에 의해 캐시될 수 있어 같은 요청에 대해 더 빠르게 응답할 수 있다.
    • 단점: URL에 데이터가 그대로 노출되므로 아이디, 비밀번호와 같은 민감한 정보를 보내기에는 보안에 매우 취약하다. 또한, URL의 길이에 제한이 있어 전송할 수 있는 데이터의 양이 한정적이다.
GET-방식의-데이터-전송-구조
GET-방식의-데이터-전송-구조
    • POST 방식: 서버에 데이터를 **전달(Submit)**하여 어떤 작업을 처리하도록 요청하기 위해 사용된다. 데이터는 URL에 표시되지 않고, HTTP 요청 메시지의 본문(Body)에 담겨서 서버로 전송된다.

      • 장점: 데이터가 요청 본문에 숨겨져 전송되므로 GET 방식보다 보안에 유리하다. 또한, 전송할 수 있는 데이터의 양에 제한이 거의 없다. 회원가입, 로그인, 파일 업로드 등 서버의 상태를 변경하는 작업에 주로 사용된다.
      • 단점: URL에 데이터가 드러나지 않으므로 해당 페이지를 북마크하거나 공유할 수 없다.
POST-방식의-데이터-전송-구조
POST-방식의-데이터-전송-구조

정리하자면, 단순히 서버의 데이터를 가져와 보여주는 경우에는 GET을, 사용자의 데이터를 서버로 보내 무언가를 생성하거나 수정하는 등 중요한 작업을 처리할 때는 POST를 사용하는 것이 일반적인 원칙이다.

서블릿에서는 이 두 가지 요청을 처리하기 위해 각각 doGet()doPost() 메소드를 제공한다. HTML의 <form> 태그에서 method 속성을 이용해 어떤 방식으로 요청을 보낼지 지정할 수 있다.

2.2. HttpServletRequest 객체

클라이언트가 요청을 보내면, 웹 컨테이너는 해당 요청에 대한 모든 정보를 HttpServletRequest 객체에 담아 서블릿의 doGet() 또는 doPost() 메소드에 인자로 전달한다. 개발자는 이 객체를 통해 사용자가 보낸 데이터를 포함한 다양한 요청 정보를 얻을 수 있다.

  • request.getParameter(String name): <input> 태그의 name 속성값에 해당하는 데이터를 문자열(String)로 받아온다. 가장 기본적이고 많이 사용되는 메소드다.
  • request.getParameterValues(String name): 체크박스처럼 하나의 name으로 여러 값이 전송될 때, 모든 값을 문자열 배열(String[])로 받아온다.
  • request.getParameterNames(): 어떤 name들이 있는지 모를 때, 요청으로 들어온 모든 name들을 Enumeration<String> 타입으로 받아온다.
  • request.setCharacterEncoding("UTF-8"): POST 방식으로 전송된 한글 데이터가 깨지는 것을 방지하기 위해 반드시 호출해야 하는 메소드다. 요청 본문의 인코딩을 지정하며, getParameter()를 호출하기 전에 실행되어야 한다.
Important
Get 방식의 한글 처리 GET 방식은 데이터를 URL에 담아 보내기 때문에 요청 본문이 없다. 따라서 해당 메소드는 적용되지 않는다. GET 방식의 한글 깨짐은 Tomcat 서버의 설정파일 (server.xml)을 통해 URIEncoding을 설정하는 방식으로 해결하는 것이 일반적이다.

3. 응답(Response) 처리

서버가 클라이언트의 요청을 처리한 후에는 그 결과를 다시 클라이언트에게 보내주어야 한다. 이때 사용되는 것이 바로 HttpServletResponse 객체이다. 이 객체는 서블릿 컨테이너에 의해 생성되며, 개발자는 이 객체를 통해 응답의 형식, 내용, 상태 등을 제어할 수 있다.

  • response.setContentType("text/html;charset=UTF-8"): 클라이언트(웹 브라우저)에게 보낼 데이터의 종류(MIME-TYPE)와 문자 인코딩을 알려주는 중요한 메소드다. 이 설정을 통해 브라우저는 "이제부터 오는 내용은 HTML 문서이고, UTF-8로 해석해야 한다"는 것을 인지하게 된다.
  • response.getWriter(): 응답 내용을 작성할 수 있는 PrintWriter 객체를 반환한다. 이 객체의 print() 또는 println() 메소드를 사용해 클라이언트에게 보낼 HTML 코드를 작성할 수 있다.

다음 4.2.doPost()에서 나올 3번 부분이 바로 HttpServletResponse를 사용하여 클라이언트에게 동적인 HTML 페이지를 생성하여 보내는 코드이다.

Request와-Response-객체를-통한-통신-흐름도
Request와-Response-객체를-통한-통신-흐름도

4. 로그인 폼으로 데이터 주고 받기

이제 이러한 이론을 바탕으로 사용자의 아이디와 비밀번호를 입력받아 처리하는 간단한 로그인 폼을 만들어 볼 수 있다.

저번 글과 마찬가지로, 멀티캠퍼스의 강의는 JDK 11, Eclipse IDE, Apache Tomcat 9.0, javax를 사용하며, 필자는 JDK 21, IntelliJ IDEA, Apache Tomcat 10.0, jakarta를 사용한다.

4.1. 로그인 화면 (HTML) 작성

먼저 사용자로부터 입력을 받을 login.html 파일을 src/main/webapp 디렉터리 내에 만들고 다음과 같이 작성한다.

html
<!DOCTYPE html>  
<html lang="ko">  
<head>  
    <meta charset="UTF-8"/>  
    <meta name="viewport" content="width=device-width,initial-scale=1"/>  
    <title>Insert title here</title>  
    <link rel="icon" type="image/png" href="#"/>  
    <link rel="stylesheet" href="style.css"/>  
</head>  
<body>  
<form name="frmLogin" method="post" action="login">  
    <label for="user_id">아이디 : </label><input type="text" id="user_id" name="user_id"/>
    <br/>  
    <label for="user_pw">비밀번호 :</label><input type="password" id="user_pw" name="user_pw">
    <br/>  
    <input type="submit" value="로그인"/>  
    <input type="reset" value="취소"/>  
</form>
</body>  
</html>
  • action="login": 폼 데이터가 /login이라는 URL로 전송된다
  • method="pose": 데이터를 POST 방식으로 전송한다.
  • name="user_id", name="user_pw": Servlet에서 이 name 값을 이용해 데이터를 꺼낸다.
브라우저에 표시된 로그인 폼 화면
브라우저에 표시된 로그인 폼 화면

4.2. 요청 처리 Servlet 작성

이제 login.html에서 보낸 쵸청을 처리할 LoginServlet을 작성한다.

java
// LoginServlet.java
package com.example.practice.sec02;

import jakarta.servlet.Servlet;  
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.Serial;  
  
@WebServlet("/login")  
public class LoginServlet extends HttpServlet {
	@Serial
	private static final long serialVersionUID = 1L;
    
    /**  
     * @see Servlet#init(ServletConfig)  
     */
    public void init(ServletConfig config) throws ServletException {  
	    System.out.println("Start Thread");  
	}  
  
  
	/**  
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)  
	 */
	 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
	    System.out.println("Request Method : GET");
	    // doGet은 보통 화면을 보여주는 용도로 사용된다.
	    // 예를 들어, 로그인 폼 페이지로 다시 보내고자 할 때 다음과 같이 작성하여 사용한다.
	    // response.sendRedirect("login.html");
	}  
  
	/**  
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)  
	 */
	 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    // 1. POST 요청 받음
	    System.out.println("Request Method : POST"); 
	    // 한글 인코딩 설정
	    request.setCharacterEncoding("UTF-8");  
  
		// 2. 클라이언트가 보낸 데이터 받기
	    String user_id = request.getParameter("user_id");
	    String user_pw = request.getParameter("user_pw");
	    
	    //3. 응답 페이지 형식 및 인코딩 설정하기
	    response.setContentType("text/html;charset=UTF-8");
	    PrintWriter out = response.getWriter();
	    
	    //4. 응답 HTML 작성
	    out.println("<!DOCTYPE html>");
	    out.println("<html>"
	            + "<head>"
	            + "<meta charset='UTF-8'>"
	            + "<title>Insert title here</title>"
	            + "<link rel='stylesheet' href='style.css' />"
	            + "</head>"
	            + "<body>"
	    );
	    out.println("<span>user_id : " + user_id + "</span><br>");  
	    out.println("<span>user_pw : " + user_pw + "</span><br>");  
	    out.println("</body></html>");
	}
}
  • @WebServlet("/login"): 이 서블릿이 /login 경로의 요청을 처리하도록 매핑한다.
  • doPost(): <form>methodpost이므로 doPost() 메소드에서 요청을 처리한다.
현재 코드에서도 알 수 있듯이 out.println()을 사용하여 HTML을 작성하는 것은 매우 비효율적이며 가독성이 저하된다. 또한, 아주 작은 수정조차 재컴파일을 요구하는 문제가 있다. JSP는 이러한 문제를 해결하기 위해 등장했다.

4.3. 실행 결과 확인

서버를 실행하고 login.html에 접속하여 아이디와 비밀번호를 입력한 후 '로그인' 버튼을 클릭하면, LoginServlet이 이를 받아 처리한 결과가 화면에 출력된다.

서블릿이 로그인 정보를 받아 출력한 결과 화면
서블릿이 로그인 정보를 받아 출력한 결과 화면
콘솔 화면
콘솔 화면

5. MVC Model1 Architecture

지금까지 우리는 HTML로 화면을 만들고, Servlet으로 로직을 처리하는 역할을 분리했다. 하지만 자바 코드 안에서 println()으로 복잡한 HTML 구조를 만드는 것은 매우 번거롭고 가독성이 떨어지기 때문에, 초창기 웹 개발에서는 이보다 더 단순한 구조를 사용했는데, 바로 MVC Model 1 아키텍처이다.

Model 1 구조에서는 JSP 페이지가 클라이언트의 요청을 직접 받고, 비즈니스 로직 처리(Controller 역할)와 결과 화면 생성(View 역할)을 모두 담당한다. 데이터베이스와의 연동이 필요할 경우, JSP는 자바빈(JavaBean)이나 DAO(Data Access Object)와 같은 모델(Model) 객체를 사용한다.

MVC-Model-1-아키텍처-구조도
MVC-Model-1-아키텍처-구조도

5.1. Model 1의 장점과 단점

  • 장점: 구조가 단순하여 개발 속도가 빠르고 배우기 쉽다. 소규모 프로젝트나 간단한 기능 구현에 적합하다.
  • 단점: JSP 페이지 하나에 프레젠테이션 로직(HTML/CSS/JS)과 비즈니스 로직(Java 코드)이 뒤섞이게 된다. 이로 인해 프로젝트의 규모가 커질수록 코드가 복잡해져 가독성이 떨어지고, 유지보수와 재사용이 매우 어려워진다. 디자이너와 개발자의 작업 영역이 명확히 분리되지 않아 협업에도 어려움이 따른다. 흔히 말하는 '스파게티 코드'가 되기 쉽다.

5.2. JSP로 퀴즈 페이지 만들기 (Model 1)

Model 1 구조를 이해하기 위해, 퀴즈를 보여주고, 정답을 입력받은 뒤, 오답인지를 판별하여 보여주는 페이지를 JSP만으로 작성해 본다.

5.2.1. response.jsp 작성

jsp
<%-- src/main/webapp/response.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<!DOCTYPE html>  
<html lang="ko">  
  <head>  
    <meta charset="UTF-8">  
    <title>response 객체</title>  
    <link rel="stylesheet" href="../style.css"/>  
  </head>  
  <body>
    <form method="post" action="responseOk.jsp">  
      <label for="answer">대한민국의 수도는 ?</label>  
      <input type="text" name="answer" size="10" id="answer">  
      <input type="submit" value="전송">  
    </form>  
  </body>  
</html>

5.2.2. responseOk.jsp 작성

jsp
<%-- src/main/webapp/responseOk.jsp --%>
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<!DOCTYPE html>  
<html>  
  <head>  
    <meta charset="UTF-8">  
    <title>Insert title here</title>  
    <link rel="stylesheet" href="../style.css"/>  
  </head>  
  <body>
    <%--  request 객체에 저장되어 전달되는 answer 값에 따라 두 페이지 중 하나로 포워딩 --%>
    <%! String answer; %>  
    <%
      request.setCharacterEncoding("UTF-8");  
      answer = request.getParameter("answer");  
  
      if ("서울".equals(answer)) {  
        response.sendRedirect("pass.jsp");  
      } else {  
        response.sendRedirect("fail.jsp");  
      }  
    %>  
  </body>  
</html>

이 jsp 페이지는 response.jsp가 보낸 POST 요청을 받아 처리하는 페이지 이다. answer 파라미터를 직접 받아 오답 여부를 판별한 뒤, pass.jsp 또는 fail.jsp로 보낸다.

5.2.3. pass/fail.jsp 작성

jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<!DOCTYPE html>  
<html>  
  <head>  
    <meta charset="UTF-8">  
    <title>pass/fail 페이지</title>  
    <link rel="stylesheet" href="../style.css"/>  
  </head>  
  <body>
    <%-- fail.jsp는 오답입니다. 로 작성 --%>
    정답입니다!  
  </body>  
</html>

5.2.4. 결과

JSP-Model-1-퀴즈-실행-결과-화면
JSP-Model-1-퀴즈-실행-결과-화면

responseOk.jsp를 보면, HTML 코드 중간에 <% %> 스크립틀릿을 사용하여 자바 코드가 삽입되어 있는 것을 볼 수 있다. 이처럼 요청 처리, 로직 수행, 화면 출력이 한 파일에 모두 섞여 있는 것이 바로 MVC Model 1 구조의 전형적인 모습이다.

6. 결론

이번 2편에서는 클라이언트의 요청을 처리하는 GET/POST 방식의 차이점부터 시작하여, HttpServletRequestHttpServletResponse 객체를 이용해 데이터를 주고받는 구체적인 방법을 실습을 통해 알아보았다. 이를 통해 웹 애플리케이션의 기본적인 데이터 흐름을 이해할 수 있었다.

또한, 초기 웹 개발 방식인 MVC Model 1 아키텍처에 대해 학습했다. JSP가 컨트롤러와 뷰의 역할을 모두 담당하는 Model 1은 간단한 애플리케이션을 빠르게 개발할 수 있다는 장점이 있지만, 로직과 화면이 뒤섞여 애플리케이션이 복잡해질수록 유지보수가 어려워진다는 명확한 한계를 가지고 있다.

이러한 Model 1의 한계를 극복하기 위해 등장한 것이 바로 역할을 명확하게 분리하는 MVC Model 2 아키텍처이다. 다음 글에서는 Model 1의 문제점을 해결하고 보다 체계적이고 확장 가능한 애플리케이션을 만들기 위한 MVC Model 2 아키텍처와, 이를 효율적으로 구현하기 위한 프론트 컨트롤러(Front Controller) 패턴에 대해 다루어 볼 것이다.

BlueNyang
작성자BlueNyang
라이선스
CC BY NC
BlueNyang

BlueNyang

BlueNyang의 개발 log

카테고리

  • Development
  • Framework
  • Language
  • Dev Tools
  • DevOps & Infra
  • Studies

페이지

© 2026 BlueNyang. All rights reserved.

Made with Nuxt.js and Directus