Intro
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
음, page directive를 이용하면 자바 코드를 JSP에서 작성할 수 있다고 합니다. 관련된 속성은 아래에 표를 첨부해 두었습니다. import 속성을 제외한 나머지 속성은 1회씩만 사용 가능합니다.
| 속성명 | 설명 | 초기값 |
| language | 사용할 프로그래밍 언어 | java |
| contentType | 생성할 문서의 콘텐츠 유형 | text / html |
| pageEncoding | 페이지에 대한 인코딩 설정 | EUC-KR / ISO-8859-1 |
| import | 사용할 자바 클래스 추가 | |
| session | 세션 사용 여부 | true |
| info | 페이지에 대한 설명 작성(주석처럼 이용) | |
| errorPage | 예외 발생시 이동할 페이지 설정 | |
| isErrorPage | 오류페이지로 설정할 것인지에 대한 여부 | false |
일단, 이번 포스트에서는 에러 페이지 포워딩부터 해보면 좋겠습니다. 나머지는 의식의 흐름대로 진행할게요.
<%@ page import="java.util.*" %>
자바 코드야 이런 식으로 import 해서 쓰면 되니까 금방 익힐 수 있을 것 같아요.
jsp → .java → .class 형태로 JSP를 서블릿으로 변환해서 서블릿 컨테이너에 넣어놓고 사용하는 형태라고 생각하면 되겠습니다.
흔히 Web Application Server(WAS)로 사용하는 Tomcat 역시 Servlet Container의 일종이에요.
서블릿의 Lifecycle이 어떤지 궁금하다면, 하단에 첨부한 이미지를 참고합시다.

아, 추가로 JSP에는 implicit object(내장 객체)를 가지고 있는데 한번 짚고 넘어가면 좋겠습니다. JSP 내에서 선언하지 않고 사용할 수 있는 객체입니다.
| 내장 객체 | 반환 값 | 설명 |
| request | javax.servlet.http. httpServletRequest |
웹 브라우저의 요청 정보 저장 |
| response | javax.servlet.http. httpServletResponse |
웹 브라우저의 요청에 대한 응답 정보 저장 |
| out | javax.servlet.jsp.JspWriter | JSP 페이지에 출력할 내용을 가지고 있는 출력 스트림 |
| session | javax.servlet.http.HttpSession | 웹 브라우저 내에서 정보를 유지하기 위한 세션 정보 저장 |
| application | javax.servlet.ServletContext | 웹 애플리케이션 Context의 정보 저장 |
| pageContext | javax.servlet.jsp.PageContext | JSP 페이지에 대한 정보 저장 |
| page | java.lang.Object | JSP 페이지를 구현한 자바 클래스의 인스턴스 |
| config | javax.servlet.ServletConfig | JSP 페이지에 대한 설정 정보 저장 |
| exception | java.lang.Throwable | 예외가 발생한 경우 사용 |
본론
Error Page Test (page directive)
먼저, 에러가 발생했을 때 에러 페이지로 포워딩하는 코드를 작성하도록 합시다.
WEB-INF/views/errorPageTest.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isErrorPage="true"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Error!</title>
</head>
<body>
<h2>Error!</h2>
<p>
Error Name : <%= exception.getClass().getName() %> <br/>
Error Msg : <%= exception.getMessage() %>
</p>
</body>
</html>
jspTest.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" errorPage="/WEB-INF/views/errorPageTest.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSP TEST PAGE</title>
</head>
<body>
<%
int tmp = Integer.parseInt(request.getParameter("number"));
%>
</body>
</html>
결과

이런, null은 parsing 할 수 없습니다.
그리고 상단 주소창을 보면 주소가 그대로인데, 페이지 전환 없이 에러 페이지로 포워딩하는 데 성공한 것입니다.
Header Footer Test (include directive)
이번에는 JSP 페이지의 특정 영역에 외부 파일의 내용을 삽입하는 include directive를 사용해 봅시다.
header.jsp
<h2 style="background: black; color: white;">Header Area</h2>
footer.jsp
<h2 style="background:olive; color: white;">Footer Area</h2>
<hr>
<p>
Copyright ©madirony
</p>
jspTest.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" errorPage="/WEB-INF/views/errorPageTest.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSP TEST PAGE</title>
</head>
<body>
<%@ include file="./header.jsp" %>
<h4>Body Area</h4>
<p>
Contents <br/>
Contents <br/>
Contents <br/>
</p>
<%@ include file="./footer.jsp" %>
</body>
</html>
참고로 header와 footer에는 필요한 페이지에서 include 해서 사용하기 때문에 필요한 부분만 작성하면 됩니다.


웹 브라우저에서 생성된 소스코드를 보면 정상적으로 include한 파일들이 삽입되어 있는 것을 볼 수 있습니다.
Script Elements : Declaration, Scriptlet, Expression
JSP의 스크립트 요소에는 총 3가지가 있습니다. 선언부, 스크립틀릿, 표현식이 있죠.
1) Declaration <%! ... %>
선언부의 경우에는 생성된 서블릿의 클래스 영역에 위치하게 됩니다. (필드/메서드 자리)
헬퍼 메서드 선언 정도로만 활용된다는데, private 메서드를 써도 되지 않을까라는 생각.
<%!
private String printTest(String str1, String str2){
return str1+str2;
}
%>

2) Scriptlet <% ... %>
스크립틀릿과 같은 경우는 서블릿의 _jspService() 메서드 내부에 위치하게 됩니다. (요청 처리 로직 자리)
선언부에서 정의한 메서드를 활용할 수는 있으나, 다른 메서드를 선언할 수는 없습니다.
<% String res = printTest("Hello", "Irony"); %>
하지만 로직은 서블릿/컨트롤러, 화면은 JSP로 분리하는 게 권장됩니다.

3) Expression <%= ... %>
마지막으로 표현식. 변수의 값을 출력하기 위해 사용되고, out.print 형태로 컴파일되어 응답 본문에 바로 출력합니다.
<%= res %>

EL + JSTL

선언부, 스크립틀릿, 표현식은 각각 스레드 안전 이슈라던가, 뷰와 로직이 섞인 형태라던가, XSS의 위험이 존재합니다.
이를 해결하기 위해 컨트롤러/서비스/DAO에 로직을 두고, JSP는 EL과 JSTL만으로 표현하는 것이 일반적입니다.
목록 출력을 예시로 들어볼까요?
<ul>
<% for (Ticket t : (List<Ticket>)request.getAttribute("tickets")) { %>
<li><%= t.getTitle() %></li>
<% } %>
</ul>
스크립틀릿으로 목록을 출력한 예시입니다.
만약에 t라는 객체의 title이라는 변수에 악의적인 스크립트 코드가 String 형태로 저장되어 있고, 서버에서 렌더링 된 HTML 파일을 클라이언트가 받게 된다면 XSS 공격을 할 수도 있겠죠.
<ul>
<c:forEach var="t" items="${tickets}">
<li><c:out value="${t.title}"/></li>
</c:forEach>
</ul>
EL과 JSTL을 복합적으로 사용한 예시입니다. JSTL은 로직을 태그로, EL은 값 읽기와 간단한 연산을 수행할 수 있습니다.
EL ${...}은 스코프에 담긴 값(page/request/session/application)이나 파라미터/쿠키/헤더 등을 간결하게 읽어와 출력.
JSTL은 자바 코드를 섞는 대신 태그로 뷰 로직을 표현하게 해주는 표준 태그 라이브러리.

그전에 먼저 Maven Project로 전환해 보도록 합시다. Maven은 흔히 Spring을 다룰 때 사용하던 Gradle과 마찬가지로 빌드 관리 도구입니다. 정해진 Lifecycle에 의해 작업을 수행하고, 전반적인 프로젝트 관리 기능을 포함하고 있습니다.
프로젝트의 설정이라던가 의존성 같은 것들은 pom.xml(Project Object Model)에 정의합니다.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>JSP_Board_Practice</groupId>
<artifactId>JSP_Board_Practice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
</plugin>
</plugins>
</build>
</project>
Maven 프로젝트로 전환하게 된다면 pom.xml이 생성되는 것을 볼 수 있습니다.



라이브러리는 mvn repository에서 검색을 통해 Usages가 많은 버전 위주로, 의존성을 Copy & Paste 하면 됩니다.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>JSP_Board_Practice</groupId>
<artifactId>JSP_Board_Practice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
프로젝트에 적용할 의존성들은 dependencies 태그 안에 모아놓읍시다.
1. 코어(변수지원, 흐름제어, URL처리) prefix = c
- http://java.sun.com/jsp/jstl/core
2. XML (XML코어, 흐름제어, XML변환) prefix = x
- http://java.sun.com/jsp/jstl/xml
3. 국제화 (지역, 메시지형식, 숫자 및 날짜 형식) prefix = fmt
- http://java.sun.com/jsp/jstl/fmt
4. 데이터베이스(SQL) prefix = sql
- http://java.sun.com/jsp/jstl/sql
5. 함수(컬렉션 처리, String 처리)
- http://java.sun.com/jsp/jstl/functions
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
JSTL을 사용하려면 directive 선언 형태로 prefix와 uri를 불러와서 사용해야 합니다. prefix는 사용자가 정의해서 사용할 수 있으나, 헷갈리지 않도록 core의 c를 따오도록 하겠습니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" errorPage="/WEB-INF/views/errorPageTest.jsp"%>
<%@ page import="java.util.*" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSP TEST PAGE</title>
</head>
<body>
<%@ include file="./header.jsp" %>
<h3>JSTL TEST</h3>
<c:set var="price" value="1000"/>
<p> Price : ${price * 1.1}</p>
<c:out value="${param.msg}" default="Empty"/>
<p><fmt:formatDate value="<%= new Date() %>" pattern="yyy-MM-dd HH:mm:ss"/> </p>
<%@ include file="./footer.jsp" %>
</body>
</html>

JSTL을 통해 price라는 변수를 만들었고, EL을 통해 변수의 값을 가져오는 테스트 아닌 테스트를 진행해 봤습니다.
참고로 EL과 같은 경우에는 Dot 표기법 외에 [] 연산자를 통해 객체가 가지고 있는 값에 접근할 수 있습니다.
${userinfo["name"]} 이라던가, ${userinfo.name}이라던가.
하지만, 지금까지는 본격적으로 프로젝트를 만들어보지는 않았으니 필요한 만큼만 건져내 봅시다.
값 읽기: ${param.q}, ${sessionScope.loginUser}
출력: <c:out value="${b.title}"/>
조건/반복: <c:if>, <c:forEach var="b" items="${boards}">
포맷: <fmt:formatDate value="${b.createdAt}" pattern="yyyy-MM-dd HH:mm"/>
일단 JSTL은 여기까지! 이제 바로 DB 연결하고, 간단한 프로젝트를 진행해 보겠습니다!
P.S.
JSP에서 Servlet으로 변환될 때, java 소스 코드를 열어보고 싶다면?
/Desktop/JSP_Practice/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/JSP_Board_Practice/org/apache
eclipse workspace를 생성한 폴더에서 .metadata 폴더를 찾고 위에 적은 경로를 따라가면 서블릿으로 변환된 코드를 볼 수 있습니다.


Jasper는 Tomcat의 JSP 엔진으로, JSP 파일을 Java 서블릿 코드로 변환하고 컴파일하여 실행하는 역할을 합니다.
'Study > Java' 카테고리의 다른 글
| [JSP] 세션 기반 로그인과 회원가입을 만들어보자 (0) | 2025.09.09 |
|---|---|
| [JDBC] JDBC 연결 테스트와 MyBatis 설정 해보기 (0) | 2025.09.09 |
| [JSP] Java/JSP 프로젝트를 위한 eclipse 환경 설정 (0) | 2025.09.08 |
| [Java] HashMap의 데이터 관리?! Linked List와 Red-Black Tree의 전환 과정! (7) | 2024.12.01 |
| [Java] 직렬화(Serialization)와 역직렬화(Deserialization) (0) | 2024.11.17 |