본문 바로가기
PM으로 성장하기/개발 공부

[컴과] JSP 프로그래밍: 개요, 동작원리, 구성요소, 쿠키, 세션, 자바빈, 데이터베이스 연결, DAO/DTO

by 고양이 고씨 2022. 11. 3.

웹의 구성 요소

웹은 위 그림과 같이 네 가지 요소로 구성된다.

1. 웹 브라우저(클라이언트)는 서버에 요청을 보내고 응답 결과를 출력한다.
2. 웹 서버는 클라이언트의 요청을 처리하고 결과를 전달한다. 클라이언트가 요청한 웹 문서를 찾아서 전달하는 역할 외에도 인증 처리, 문제가 있으면 정해진 코드로 응답 등도 수행한다.
3. 웹 애플리케이션 서버(WAS)는 서버의 성능 개선을 위해 웹서버의 기능을 분리한 것으로, 동적 페이지를 만들거나 비즈니스 로직(결과 만들기)을 처리한다. (엄밀히는 비즈니스 로직을 처리하는 것이 웹 컨테이너이며, 웹 컨테이너에 보안처리, 장애처리 등이 추가되면 웹 애플리케이션이라고 한다)
4. 데이터베이스는 웹 서비스 수행에 필요한 데이터를 저장하고 제공한다.

 

Apache Tomcat은 무료로 다운로드 가능하며, 설치 후 startup shutdown 프로그램을 작동하면 키고 끌 수 있다. 이클립스라는 IDE(통합개발환경, 우리가 프로그래밍을 쉽게 할 수 있도록 도와주는 소프트웨어)에서 서버 연결이 가능하다.

톰캣 연결이 잘 되었을 때 localhost:8080를 주소창에 입력하면 위와 같은 화면이 뜬다
이클립스와 연결


JSP 개요 및 동작 원리

JSP을 알기 전에 서블릿이라는 개념을 알아야 한다. 서블릿이란 서버에서 동작하는 자바 프로그램으로, 웹 페이지를 동적으로 생성한다. 동적으로 생성한다는 것은 결과가 매번 변한다는 뜻이다.


JSP는 서버 측 스크립트 언어(참고: 스크립트 언어란 무엇인가?)로서, Java 언어의 특성을 활용하여 HTML 페이지 내에 삽입된다. 웹 컨테이너는 JSP(.jsp)를 서블릿 자바 프로그램(.java)으로 변환하고, 컴파일하여 서블릿 클래스 파일(.class)을 생성한다. .jsp는 우리가 이클립스로 코드를 입력하여 만드는 파일이다. 또한 컴파일이란 사람이 작성한 언어를 컴퓨터가 이해할 수 있는 언어로 변환한 것이다.

이렇게 변환된 서블릿 클래스는 생성자, doGet, doPost를 갖고 있다.

 

더 나아가기 앞서 생성자, doGet, doPost의 개념을 짚고 넘어가려고 한다. Java는 클래스, 속성, 메소드라는 개념을 사용한다. 속성은 클래스의 특징을, 메소드는 클래스의 기능을 의미하며, 클래스는 속성과 기능을 설명한 설계도라고 할 수 있다. 아래 예시를 보면 Radio라는 클래스는 volume이라는 속성을 가지고 있으며, volumeUp, volumeDown이라는 메소드를 통해 volume값을 증가시킬수도, 감소시킬 수도 있다.

class Radio {
    int volume;

    void volumeUp() { volume++; }
    void volumeDown() { volume--; }
  }

이러한 클래스를 복제하여 사용할 수 있는데, 이를 인스턴스라고 한다. 이 인스턴스가 생성될 때 클래스와 메소드 이름이 동일하다면 메소드가 호출되는데, 이를 초기화라고 하고 해당 메소드를 생성자라고 한다.

doGet 메소드는 서버가 get 요청(단순 질의와 검색)을 처리하기 위해 호출하는 메소드이다. doPost 메소드는 post 요청(많은 양의 데이터를 읽어들일 때)을 처리하기 위해 호출하는 메소드다. 내가 구분하기 쉬웠던 방식은 url 파라미터 여부이다. 예를 들면,
https://www.google.com/search?q=JSP → 파라미터로 요청메시지가 들어간다(GET 방식)
https://hyper-polaris.tistory.com/6 → 파라미터가 없다(POST 방식)


다시 돌아와서, 서블릿을 실행하면 웹 컨테이너는 class 파일을 메모리에 로드하며, 객체를 실행하고, 생성자가 실행되며, 초기화작업이 실행되고, doGet 혹은 doPost가 실행된다. 또한 웹 컨테이너는 동시에 요청정보를 서블릿에게 제공하기 위해 request 객체를 만들며, 서블릿이 상태코드, 응답헤더, 몸체를 표현할 수 있도록 response 객체를 만드는 역할도 수행한다.

 

자세한 설명에 앞서 HTTP 요청과 응답에 대해 알아보고자 한다. HTTP 프로토콜이란 웹 서버와 클라이언트가 통신하는 규약을 의미한다. 클라이언트는 웹서버에 요청 메시지(구성: 요청방식, URI, 버전번호, 요청 헤더, 요청 몸체)를 전송하고, 웹 서버는 응답 메시지(구성: 시작라인, 응답헤더, 응답 몸체)를 전달한다. F12를 눌러 개발자모드에 진입하고 network를 보면 이를 확인할 수 있다.

 

개발자모드 F12의 Network

 

request 객체는 클라이언트의 요청을 표현한다. 클라이언트와 서버 관련 정보를 읽고, 클라이언트가 전송한 데이터(파라미터)를 읽으며, 클라이언트가 전송한 헤더, 쿠키 정보를 읽고 속성을 처리한다. 예를 들면 request.getMethod()는 클라이언트가 데이터를 전송할 때 사용한 요청 방식을 리턴하고, request.getParameterMap()는 클라이언트가 전송한 파라미터를 <파라미터, 값> 형태로 리턴하는 메서드이다.
response 객체는 클라이언트의 응답을 제공하기 위한 것으로 응답 헤더 정보를 설정, 다른 페이지로 이동, 쿠키 추가, 상태코드 설정, 응답 몸체를 만들기 위한 객체를 제공한다. 예를 들면 response.setHeader()로 응답 헤더 정보 설정할 수 있고 response.addCookie()로 쿠키를 추가할 수 있다.


JSP의 구성 요소

1. 스크립트 요소
스크립트 요소란 동적인 콘텐츠를 만들기 위해 프로그램에 사용되는 요소들이다. 스크립트 요소 중 하나인 스크립트릿 <% … %> 은 JSP 페이지에 삽입되는 Java 코드의 조각을 말하며 <%@ page contentType="text/html; charset=UTF-8" %> 라는 형태로 표현된다. 표현식 <%= … %> 은 변수나 수식의 값을 출력할 경우 JSP페이지에 삽입하는 식이며, 선언 <%! … %> 은 JSP 코드에서 사용될 변수 또는 메서드 선언을 말한다.

2. 지시어
include 지시어는 소스코드나 텍스트를 삽입하는 것으로, JSP 페이지를 서블릿 프로그램으로 변환시키기 전에 삽입한다. 공통으로 사용되는 스크립트 요소를 포함할 때 사용한다. include 지시어는 JSP페이지의 특정 영역에 다른 문서를 포함할 텍스트나 코드를 지정할 때 사용하고, page 지시어는 JSP 페이지에 대한 정보를 지정할 때 사용한다. taglib 지시어는 JSP 페이지에 사용할 태그 라이브러리를 선언할 때 사용된다.

3. 액션태그
액션태그는 요청을 처리할 때 특별한 기능을 수행한다. <jsp:include> 액션 태그의 경우 include 지시어와는 다르게 동적 include로, JSP 페이지가 실행될 때 처리된다. 공통으로 사용되는 페이지들은 코드 중복을 피하기 위해, 별도 페이지를 만들고 <jsp:include> 액션태그를 사용한다. <jsp:param>태그는 요청이 전달될 때 파라미터를 추가할 수 있다. <jsp:forward>는 하나의 JSP 페이지에서 다른 페이지로 강제이동 시키는 것이다.

4. 내장객체
객체는 크게 사용자 정의 객체와 JSP 내장 객체가 있는데, JSP 내장 객체란 JSP 컨테이너가 자주 사용되는 기능을 객체 형태로 제공하는 것을 의미한다. 앞서 본 request와 response 외에, pageContext(JSP 페이지에 대한 정보), session(HTTP 세션 정보), application(웹 애플리케이션에 대한 정보), out(브라우저에 보낼 콘텐츠를 출력할 때 사용되는 출력 스트림), config(JSP 페이지 설정 정보) 등이 있다.

5. 표현 언어
데이터를 쉽게 다루기 위한 간단한 스크립트 언어로, ${수식} 과 같은 형태로 사용된다. 표현 언어는 JSP의 문법을 보완하는 역할을 수행한다. 표현언어는 수식에 사용되는 연산자를 제공하며, 자바 클래스의 static 메서드를 호출할 수 있다. 내장객체의 속성과 자바빈 객체를 쉽게 다룰 수 있는 특징이 있다. 예를 들어 표현언어의 내장객체로 param이 있는데, ${param.name}은 request.getParameter("name")의 결과와 동일하다. 또한 자바빈 객체에서는 ${자바빈객체.속성}의 형태로 값을 읽을 수도 있다.

6. JSTL(JSP Standard Tag Library)
유용한 사용자 정의 태그들을 모아 표준화한 태그 모음이다. 접두어를 사용하여 구분하는데, 예를들어 코어 태그 라이브러리는 접두어 c를 사용한다. 코어 태그 라이브러리를 사용하면 변수 값을 지정하거나, if문과 같은 흐름제어문을 구현할 수도 있다.

 


기본적으로 HTTP 프로토콜은 stateless한 특성을 갖고 있기 때문에, 서버가 응답을 보낸 후에는 클라이언트에 대해 알지 못한다. 따라서 상태 관리를 위해서는 쿠키와 세션이 필요하다.

 

쿠키

쿠키는 사용자를 식별하는 정보로 <이름, 값>을 갖는 작은 크기의 텍스트 데이터이다. 쿠키에 속성(유효시간, 도메인, 경로, 주석)을 추가할 수 있고, 브라우저는 이를 기억할 수 있다. 최초 요청 처리에서 웹 서버는 쿠키 클래스의 객체를 만들어 응답 헤더에 포함시키며, 브라우저는 쿠키를 저장하여 같은 서버에 다른 요청을 보낼 때 쿠키를 함께 넣어 보낸다. 이렇게 서버와 클라이언트는 상태를 공유하여 연이은 요청을 관련되게 처리할 수 있는 것이다.

예를 들어 쿠키를 통해 로그인을 구현하려면, 사용자가 아이디와 비밀번호를 입력했을 때 가입한 회원인지 판단하고 로그인 상태에서 사용할 쿠키를 생성할 수 있다. 이후 서버는 클라이언트가 보낸 쿠키를 가지고 로그인여부를 지속 판단할 수 있으며, 로그아웃을 하면 쿠키를 삭제할 수 있다

 

<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<html>
<%
	String id = request.getParameter("id");
	String pw = request.getParameter("pw");
	if(id.equals("admin") && pw.equals("pass")) {
		Cookie cookie = new Cookie("ID", "IAMCOOKIE");
		response.addCookie(cookie);
		out.print("<h3>로그인 성공</h3>");
	} else {
		out.print("<h3>로그인 실패</h3>");
	}
%>
<h3><a href="logincheck.jsp">로그인 확인</a></h3>
</body>

쿠키와 JESSIONID


세션

세션은 클라이언트가 특정 작업을 수행하는 기간을 의미한다. JSP에서 세션을 구현하는 일반적인 방법은 세션아이디(JESSIONID)를 쿠키로 사용하는 방법이 있다. 클라이언트가 최초로 요청할 때 웹 컨테이너는 session 객체를 만들고 세션 아이디를 부여한다. 최초 요청 응답에서 세션아이디를 쿠키로 포함시켜 웹브라우저에 전송하며, 이후 웹브라우저는 자신의 세션 아이디를 웹 컨테이너에 전송한다. 이를 통해 사용자 식별이 가능하다.


쿠키와 세션 비교

쿠키와 세션을 비교하면 아래와 같다.

구분 쿠키 세션
저장장소 클라이언트에 저장 서버에 저장
저장형태 텍스트파일 객체
보안 상대적으로 보안에 약하며, 클라이언트에서 쿠키를 허용하지 않는다면 사용할 수 없음 서버에 저장되어 상대적으로 보안에 유리하며, 클라이언트가 쿠키를 허용하지 않는다면 URL에 넣는 방법이 있음

자바빈

자바빈은 JSP 요소들과 맞물려 사용 가능한 사용자 정의의 자바 클래스를 의미한다. JSP 페이지에 사용할 데이터를 다루고 결과를 생성하는 비즈니스 로직 기능을 구현하는 데 목적이 있다. 자바빈은 모든 속성에 대해 getter 메서드와 setter 메서드를 정의해야 한다. getter 메서드는 속성 값을 읽으며, setter 메서드는 속성 값을 변경하는 데 사용된다. (아래 예시에서 getTitle, setTitle 이런 메서드를 의미한다)

 

JSP 페이지에서는 자바빈 액션태그를 사용한다. <jsp:useBean>는 자바빈 객체를 생성하거나 사용하겠다는 선언이다. <jsp:setProperty>는 자바빈 객체의 속성을 설정하며, <jsp:getProperty>는 자바빈 객체의 속성을 읽는 데 사용된다. 예시를 보는 것이 이해하기가 쉽다.

 

예를 들어 게시판에 글을 작성하고 확인할 수 있는 서비스를 만들고 싶다면, 네 가지의 파일을 만들어야 한다.

우선 java 파일을 생성하여 클래스를 정의한다. 이때 getter, setter 메서드를 입력해준다.

package helloJSP;

public class BoardData {
	private String title;
	private String writer;
	private String text;
	private String pass;

	public String getTitle(){ return title; }
	public void setTitle(String title){ this.title = title; }
	public String getWriter(){ return writer; }
	public void setWriter(String writer){ this.writer = writer; }
	public String getText(){ return text; }
	public void setText(String text){ this.text = text; }
	public String getPass(){ return pass; }
	public void setPass(String pass){ this.pass = pass; }

}

jsp 를 새로 생성하여 table을 사용하여 입력 폼을 만들어준다. 또한 확인 버튼을 눌렀을 때 write.jsp를 동작시키도록 세팅한다.

폼을 생성하여 입력하였다

앞서 wirte.jsp로 연결하도록 하였으므로, 액션태그를 사용하여 wirte.jsp를 작성 한다. usebean을 통해 앞서 정의한 BoardData 클래스를 이용할 것이라고 선언한다. 우리는 게시판의 글을 저장하는 것이므로 setProperty를 사용한다. 또한 확인버튼을 눌렀을 때 view.jsp 페이지로 넘어갈 수 있도록 forward 를 이용한다.

<%@ page contentType="text/html; charset=UTF-8"%>
<% request.setCharacterEncoding("UTF-8"); %>
<jsp:useBean id="boardData" class="helloJSP.BoardData" scope="request" />
<jsp:setProperty name="boardData" property="*" />
<jsp:forward page="view.jsp" />

 

view.jsp에 입력한 값을 보여주는 html 태그와 <jsp:getProperty> 로 객체 속성을 읽도록 한다.

 

입력한 데이터가 잘 등록되었다


데이터베이스

데이터베이스란 데이터를 모아 놓은 집합이다. 클라이언트가 JSP 페이지를 요청하면, 웹 컨테이너는 JSP페이지를 실행한다. JSP페이지는 DB에 접속하여 SQL을 실행하고, DBMS(데이터베이스 관리 시스템)는 SQL의 결과를 전송하여 클라이언트에게 응답 결과를 전송할 수 있다.

(자세한 내용은 여기를 참고)

 

나는 실습으로 MariaDB를 사용했다.

Maria DB
MariaDB를 통해 테이블 생성 및 데이터 삽입

 

MariaDB는 자바 커넥터를 지원하는데, 이를 사전에 다운로드 받아야 한다. 자바커넥터는 말 그대로 DB와 연결하기 위해 필요한 것으로, 보통은 DBMS 사에서 제공한다고 한다. 이를 다운로드 받아 Tomcat 설치폴더의 lib 폴더 안에 넣고, Properties-Java Bulid Path에 들어가서 등록해주면 된다. 또한 java.sql 패키지를 import 해주고, class.forName문을 통해 JDBC 드라이버를 로드한다. Connection 객체를 사용하여 MariaDB 서버에 접속할 url과 DBMS 아이디, 패스워드를 입력한다. 참고로 JDBC는 Java에서 데이터베이스에 접속할 수 있도록 도와주는 API이다.

Properties 설정을 안해서 계속 실패하다가 겨우 연결했다

이렇게 연결되었다면 ResultSet 객체를 사용하여 select 문을 실행하고, int executeUpdate를 통해 update, insert, delete 구문을 실행할 수 있다.

먼저 select 문부터 진행해보면 아래와 같다. 우선 Statement 객체를 통해 MariaDB 서버에서 실행시킬 SQL 구문을 저장하도록 한다. 이후 ResultSet을 통해 SQL구문(여기서는 select문)의 실행 결과를 저장한다. 이후 표로 나타내기 위해 while문으로 행마다 레코드를 삽입해준다.

 

추가로 수정, 삭제 버튼도 아래와 같이 확인할 수 있는데 id값을 파라미터로 하여, 정보를 수정, 삭제할 수 있도록 구성되어 있다. ?iid=%s로 하여 파라미터로 rs.getInt("id")값을 작성되어있다(아래 이미지에선 코드가 일부 잘렸다). 즉 %s 부분에 id값이 들어오는 것이다. 수정, 삭제 jsp 페이지에서 sql문 작성 시 where 조건을 걸어주면 된다.

select문을 실행해서 현재 등록된 데이터를 확인한다

그 다음 insert 문을 진행해보면 아래와 같다. 우선 insert를 진행할 form을 html로 만들어준다. 이후 확인 버튼을 누르면, jsp가 작동하여 값을 저장하도록 한다. jsp 문서에는 위와 마찬가지로 입력하되 select 문 대신에 insert문을 넣는다. (insert into member values(%s,'%s','%s','%s','%s')", id, pass, name, phone, address) 이후 form에 데이터를 입력하고 확인을 누르면 성공메시지를 확인할 수 있다.

신규 데이터 등록에 성공했다

 

이렇게 해서 결과적으로 Maria DB에서 select 문을 입력해보면 아래와 같이 확인할 수 있다.

기존 데이터에 추가된 데이터까지 확인할 수 있다

 


DAO, DTO

앞서 데이터베이스 예시를 보면, Maria DB 연결코드가 중복이 되었고, SQL구문도 일부 중복이 있으며 데이터베이스에 대한 정보가 노출되어 있다. DAO와 DTO를 이용하면 코드 중복을 최소화하고 SQL 구문을 숨길 수 있다. 또한 테이블의 스키마가 변경되어도 DAO 클래스만 변경하면 되기 때문에 효율적이다.

 

DAO(Data Access Object)란 데이터베이스에 연결하고 SQL문을 실행하는 기능의 클래스이다. DAO 클래스는 DB에 연결하고 SQL문을 실행하는 메서드로 구성한다. 아래 이미지에서는 selectAll 메서드를 확인할 수 있다. DTO(Data Tranfer Object)는 주고 받을 데이터를 저장할 때 사용되는 클래스이다. DTO 클래스에는 변수와 getter, setter를 만든다.

 

(좌) DTO, (우) DAO

 

다 만들었다면 기존 JSP 코드를 아래처럼 수정할 수 있다.  데이터베이스에 연결하는 부분과 select 문을 숨겼다.

(좌) 수정 전 (우) 수정 후


후기

학교에서 수강할 수 있는 프로그래밍 과목들 중에는 C, C++, JAVA, JSP가 있다. Java나 C 같은 언어들의 이름은 나름 익숙했다. 그런데 JSP 프로그래밍의 "JSP"는 난생 처음들어보는 단어였다. 하지만 JSP를 배우고 나니, 그동안 애매하게 알고 있거나 이해하지 못했던 부분들을 많이 해소할 수 있었다. 예를 들면 쿠키, 세션, DB 연동, 웹 컨테이너인 Tomcat 같은 부분이다.


특별히 Tomcat은 이전 회사에서 Tech PM님이 발행한 JIRA 티켓을 통해 처음 접했다. 그 때 찾아본 내용은 아래와 같다.

아파치 톰캣(Apache Tomcat)은 아파치 소프트웨어 재단에서 개발한 서블릿 컨테이너(또는 웹 컨테이너)만 있는 웹 애플리케이션 서버이다. 톰캣은 웹 서버와 연동하여 실행할 수 있는 자바 환경을 제공하여 자바서버 페이지(JSP)와 자바 서블릿이 실행할 수 있는 환경을 제공하고 있다. (출처: 위키백과)


한국어로 설명은 되어있지만 서블릿 컨테이너, 웹 컨테이너, 웹 애플리케이션 서버, 자바서버 페이지, 자바 서블릿 이라는 단어가 무엇인지 알 수 없었다. 하지만 이번 JSP 프로그래밍을 배우면서 저 문장이 무슨 말인지 비로소 알 수 있었다.

 

도움 받은 글

1. 방송통신대학교 강의록

2. 웹 애플리케이션의 이해, https://catsbi.oopy.io/defe6c4d-1d74-4a5e-8349-ff9077dda184

3. 웹 애플리케이션 아키텍처의 특징, https://velog.io/@y_dragonrise/Web-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EC%9D%98-%ED%8A%B9%EC%A7%95

4. 생활코딩, https://opentutorials.org/course/3930

5. [자바JAVA] 객체지향1 - 클래스와 객체 . Tv클래스로 알아보는 객체배열, 멤버호출방법, 객체주소변경, 향상된 for문, https://sso-feeling.tistory.com/75

6. 쿠키(Cookie)와 세션(Session)의 차이, https://dev-coco.tistory.com/61

7. JSP Servelt의 기초(13) DAO, DTO, https://rwd337.tistory.com/21

8. JSP - 표현언어(EL, Expression Launguage), https://shinny.tistory.com/75

9. java와 mariaDB연결하기 [JDBC Driver], https://januarysecurity.tistory.com/41

 

 

728x90

댓글