자바(JAVA)/JSP 웹 프로그래밍 공부 (성낙현의 JSP 자바 웹 프로그래밍 참고)

JAVA/JSP 39. 서블릿(Servlet) 작성 - JSP 없이 서블릿에서 바로 응답 출력하기, 한 번의 매핑으로 여러 가지 요청 처리하기, 서블릿 수명주기 메서드

개발학생 2025. 4. 30. 16:59
반응형

*JAVA/JSP 35번 글의 시점부터는 노트북이 고장나는 바람에.. 다른 분의 글과 이전에 올렸던 글들을 참고하여, 다른 데스크탑의 윈도우 환경에 환경설정을 다시 진행한 후 작성하였습니다. 환경설정 관련 글들은 아래를 참고해 주세요.

  • JDK11 설치 및 환경 변수(JAVA_HOME) 설정 - CLASSPATH는 추가하지 않음
 

자바(JAVA) 11 설치 및 환경설정 | 자바 11 환경 변수

자바로 코딩 공부를 하려면 개발 할 수 있는 환경을 만들어 주어야 한다. 그 순서를 먼저 작성하자면JAVA SE JDK 설치 -> JAVA 환경 변수 설정 -> IDE 설치 이렇게 볼 수 있겠다. 이 포스팅은 자바로 개

velog.io

  • 톰캣 설치, 이클립스 설치 - 이 글을 쓰는 시점에서는 Tomcat 8버전이 없어, Tomcat 9버전 설치
 

JSP) JDK, 이클립스(eclipse), 톰캣 설치 및 환경 설정

1. JDK 설치 → Path 설정 2.eclipse JAVA EE버전 다운로드 3.웹컨테이너 톰캣 설치 →톰캣 환경설정 1. JDK 설치 - JAVA) 1. JDK 참고하여 설치하고 설정한다. -https://storyblogger.tistory.com/15?category=984696 2. 구글에

storyblogger.tistory.com

  • 이클립스 JDK 버전 설정 - JDK11로 설정
 

[이클립스] JDK 버전 바꾸는 법

스프링을 사용하는 에러가 난다? 그러면 JRE 버전을 확인해보자! 프로젝트의 JRE System Library의 오른쪽을 살펴보면 [JavaSE-17]이라고 되어있다. 스프링이나 하이버네이트를 사용할 때, 자바 8이나 자

myvelop.tistory.com

  • JDK 설치 및 환경 변수(JAVA_HOME) 설정, 톰캣 설치, 이클립스 설치 및 JDK 버전 설정 이후~ ⇒ 톰캣 버전과 jsp 파일 경로는 글 내용과 다르게 아래 이미지와 같음

 

JAVA/JSP 1. 개발 환경 구축 - 이클립스 기본 설정

*JDK 설치 및 환경 변수(JAVA_HOME) 설정, 톰캣 설치, 이클립스 설치를 완료한 상태OpenJDK 11: 자바 프로그램을 컴파일하고 실행해주는 기본 도구*이클립스 JDK-17이 설치되어있어서, https://coding-house.tisto

keep-programming-study.tistory.com

 

 

JAVA/JSP 1. 개발 환경 구축 - JSP 예제 테스트

1. 프로젝트 생성1) [File] → [New] → [Dynamic Web Project] 선택 2) 프로젝트 설정 화면 → Project name: HelloJSP, Target runtime: Apache Tomcat v9.0, Dynamic web module version: 4.0으로 설정 후 Next 클릭 3) 자바 소스 파일

keep-programming-study.tistory.com

 

 

JAVA/JSP 1. 개발 환경 구축 - 마지막 추가 설정

1. 외부 웹 브라우저로 실행하기-크롬이클립스는 웹 애플리케이션 실행 시, 자체 브라우저를 통해 실행 결과 출력웹 애플리케이션 배포 시 사용자는 크롬/파이어폭스 같은 전용 웹 브라우저로

keep-programming-study.tistory.com

  • 오라클(Oracle Database 11gR2 Express Edition) 설치 및 설정 
 

JAVA/JSP 14. 데이터베이스 - 특징, 오라클 설치(Oracle Database 11gR2 Express Edition), 사용자 계정 생성 및

1. 데이터베이스의 특징우리가 매일 PC나 스마트폰을 통해 접하는 거의 모든 웹 애플리케이션에서 사용함매일 업데이트되는 뉴스나 날씨 등의 정보는 데이터베이스가 없다면 클라이언트에 전달

keep-programming-study.tistory.com

 

 

 

JAVA/JSP 15. 데이터베이스 - 테이블 및 시퀀스 생성, JDBC 설정 및 데이터베이스 연결

*회원제 게시판 만들기-회원 인증 필요4. 테이블 및 시퀀스 생성1) 테이블 생성(1) member 테이블 - 아이디, 패스워드, 이름, 가입 날짜테이블 정의컬럼명데이터 타입 null 허용 키 기본값 설명idvarchar2

keep-programming-study.tistory.com

 

JAVA/JSP 16. 데이터베이스 - 커넥션 풀로 성능 개선, 간단한 쿼리 작성 및 실행

6. 커넥션 풀로 성능 개선웹은 클라이언트의 요청에 서버가 응답하는 구조→ Connection 객체 생성 때마다 네트워크 통신이 이뤄지며, 시간이 걸리는 작업들이 수반됨 == 시스템 성능에 큰 영향을

keep-programming-study.tistory.com

  • 시퀀스 설정
 

JAVA/JSP 15. 데이터베이스 - 테이블 및 시퀀스 생성, JDBC 설정 및 데이터베이스 연결

*회원제 게시판 만들기-회원 인증 필요4. 테이블 및 시퀀스 생성1) 테이블 생성(1) member 테이블 - 아이디, 패스워드, 이름, 가입 날짜테이블 정의컬럼명데이터 타입 null 허용 키 기본값 설명idvarchar2

keep-programming-study.tistory.com

 

1. JSP 없이 서블릿에서 바로 응답 출력하기

  • 요청 방식을 get 대신에 post를 사용
  • 순수 데이터만 출력해야 하는 경우에만 사용 

예제

  • jsp 파일
// src/main/webapp/DirectServletPrint.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DirectServletPrint.jsp</title>
</head>
<body>
  <h2>web.xml에서 매핑 후 Servlet에서 직접 출력하기</h2>
  <!-- post 방식으로 전송하기 위해 form 태그를 사용(요청명은 action 속성에 지정) -->
  <form method="post" action="./DirectServletPrint.do">
    <input type="submit" value="바로가기" />
  </form>
</body>
</html>
  • web.xml에 요청명과 서블릿 매핑
<!-- src/main/webapp/WEB-INF/web.xml -->

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  ... 생략 ...
  <servlet> <!-- 서블릿 등록 -->
    <servlet-name>DirectServletPrint</servlet-name>  <!-- 1. 서블릿 매핑을 위한 서블릿명 -->
    <servlet-class>servlet.DirectServletPrint</servlet-class>  <!-- 2. 요청을 처리할 서블릿을 패키지를 포함하여 명시 -->
  </servlet>
  <servlet-mapping>  <!-- 서블릿과 요청명 매핑 -->
    <servlet-name>DirectServletPrint</servlet-name>  <!-- 3. 1과 동일한 서블릿명 -->
    <url-pattern>/DirectServletPrint.do</url-pattern>  <!-- 4. 컨텍스트 루트를 제외한 요청명 작성 -->
  </servlet-mapping>
</web-app>

 

  • servlet 패키지에 DirectServletPrint 클래스(서블릿) 생성
// Java Resources/src/servlet/DirectServletPrint.java

package servlet;

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

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DirectServletPrint extends HttpServlet {
  @Override
  // 1. post 방식의 요청이므로 doPost() 메소드를 오버라이딩
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    // 2. 클라이언트에 응답하기 위해 response 내장 객체에 응답 콘텐츠 타입 지정
    resp.setContentType("text/html;charset=UTF-8");
    // 3. 웹 브라우저에 전송할 응답 결과를 쓰기 위해, response 내장 객체에서 PrintWriter 객체 얻어옴
    PrintWriter writer = resp.getWriter();
		
    // 4. PrintWriter의 println() 메서드로 응답 내용 출력
    writer.println("<html>");
    writer.println("<head><title>DirectServletPrint</title><head>");
    writer.println("<body>");
    writer.println("<h2>서블릿에서 직접 출력</h2>");
    writer.println("<p>jsp로 포워드하지 않음</p>");
    writer.println("</body>");
    writer.println("</html>");
		
    // 5. PrintWriter 객체를 닫아줌
    writer.close();
  }
}

Direct ServletPrint.jsp 실행 

  • 첫 화면에서 [바로가기] 버튼 클릭 시, 서블릿이 실행되며 화면이 아래 이미지처럼 변함

 

2. 한 번의 매핑으로 여러 가지 요청 처리하기

  • 요청명이 추가되면 그에 따른 매핑도 함께 추가해야 한다는 불편함을 개선

예제

  • JSP 파일
// src/main/webapp/onemapping/FrontController.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>FrontController.jsp</title>
</head>
<body>
  <h3>한 번의 매핑으로 여러 가지 요청 처리하기</h3>
  <!-- 1. 서블릿이 request 영역에 저장할 결괏값 -->
  ${ requestValue }
  <ol>
    <!-- 2. 클라이언트가 요청한 전체 경로 표시 -->
    <li>URI: ${ uri }</li>
    <!-- 3. 전체 경로에서 마지막의 xxx.one 부분을 추출할 문자열 -->
    <li>요청명: ${ commandStr }</li>
  </ol>
  <ul>
    <!-- 4. 각 페이지로의 바로가기 링크 -->
    <li><a href="../onemapping/regist.one">회원가입</a></li>
    <li><a href="../onemapping/login.one">로그인</a></li>
    <li><a href="../onemapping/freeboard.one">자유게시판</a></li>
  </ul>
</body>
</html>

 

  • servlet 패키지에 FrontController 클래스(서블릿) 생성
// Java Resources/src/servlet/FrontController.java

package servlet;

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;

// 1. 와일드카드(*)를 사용하여 URL 패턴이 *.one에 해당하는 요청을 모두 이 서블릿과 매핑
@WebServlet("*.one")
public class FrontContoller extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
    // 2. request 내장 객체로부터 현재 경로에서 호스트명을 제외한 나머지 부분을 알아냄
    String uri = req.getRequestURI();
    // 3. 마지막 슬래시(/)의 인덱스를 구함
    int lastSlash = uri.lastIndexOf("/");
    // 4. 3에서 구한 인덱스로 경로 마지막 부분의 문자열을 얻어옴
    String commandStr = uri.substring(lastSlash);
		
    // 5. 4의 문자열로 페이지를 구분하며, 각 페이지를 처리할 수 있는 메서드 호출
    if (commandStr.equals("/regist.one"))
      registFunc(req);
    else if (commandStr.equals("/login.one"))
      loginFunc(req);
    else if (commandStr.equals("/freeboard.one")) 
      freeboardFunc(req);
		
    // 6. uri와 페이지 구분을 위한 문자열(commandStr)을 request 영역에 저장
    req.setAttribute("uri", uri);
    req.setAttribute("commandStr", commandStr);
    // 7. FrontController.jsp로 포워드
    req.getRequestDispatcher("/onemapping/FrontController.jsp").forward(req, resp);
  }
	
  // 8. 페이지별 처리 메서드 - 각 페이지에 출력할 데이터를 request 영역에 저장
  void registFunc(HttpServletRequest req) {
    req.setAttribute("resultValue", "<h4>회원가입</h4>");
  }
	
  void loginFunc(HttpServletRequest req) {
    req.setAttribute("resultValue", "<h4>로그인</h4>");
  }
	
  void freeboardFunc(HttpServletRequest req) {
    req.setAttribute("resultValue", "<h4>자유게시판</h4>");
  }
}

FrontController.jsp 실행

  • [회원가입] 링크 클릭

  • [로그인] 링크 클릭

  • [자유게시판] 링크 클릭

3. 서블릿 수명주기 메서드

서블릿의 수명주기

  • 서블릿 컨테이너가 담당: 클라이언트의 요청이 들어오면 서블릿에서 서블릿 객체를 생성하고 초기화한 후 요청 처리
    -> 서블릿 객체 생성 후 각 단계마다 자동으로 특정 메서드를 호출하여 해당 단계에 필요한 기능 수행
    => 서버 종료 시 서블릿 객체 소멸
  • 서블릿 수명주기 메서드: 서블릿 컨테이너가 호출하는 콜백 메서드들

 

@PostConstruct 객체 생성 직후 init( ) 메서드를 호출하기 전에 호출
어노테이션을 사용하므로, 메서드명은 개발자가 설정
init( )  서블릿의 초기화 작업을 수행하기 위해 호출
최초 요청 시 딱 한 번 호출
service( ) 클라이언트의 요청을 처리하기 위해 호출
전송 방식에 따라 doGet( ), doPost( ) 사용
destroy( ) 서블릿이 새롭게 컴파일되거나, 서버가 종료될 때 호출
@PreDestroy destroy( ) 메서드 실행 후, 컨테이너가 서블릿 객체를 제거하는 과정에 호출
어노테이션을 사용하므로,  메서드명은 개발자가 설정

서블릿 수명주기 메서드 동작 확인 예제

  • JSP 파일
// src/main/webapp/cycle/LifeCycle.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LifeCycle.jsp</title>
</head>
<body>
  <script>
    // 1. 폼값 전송 자바스크립트 함수: form 태그의 DOM 객체와 전송 방식을 인수로 받음
    function requestAction(frm, met) {
      // 2. 두번째 인수를 보고 전송 방식 결정
      if (met == 1) {
        frm.method = 'get';
      } else {
        frm.method = 'post';
      }
      // 3. 폼값 전송
      frm.submit();
    }
  </script>
	
  <h2>서블릿 수명주기(Life Cycle) 메서드</h2>
  <!-- 4. form 태그 정의: action 속성을 제외한 나머지는 클릭 시 자바스크립트에서 설정 -->
  <form action="./LifeCycle.do">
    <input type="button" value="Get 방식 요청하기" onclick="requestAction(this.form, 1)" />
    <input type="button" value="Post 방식 요청하기" onclick="requestAction(this.form, 2)" />
  </form>
</body>
</html>
  • 서블릿 클래스 작성(어노테이션 활용)
// Java Resources/src/servlet/LifeCycle.java

package servlet;

import java.io.IOException;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
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("/cycle/LifeCycle.do")
public class LifeCycle extends HttpServlet {
	
  @PostConstruct
  public void myPostConstruct() {
    System.out.println("myPostConstruct() 호출");
  }
	
  @Override
  public void init() throws ServletException {
    System.out.println("init() 호출");
  }
	
  @Override
  public void service(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
    System.out.println("service() 호출");
		
    // 전송 방식을 확인해 doGet() 또는 doPost() 호출
    super.service(req, resp);
  }
	
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
    System.out.println("doGet() 호출");
    req.getRequestDispatcher("/cycle/LifeCycle.jsp").forward(req, resp);
  }
	
  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
    System.out.println("doPost() 호출");
    req.getRequestDispatcher("/cycle/LifeCycle.jsp").forward(req, resp);
  }
	
  @Override
  public void destroy() {
    System.out.println("destroy() 호출");
  }
	
  @PreDestroy
  public void myPreDestroy() {
    System.out.println("myPreDestroy() 호출");
  }
}

LifeCycle.jsp 실행

  • 첫 화면

  • [Get 방식 요청하기] 클릭 시 이클립스의 console 뷰

  • [Post 방식 요청하기] 클릭 시 이클립스의 console 뷰

  • 톰캣 서버 종료 시 시 이클립스의 console 뷰

반응형