IT/Backend

JSP + Servlet

_KH_ 2025. 3. 2. 23:20

 서블릿Java로 웹 요청(HTTP)을 처리하는 API.

원래 자바는 웹 개발과는 거리가 멀었다 (HTTP 요청/응답이 불편)

 

그때, 서블릿이라는 API가 등장하면서 자바로도 웹 개발을 할 수 있게 되었다. (HTTP 요청이 편해짐)

서블릿은 웹 서버에서 동작하며, HTTP 요청을 받아 처리하고, 클라이언트(웹 브라우저)로 응답을 보내는 역할을 한다.

서블릿에서 진화한 JSP가 등장했고, 그 이후에 Spring이 등장했다.

 

(서블릿보다 jsp가 편하고 jsp는 서블릿으로 자동 변환된다. 확장자는 .java) 

 

서블릿의 HTTP 요청/응답 과정

  1. 클라이언트(웹 브라우저)가 요청을 보내면,
  2.  웹 서버(Tomcat)가 요청을 서블릿으로 전달하고,
  3.  서블릿이 그 요청을 처리한 후,
  4.  서블릿이 응답을 생성해서 응답을 보내고,
  5. 웹 브라우저가 응답을 받아 화면에 표시한다.
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html"); // 응답 타입 설정
        PrintWriter out = response.getWriter(); // 응답을 출력할 스트림
        out.println("<h1>Hello, Servlet!</h1>"); // 응답 데이터 전송
    }
}

 

요청 : HttpServletRequest / 응답 : HttpServletResponse


JSP : JSP는 HTML 안에서 Java 코드를 실행할 수 있는 기술로, 서블릿보다 편리하다.

JSP 파일은 내부적으로 서블릿으로 변환되어 실행되며 서블릿보다 코드가 간결해서 웹 페이지 개발이 쉽다. 

JSP도 SPRING이 나오면서 많이 사용되지는 않는듯.

 

JSP의 HTTP 요청/응답 과정

  1. 클라이언트가 index.jsp 요청
  2. JSP 파일이 서블릿(Java 코드)로 변환됨
  3. 서블릿이 컴파일되고 실행됨
  4. 서블릿이 HTML을 생성하여 클라이언트에게 응답
  5. 웹 브라우저가 HTML을 렌더링하여 사용자에게 표시

※ 서블릿이란? (Servlet) : 
.java로 끝나는 클래스 파일의 한 종류
not POJO (여태껏 써온 평범한 클래스가 POJO에 해당함)
뭔가 많이 추가된 클래스 파일
서버(백)를 구현할 때 활용하는 클래스 파일 
자바에서 미리 구현한 HttpServelt을 서블릿을 상속 받아서 구현하기 때문에 NOT POJO


서버(웹 서버) : Tomcat
서블릿 클래스 파일을 new 해주는 역할 담당
객체를 생성해주는 역할을 하며, 이 역할을 컨테이너라고 한다.
톰캣은 대표적인 서블릿 컨테이너
기억했다가 서버를 실행할 때 만들어줌


JSP로 생성한 파일(.jsp)이 .java로 컴파일 된다.
>> 파일 펼쳐보면 서블릿이랑 매우 유사함!!
>> 결국 서블릿이 되는 것 ★★(=자바코드)


JSP에는 선언을 별도로 하지 않아도 쓸 수 있는 내장 객체가 있다 >> "JSP 내장객체"
>> request, response, out, session, application(=서버), page
--->>> request, session, application
① request 
요청 단위. 하나의 요청이 끝나면 사라진다. ex) 단순 검색정보, ..
② session 
브라우저 단위. 로그인 등에 사용됨. 다른 요청이라도 데이터가 유지된다. ex) 로그인정보, 장바구니 
③ application 
서버. ex) 광고 안 보기
>> 셋은 유효범위가 다르다. (1에서 3으로 갈 수록 커짐)


[ Servlet 예 1 ]

package calc;

import java.io.IOException;
import java.io.PrintWriter;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/calc") // CalcServlet01 calcServlet01 = new CalcServlet01();
public class CalcServlet01 extends HttpServlet {
	private static final long serialVersionUID = 1L; // 직렬화

    public CalcServlet01() {
    }
    
    private int calc(int num1,int num2,String op) {
    	int res=0;
    	if(op.equals("+")) {
			res=num1+num2;
		}
		else if(op.equals("-")) {
			res=num1-num2;
		}
		else if(op.equals("x")) {
			res=num1*num2;
		}
		else if(op.equals("/")) {
			res=num1/num2;
		}
    	return res;
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("GET 요청을 받은 상태");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int num1 = Integer.parseInt(request.getParameter("num1"));
		int num2 = Integer.parseInt(request.getParameter("num2"));
		String op = request.getParameter("op");
				
		int res=calc(num1,num2,op);
		
		PrintWriter out = response.getWriter();
		out.println("<!DOCTYPE html>");
		out.println("<html>");
		out.println("<head>");
		out.println("<meta charset=\"UTF-8\">");
		out.println("<title>계산기 예제 01 - 결과</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>계산결과</h1>");
		out.println("<hr>");
		out.println(res);
		out.println("</body>");
		out.println("</html>");
	}	
}
@WebServlet("/calc")

// 해당 URL 요청이 이 서블릿으로 전달된다.

 

   public CalcServlet01() {
    }

기본 생성자. 서블릿이 처음 로드될 때, 웹 컨테이너는 기본 생성자를 호출하여 객체를 생성한다.

 

 private int calc(int num1,int num2,String op) {
    	int res=0;
    	if(op.equals("+")) {
			res=num1+num2;
		}
		else if(op.equals("-")) {
			res=num1-num2;
		}
		else if(op.equals("x")) {
			res=num1*num2;
		}
		else if(op.equals("/")) {
			res=num1/num2;
		}
    	return res;
    }

계산(로직)을 담당하는 메서드.

 

int num1 = Integer.parseInt(request.getParameter("num1"));
		int num2 = Integer.parseInt(request.getParameter("num2"));
		String op = request.getParameter("op");
				
		int res=calc(num1,num2,op);

계산에 쓰일 변수 선언 및 메서드 호출

 

	PrintWriter out = response.getWriter();
		out.println("<!DOCTYPE html>");
		out.println("<html>");
		out.println("<head>");
		out.println("<meta charset=\"UTF-8\">");
		out.println("<title>계산기 예제 01 - 결과</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>계산결과</h1>");
		out.println("<hr>");
		out.println(res);
		out.println("</body>");
		out.println("</html>");

서블릿의 단점!

바로, 자바 코드 안에서 HTML 코드를 작성해야한다는 것이다.

자바 코드 안에서 HTML 코드를 사용하려면 내장객체인 out.println()을 계속 써야해서 코드가 길어지고 유지보수가 안좋다.


[ Servlet 예 2 + 자바 빈 ]

package calc;

import java.io.IOException;
import java.io.PrintWriter;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/calc2") // CalcServlet01 calcServlet01 = new CalcServlet01();
public class CalcServlet02 extends HttpServlet {
	private static final long serialVersionUID = 1L; // 직렬화

    public CalcServlet02() {
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("GET 요청을 받은 상태");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int num1 = Integer.parseInt(request.getParameter("num1"));
		int num2 = Integer.parseInt(request.getParameter("num2"));
		String op = request.getParameter("op");
				
		CalcBean cb=new CalcBean(num1,num2,op);
		int res=cb.getRes();
		
		PrintWriter out = response.getWriter();
		out.println("<!DOCTYPE html>");
		out.println("<html>");
		out.println("<head>");
		out.println("<meta charset=\"UTF-8\">");
		out.println("<title>계산기 예제 01 - 결과</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>계산결과</h1>");
		out.println("<hr>");
		out.println(res);
		out.println("</body>");
		out.println("</html>");
	}
	
}

위랑 달라진 것은 

	CalcBean cb=new CalcBean(num1,num2,op);
		int res=cb.getRes();

여기뿐이다. 


+) 자바 빈 추가

package calc;

public class CalcBean {
	private int res;
	
	public CalcBean(int num1,int num2,String op) {
		System.out.println("로그 : CalcBean 생성됨");
		if(op.equals("+")) {
			this.res=num1+num2;
		}
		else if(op.equals("-")) {
			this.res=num1-num2;
		}
		else if(op.equals("x")) {
			this.res=num1*num2;
		}
		else if(op.equals("/")) {
			this.res=num1/num2;
		}
	}

	public int getRes() {
		return res;
	}
	public void setRes(int res) {
		this.res = res;
	}
}

자바 빈은 데이터를 저장하고 관리하는 객체이다.

서블릿이나 JSP에서 연산 로직을 분리하기 위한 "비즈니스 로직 클래스"!

로직을 Bean에 따로 저장함으로써 메인 서블릿의 코드를 줄이고 가독성을 높인다. 

기본 생성자가 없고, private 필드를 가지며, GETTER/SETTER 메서드를 가진다는 것이 특징이다.


[ JSP 예  1 ]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>계산기 예제 02</title>
</head>
<body>

<%
	int res=0;

	if(request.getMethod().equals("POST")){
		int num1=Integer.parseInt(request.getParameter("num1"));
		int num2=Integer.parseInt(request.getParameter("num2"));
		String op=request.getParameter("op");
		if(op.equals("+")){
			res=num1+num2;
		}
		else if(op.equals("-")){
			res=num1-num2;
		}
	}
%>

<form method="POST">
	<input type="text" name="num1"> 
    <select name="op">
    	<option>+</option>
        <option>-</option>
    </select> 
    <input type="text" name="num2"> <br>
	<input type="submit" value="계산">
</form>

<hr>

계산결과 : <%= res %>

</body>
</html>

다음은 JSP 코드로, HTML 코드 안에 JAVA 코드를 원하는 곳에만 넣을 수 있어 훨씬 개발이 쉽고 가독성이 좋다.

이 코드도 아직 자바 빈은 들어가지 않은 상태라 로직이 함께 있다.

 

<form method="POST">
	<input type="text" name="num1"> 
    <select name="op">
    	<option>+</option>
        <option>-</option>
    </select> 
    <input type="text" name="num2"> <br>
	<input type="submit" value="계산">
</form>

사용자의 입력을 받을 HTML 폼.

POST로 요청을 보내며, num1과 연산자, num2를 받아온다.

그리고 사용자가 submit을 누르면 브라우저가 POST로 JSP에게 요청을 보낸다.

 

<%
	int res=0;

	if(request.getMethod().equals("POST")){
		int num1=Integer.parseInt(request.getParameter("num1"));
		int num2=Integer.parseInt(request.getParameter("num2"));
		String op=request.getParameter("op");
		if(op.equals("+")){
			res=num1+num2;
		}
		else if(op.equals("-")){
			res=num1-num2;
		}
	}
%>

<% %> 사이에 있는 코드들이 자바 코드.

만약 클라이언트의 요청이 POST라면,

form에서 입력된 정보들을 가져와 정수로 변환한다.

정수로 변환하는 이유는 웹의 모든 정보는 값이 문자열로 들어오기 때문에.

정수 변환 후 연산을 수행하고 그 값을 저장.

 

계산결과 : <%= res %>

연산 수행 후 표현식을 통해 저장된 결과를 반환해준다.


[ JSP 예  2 + 자바빈 ]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:useBean class="calc.CalcBean02" id="cb" />
<%-- CalcBean02 cb = new CalcBean02(); --%>
<jsp:setProperty property="*" name="cb" />
<%-- cb.setXxx() --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>계산기 예제 03</title>
</head>
<body>

<%
	cb.calc();
%>

<form method="POST">
	<input type="text" name="num1"> 
    	<select name="op">
        	<option>+</option>
            <option>-</option>
        </select> 
    <input type="text" name="num2"> <br>
	<input type="submit" value="계산">
</form>

<hr>

계산결과 : <jsp:getProperty property="res" name="cb" />
<%-- cb.getRes() --%>

</body>
</html>

 

확실히 자바 빈을 사용하니 코드가 간결해졌다.

<form method="POST">
	<input type="text" name="num1"> 
    	<select name="op">
        	<option>+</option>
            <option>-</option>
        </select> 
    <input type="text" name="num2"> <br>
	<input type="submit" value="계산">
</form>

 

이건 사용자에게 정보를 받아올 HTML 폼. POST로 요청하고 있다.

<%
	cb.calc();
%>

자바 코드를 보면 얘 하나뿐인데 이건 자바빈의 메서드를 호출하는 코드이다.

 

<jsp:useBean class="calc.CalcBean02" id="cb" />
<%-- CalcBean02 cb = new CalcBean02(); --%>
<jsp:setProperty property="*" name="cb" />
<%-- cb.setXxx() --%>

앞과 달리 new 연산자를 사용하지 않고 자바 빈을 가져올 수 있었던 건 해당 코드 덕분이다.


<jsp:useBean class="calc.CalcBean02" id="cb" />

1. useBean : 자바 빈 객체 생성

  •  JSP에서 Java 객체를 생성하고 관리하는 방식
  • class="calc.CalcBean02" → calc 패키지에 있는 CalcBean02 객체를 생성
  • id="cb" → 생성된 객체를 cb라는 이름으로 JSP에서 사용 가능.
  • CalcBean02 cb = new CalcBean02();와 동일한 동작 수행
<jsp:setProperty property="*" name="cb" />

2. setProperty : HTML 폼에서 입력 받은 값을 Bean의 변수에 자동으로 설정

 

계산결과 : <jsp:getProperty property="res" name="cb" />
<%-- cb.getRes() --%>

3. getProperty: 계산된 결과를 가져와서 출력

  • property="*" → HTML 폼의 name과 일치하는 Bean의 변수에 값을 자동 설정
  • name="cb" → 이전에 생성한 cb(CalcBean02) 객체에 값을 설정
  • cb.setNum1(request.getParameter("num1"));
  • cb.setOp(request.getParameter("op")); 
  • cb.setNum2(request.getParameter("num2")); 와 동일한 동작 수행
  • property="res" → cb.getRes() 값을 가져와서 출력

 

아래는 자바 빈 코드다. 자바 파일에 따로 로직을 분리한 모습을 볼 수 있다.

package calc;

public class CalcBean02 {
	private int num1;
	private int num2;
	private String op;
	private int res;
	
	
	
	public void calc() {
		if(this.op == null) {
			return;
		}
		if(this.op.equals("+")) { // op가 null이라 nullpointer~ 뜸
			this.res=this.num1+this.num2; 
		}
	} // 굳이 따지자면 M 파트?
	// 로직을 JSP가 아닌 자바 파일에 작성
	
	
	public int getNum1() {
		return num1;
	}
	public void setNum1(int num1) {
		this.num1 = num1;
	}
	public int getNum2() {
		return num2;
	}
	public void setNum2(int num2) {
		this.num2 = num2;
	}
	public String getOp() {
		return op;
	}
	public void setOp(String op) {
		this.op = op;
	}
	public int getRes() {
		return res;
	}
	public void setRes(int res) {
		this.res = res;
	}
	

}

 

나중에 스프링 가면 @Bean이란 애가 있던데 자바 빈이랑 얘랑은 또 무슨 차이일지 궁금하다.

'IT > Backend' 카테고리의 다른 글

예제 (JSP)  (0) 2025.03.03
Session + Application으로 회원가입, 로그인 구현하기  (0) 2025.02.23