서블릿은 Java로 웹 요청(HTTP)을 처리하는 API.
원래 자바는 웹 개발과는 거리가 멀었다 (HTTP 요청/응답이 불편)
그때, 서블릿이라는 API가 등장하면서 자바로도 웹 개발을 할 수 있게 되었다. (HTTP 요청이 편해짐)
서블릿은 웹 서버에서 동작하며, HTTP 요청을 받아 처리하고, 클라이언트(웹 브라우저)로 응답을 보내는 역할을 한다.
서블릿에서 진화한 JSP가 등장했고, 그 이후에 Spring이 등장했다.
(서블릿보다 jsp가 편하고 jsp는 서블릿으로 자동 변환된다. 확장자는 .java)
서블릿의 HTTP 요청/응답 과정
- 클라이언트(웹 브라우저)가 요청을 보내면,
- 웹 서버(Tomcat)가 요청을 서블릿으로 전달하고,
- 서블릿이 그 요청을 처리한 후,
- 서블릿이 응답을 생성해서 응답을 보내고,
- 웹 브라우저가 응답을 받아 화면에 표시한다.
@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 요청/응답 과정
- 클라이언트가 index.jsp 요청
- JSP 파일이 서블릿(Java 코드)로 변환됨
- 서블릿이 컴파일되고 실행됨
- 서블릿이 HTML을 생성하여 클라이언트에게 응답
- 웹 브라우저가 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 |