<< 학습 목표 >>
1. 클라이언트와 서버가 통신하는 과정에 필요한 구성요소들을 설명할 수 있다.
2. 뷰(View), 컨트롤러(Controller), 서비스(Service)에 대해 설명할 수 있다.
2. 서버로 요청하는 뷰 페이지를 만들 수 있다.
3. 클라이언트의 요청을 받을 컨트롤러를 만들 수 있다.
4. 클라이언트의 요청을 처리할 서비스 클래스를 만들 수 있다.
5. 클라이언트의 요청 처리 결과를 클라이언트에게 전달할 수 있다.
앞서 서블릿을 생성하고 브라우저에서 직접 서블릿의 URL를 입력해 서블릿을 호출했는데 이번에는 좀 더 실전과 가까운 경험을 해보자
실제 개발할 때는 아래와 같이 웹 페이지, 서블릿, 자바, DB가 함께 동작해 하나의 서비스가 됨
( 앞서 설명한 웹 서버가 요청을 받아 서블릿 컨테이너에게 위임하는 부분은 생략함 )

| 1. 요청(Request) |
| 클라이언트는 웹 페이지에서 원하는 컨텐츠를 클릭, 입력 등을 해 서버로 요청을 보냄 서버의 서블릿이 클라이언트의 요청을 받음 |
| 2. 자바의 메서드 호출 |
| 서블릿이 클라이언트의 요청을 직접 처리하기도 하지만 서블릿은 주로 컨트롤러(Controller, 제어자)의 역할로 클라이언트의 요청을 받아 요청을 처리할 수 있는 메서드를 호출함 요청을 처리할 수 있는 메서드는 개발자가 직접 만드는 것 |
| 3. DB로 쿼리(Query) 전송 |
| 클라이언트가 보낸 데이터를 DB에 저장하거나(INSERT), DB에 저장된 데이터를 수정하거나(UPDATE), 삭제(DELETE), 또는 조회(SELECT) 해야한다면 메서드가 그러한 역할을 담당함 DB로 INSERT, UPDATE, DELETE, SELECT 를 할 필요가 없다면 당연히 3, 4는 없음 |
| 4. DB의 결과 받기 |
| 메서드가 DB에게 INSERT, UPDATE, DELETE, SELECT 결과를 받음 DB로 INSERT, UPDATE, DELETE, SELECT 를 할 필요가 없다면 당연히 3, 4는 없음 |
| 5. 요청 처리 결과를 서블릿(Controller)으로 반환 |
| 클라이언트의 요청을 처리한 결과를 서블릿으로 반환함 |
| 6. 전달(Response / 응답) |
| 메서드가 반환한 처리 결과에 필요한 부가적인 작업을 하고 클라이언트에게 결과를 전달 웹 프로그래밍에서는 전달을 Response (응답) 이라고 부름 |
위 그림처럼 클라이언트는 요청을, 서버는 응답을 하는 이 전체 과정을 통신이라고 함
따라서 짧게 "클라이언트와 서버는 통신을 한다" 라고 함
우리는 아직 DB 연동을 배우지 않았으니 위 과정의 3, 4를 빼고 1, 2, 5, 6의 과정을 갖고 있는 서비스를 만들자
우리는 계산기 웹 페이지를 만들 것이고 사용자는 계산기 웹 페이지에서 두 수를 입력하고 사칙 연산자 중 하나를 선택함
그 후 [ 결과 보기 ] 를 누르면 계산 결과가 보이는 웹 서비스임
( HTML 기초와 관련된 내용은 언급하지 않습니다. 만약 여기서 사용된 HTML 태그에 대해 모르신다면 우선 HTML, CSS, JS 공부를 하고 오세요 )
<< 웹 페이지 ( HTML ) >>
웹 페이지를 추가하기 위해 webapp 폴더 안에 chapter02 폴더를 만들고 calculator.html 을 만들자
그 후 아래 코드를 입력하자
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>계산기</title>
</head>
<body>
<h1>계산기</h1>
<form action="http://localhost:8080/studyProject/chapter02/calculator" method="GET">
<input type="number" name="firstNumber" placeholder="첫 번째 수">
<select name="operator">
<option>+</option>
<option>-</option>
<option>*</option>
<option>/</option>
</select>
<input type="number" name="secondNumber" placeholder="두 번째 수">
<input type="submit" value="결과 보기">
</form>
</body>
</html>
form 태그의 action 속성은 클라이언트의 요청을 받을 URL ( 서블릿의 경로 ) 임
그리고 요청 방식은 GET 방식임
! 여기서 잠깐 ! URL에 서버 IP 주소가 아니라 localhost 가 들어있는데 이는 특별한 서버 IP 주소로 "내 컴퓨터의 IP 주소" 를 뜻함
웹 서비스를 만들 때 가장 먼저 해야할 것은 클라이언트의 요청을 어느 서블릿이 어떤 요청 방식으로 받아야하는지 생각해야함
그래야 클라이언트가 볼 페이지를 완성할 수 있음

위와 같이 클라이언트가 두 수를 입력하고 연산자를 선택한 후 [ 결과 보기 ] 를 누르면
사용자가 입력한 첫 번째 수는 firstNumber 이름에 담겨 전달 되고 사용자가 입력한 두 번째 수는 secondNumber에 담겨 전달됨
input 태그와 select의 name 속성, form 태그의 action, method 속성을 잘 기억해야함
어디로 전달? action 속성에 적어둔 URL 로 / 어떤 방식으로 전달? method 속성에 적어둔 방식으로...
( 요청 정보가 생각 나지 않는다면 https://codingaja.tistory.com/16 글 다시 보고 오세요 )

( 위 요청 정보에 데이터를 몸통(body)에 담았는데 이는 잘못된 표기법 / 그러나 이해를 위해서 이렇게 표현했음 / 왜 잘못됐는지는 이 다음 글에서 알 수 있음 )
HTML 웹 페이지는 사용자에게 보여지는 화면이므로 "뷰(View)" 라고 함
<< 서블릿 >>
서블릿은 기존에 만들었던 chapter02 패키지 안에 이름을 Calculator인 서블릿을 만들고 아래 코드를 입력하자
( 서블릿 만드는 방법이 생각 나지 않으면 https://codingaja.tistory.com/19 글 다시 보고 오세요 )
package chapter02;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter02/calculator")
public class CalculatorController extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int firstNumber = Integer.parseInt(request.getParameter("firstNumber"));
int secondNumber = Integer.parseInt(request.getParameter("secondNumber"));
String operator = request.getParameter("operator");
System.out.println("클라이언트가 입력한 첫 번째 수 => " + firstNumber);
System.out.println("클라이언트가 선택한 연산자 => " + operator);
System.out.println("클라이언트가 입력한 두 번째 수 => " + secondNumber);
}
}
do 로 시작하는 메서드의 매개변수를 보면 2개의 매개변수가 있음
( 매개변수의 이름이 다를 수 있지만 매개변수의 이름이 중요한건 아님 / 만약 "왜?" 라는 생각이 들면 다시 자바의 메서드를 공부하고 와야함 )
1. HttpServletRequest 타입인 매개변수
2. HttpServletResponse 타입인 매개변수
서블릿은 클라이언트가 보낸 요청 정보를 HttpServletRequest 타입인 첫 번째 매개변수에 저장함
그리고 클라이언트에게 보낼 응답 정보를 HttpServletResponse 타입인 두 번째 매개변수에 저장함
클라이언트가 보낸 firstNumber, secondNumber, operator 를 꺼내려면 위와 같이 request.getParameter("name") 으로 꺼내야함
이때 request.getParameter 메서드는 클라이언트가 보낸 값을 무조건 문자열로 꺼내줌
클라이언트는 "정수" 를 입력했으므로 클라이언트가 보낸 값을 꺼낸 후(1) 정수로 변환함(2)
( 슬라이드 이미지로 되어있으니 넘겨 보세요 )




서블릿은 이렇게 클라이언트의 요청을 받고 클라이언트가 보낸 값을 꺼냄
그 후 클라이언트의 요청을 처리할 수 있는 메서드를 호출하면서 인자로 클라이언트가 보낸 값을 메서드로 전달함
이런 역할을 하는 서블릿을 "컨트롤러(Controller)" 라고 함
아직 우리는 메서드는 만들지 않았으므로 일단 위와 같이 클라이언트가 보낸 값들을 출력만 해봤음
<< 자바 >>
자바 코드는 chapter02 패키지에 CalculatorService 클래스를 만들고 아래 코드를 입력하자
package chapter02;
public class CalculatorService {
// 덧셈
public int add(int firstNumber, int secondNumber) {
return firstNumber + secondNumber;
}
// 뺄샘
public int sub(int firstNumber, int secondNumber) {
return firstNumber - secondNumber;
}
// 곱셈
public int mul(int firstNumber, int secondNumber) {
return firstNumber * secondNumber;
}
// 나눗셈
public double div(int firstNumber, int secondNumber) {
double result = (double) firstNumber / secondNumber;
return result;
}
}
위 자바 코드는 클라이언트의 요청을 처리할 코드로 컨트롤러에서 operator에 맞는 메서드를 호출해 클라이언트의 요청에 대한 결과를 반환함
이러한 자바 코드를 "서비스(Service)" 라고 함
다시 서블릿(CalculatorController)으로 돌아가서 코드를 수정하자
( 거의 마지막입니다 ~ )
기존에 서블릿에서 클라이언트가 전달한 값을 출력했는데 이제는 클라이언트가 전달한 operator에 맞는 서비스를 호출해 클라이언트의 요청을 처리하고 결과를 받고 있도록 수정했음
package chapter02;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter02/calculator")
public class CalculatorController extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int firstNumber = Integer.parseInt(request.getParameter("firstNumber"));
int secondNumber = Integer.parseInt(request.getParameter("secondNumber"));
String operator = request.getParameter("operator");
CalculatorService cs = new CalculatorService();
int result1 = 0;
double result2 = 0.0;
switch(operator) {
case "+":
result1 = cs.add(firstNumber, secondNumber);
break;
case "-":
result1 = cs.sub(firstNumber, secondNumber);
break;
case "*":
result1 = cs.mul(firstNumber, secondNumber);
break;
case "/":
result2 = cs.div(firstNumber, secondNumber);
break;
}
// 처리 결과를 클라이언트에게 전달
}
}
여기서 조심해야할 점!
나눗셈의 결과는 double 이므로 덧셈, 뺄셈, 곱셈의 결과를 받을 result1 과 나눗셈의 결과를 받을 result2 변수가 있음
그리고 case "/" 의 코드를 주의해서 입력하자
이 서블릿에서 완성하지 못한 부분이 있음
마지막에 있는 "처리 결과를 클라이언트에게 전달"
처리 결과를 클라이언트에게 전달할 때는
1. "결괏값" 만 전달
2. "결과 페이지"를 전달
하는 두 가지 방법이 있음
! 기본적으로 ! 두 가지 방법 모두 응답 정보에 담아서 전달하면 됨
( 나중에가면 2번 방법이 또 분화됨 )
응답 정보는 do 로 시작하는 메서드에서 어떤 매개변수에 담는지?
타입이 HttpServletResponse 인 두 번째 매개변수
먼저 첫 번째 방법인 "결괏값" 만 전달해보자
package chapter02;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter02/calculator")
public class CalculatorController extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int firstNumber = Integer.parseInt(request.getParameter("firstNumber"));
int secondNumber = Integer.parseInt(request.getParameter("secondNumber"));
String operator = request.getParameter("operator");
CalculatorService cs = new CalculatorService();
int result1 = 0;
double result2 = 0.0;
switch(operator) {
case "+":
result1 = cs.add(firstNumber, secondNumber);
break;
case "-":
result1 = cs.sub(firstNumber, secondNumber);
break;
case "*":
result1 = cs.mul(firstNumber, secondNumber);
break;
case "/":
result2 = cs.div(firstNumber, secondNumber);
break;
}
// 처리 결과를 클라이언트에게 전달
PrintWriter pw = response.getWriter();
if(operator.equals("/")) {
pw.print(result2);
} else {
pw.print(result1);
}
}
}
클라이언트에게 결과를 전달하기 위해 응답정보(HttpServletResponse 타입 매개변수)에 들어있는 PrintWriter 객체를 꺼냈음(1)
결과를 전달할 때는 PrintWriter 객체의 print 메서드를 사용함(2)
print 메서드를 사용해서 결과를 출력하면 서블릿이 응답 정보 안에 출력한 결괏값을 담아 클라이언트에게 전달함

우선은 이렇게 서블릿을 마무리하고 확인해보자!
여기까지 우리가 이 글의 처음에 보여준 완전한 하나의 서비스를 만들었음
이제 서버를 시작하고 웹 페이지를 열어 calculator.html 의 경로를 입력해 웹 페이지에 접속하자
( http://localhost:8080/studyProject/chapter02/calculator.html )
그 후 두 값을 입력하고 연산자를 선택한 다음 [ 결과 보기 ] 를 누르면 연산 결과가 보임
결과가 심플하게 보이는 이유는 서버가 처리 "결괏값" 만 보내도록 했으므로...
클라이언트 프로그램인 웹 브라우저의 주요 기능은 "보여주기" 임
따라서 서버가 보낸 처리 "결괏값"만 보여주는 것
이번에는 컨트롤러가 처리 결과를 보내줄 때 "결괏값을 담은 웹페이지"를 보내도록 바꿔보자
( HTML 기초와 관련된 내용은 언급하지 않습니다. 만약 여기서 사용된 HTML 태그에 대해 모르신다면 우선 HTML, CSS, JS 공부를 하고 오세요 )
package chapter02;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter02/calculator")
public class CalculatorController extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int firstNumber = Integer.parseInt(request.getParameter("firstNumber"));
int secondNumber = Integer.parseInt(request.getParameter("secondNumber"));
String operator = request.getParameter("operator");
CalculatorService cs = new CalculatorService();
int result1 = 0;
double result2 = 0.0;
switch(operator) {
case "+":
result1 = cs.add(firstNumber, secondNumber);
break;
case "-":
result1 = cs.sub(firstNumber, secondNumber);
break;
case "*":
result1 = cs.mul(firstNumber, secondNumber);
break;
case "/":
result2 = cs.div(firstNumber, secondNumber);
break;
}
// 처리 결과를 클라이언트에게 전달
PrintWriter pw = response.getWriter();
pw.print("<html>");
pw.print("<head>");
pw.print("<meta charset=\"UTF-8\">");
pw.print("<title>Calculator Result Page</title>");
pw.print("</head>");
pw.print("<body>");
pw.print(firstNumber + " " + operator + " " + secondNumber + " = ");
if(operator.equals("/")) {
pw.print(result2);
} else {
pw.print(result1);
}
pw.print("</body>");
pw.print("</html>");
}
}
컨트롤러를 위와 같이 바꾸고 서버를 재부팅한 후 다시 계산기 웹 페이지로 들어가 결과를 확인해보자
가장 단순한 형태의 HTML 코드만 사용해 결과가 보기 좋게 나오진 않았음
이 방법을 통해 여러분이 알고 있는 HTML, CSS, JS 지식을 더하면 보기 좋게 바꿀 수 있을 것
이번에 굉장히 중요한 내용들을 했음
웹 서비스의 구조와 그 구조에 맞는 뷰, 컨트롤러, 서비스
웹 프로그래밍은 이 구조가 끝 이라고 해도 될 정도이니 우리가 만든 계산기 페이지부터 웹 서비스의 구조와 비교하면서 다시 보자
'Servlet + JSP > Serlvet-Chapter02' 카테고리의 다른 글
| Chapter02. 서블릿의 구조와 라이프 사이클, 동작 순서 (0) | 2023.02.25 |
|---|---|
| Chapter02. 서블릿 추가 & 등록, 실행, 요청(호출) (0) | 2023.02.24 |
| Chapter02. 서블릿 추가, 등록, 실행, 요청(호출) (0) | 2023.02.24 |
| Chapter02. 서버, URL, 포트 (0) | 2023.02.24 |
| Chapter02. 용어 정의 (0) | 2023.02.24 |