본문 바로가기

Server/Servlet & JSP

JSP 기본 개념 - 3 ( JSTL - JSP Standard Tag Library )

  • JSTL (JSP Standard Tag Library)
    - JSP에서 자주 사용되거나 공통적으로 사용되는 Java 문법(코드)을
      스크립틀릿(scriptlet) 대신 HTML 태그 형식으로 전환하여
      표준으로 제공하는 라이브러리(아파치 재단에서 제공)
    - if, for, 변수 선언(scope 지정 가능), 변수 제거(scope 지정 가능),
      형변환, 문자열, 숫자, 날짜 관련 포맷 지정

  • JSTL 적용 방법
    - JSTL 관련 jar 파일을 webapp/WEB-INF/lib 폴더에 추가
    - JSTL을 사용하려는 JSP 페이지 상단에 tablib JSP 지시자를 추가

  • JSTL로 변수 선언 / 제거 / 출력
    1. 변수 선언(== 속성 추가) (c:set  태그)
    - 변수 선언 (속성 추가 == setAttribute)을 위한 태그
    - 작성 가능한 속성
    1) var : 선언할 변수명 (== 속성 key)
    2) value : 대입할 값 (== 속성 value)
    3) scope : 범위 지정 (page, request, session, application / 기본값은 page)

    2. 변수 제거 (== 속성 제거) (c:remove 태그)
    - 변수 제거 (== 속성 제거(removeAttribute("key")))
    - 작성 가능한 속성
    1) var : 제거할 변수명 (== 속성 key)
    2) scope : 지정된 scope의 변수만 제거 (기본값은 모든 scope 일괄 제거)

    3. 변수 출력 (c:out 태그)
    - EL 구문과 유사
    - 단, escapeXml 속성에 따라 html 태그 해석 여부가 결정됨
       true : 해석 X (기본값) / false : 해석 O
  • JSTL 조건문
    1. 단일 조건문 (c:if 태그)
    - 조건식이 true이면 수행 + 화면에 출력
    - 별도의 else 구문 없음
    - 속성은 test만 존재
    ★ ★ test 속성값 작성 시 주의 사항★ ★
    1) 속성값은 무조건 EL 구문으로만 작성
        ex) test="${key==abc}"
    2) 속성값은 무조건 true / false 가 결과로 나와야 함
    3) 속성값을 작성하는 " " 제일 앞/뒤에는 띄어쓰기가 있으면 안 됨
     ※ 오류 예시
      test=" ${key==abc}" // 앞에 공백
      test="${key==abc} " // 뒤에 공백

    2. 연속된 조건문 (c:choose / c:when / c:otherwise)
    - c:choose 태그
    : c:when / c:otherwise를 감싸는 태그 (내부에 if ~ else if ~ else 구문을 쓰는 것)
    ★ ★ ★ c:choose 태그 작성 시 주의 사항 ★ ★ ★
      c:choose 태그 내부에는
      c:when, c:otherwise, JSP 주석, 공백 이외에는 아무 것도 작성되면 안 됨
    - c:when 태그
    : if, else if를 나타내는 태그 / 속성은 test만 있음 (c:if 참고)
    - c:otherwise 태그
    : else 역할의 태그로 아무 속성이 없음
  • JSTL 반복문 ( c:forEach 태그 )
    - 일반 for문 + 추가 기능
    - 작성할 수 있는 속성
    1) var     : 현재 반복 횟수에 해당하는 변수 ( ex. int i )
    2) begin : 반복 시 var 시작 값
    3) end    : 반복이 종료될 var 값
    4) step   : 반복할 때마다 var가 증가하는 값 (기본값: 1)
    5) item   : 반복 접근한 객체 (배열, 컬렉션 객체)

    6) varStatus : 현재 반복 상태와 관련된 정보를 제공하는 변수 선언
    - varStatus="변수명"
    → c:forEach 구문 내에서 "변수명"을 통해 원하는 값을 얻을 수 있음
    ※ varStatus에서 제공되는 값
    a) current : 현재 반복 횟수 (현재 var 값) 또는 현재 반복 접근 중인 객체(컬렉션/배열 요소)
    b) index : 현재 인덱스값 반환 (0부터 시작)
    c) count : 현재 몇 바퀴째인지 반복 횟수 반환 (1부터 시작)
    d) first : 첫 번째 반복이면 true, 아니면 false
    e) last : 마지막 반복이면 true, 아니면 false
  • JSTL 예시

- index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSTL</title>
</head>
<body>
    <h3>JSTL 확인하기</h3>
    <ul>
        <li>
            JSTL 기초 <button id="btn1">이동</button>
        </li>
        <li>
            JSTL 조건문 <button id="btn2">이동</button>
        </li>
        <li>
            JSTL 반복문 <button id="btn3">이동</button>
        </li>
    </ul>

    <!-- resources 폴더 내 파일 접근 시 절대 경로 사용 권장 -->
    <!-- 절대 경로 기준 : webapp == /JSPProject3 -->
    <script src="/JSPProject3/resources/js/main.js"></script>
</body>
</html>

- JavaScript

// #btn1 요소 클릭 시
document.getElementById("btn1").addEventListener("click", function(){
    
    // location.href;        : 현재 주소 반환
    // location.href = 주소; : 대입된 주소로 이동(GET 방식)
    location.href="jstl/basic";
})

// #btn2 요소 클릭 시
document.querySelector("#btn2").addEventListener("click", ()=>{
    location.href="jstl/condition";
})

// #btn3 요소 클릭 시
document.getElementById("btn3").addEventListener("click", function(){
    location.href="jstl/loop";
})

- Servlet Container [ 1 ]
→ BasicServlet

package edu.kh.jsp.jstl.controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
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("/jstl/basic")
public class BasicServlet extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/jstl/basic.jsp");
		dispatcher.forward(req, resp);
	}
}

- JSP [ 1 ]
→ basic ( 변수 선언 / 변수 제거 / 변수 출력)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%-- JSTL에 사용하려는 태그 추가하기 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    

<%-- 
	<%@ %> : JSP 지시자 태그
	
	taglib : 태그 라이브러리 추가
	
	prefix 속성 : 태그 앞에 붙을 접두사를 지정
	
	uri(Uniform Resource Identifier, 통합 자원 식별자) 
	: 자원을 식별하는 고유 문자열 (ID)
	
	(참고)
	URL(Uniform Resource Locator, 통합 자원 경로)
	: 자원의 위치를 나타내는 문자열 (주소, 경로)
--%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSTL 기초</title>
</head>
<body>
	<h1>1. 변수 선언(== 속성 추가) (c:set 태그)</h1>	
	
    <% // 스크립틀릿으로 page scope 추가하기
	   pageContext.setAttribute("num1", 5);
	%>
	
	<%-- JSTL로 page scope 속성 추가하기 --%>
	<c:set var="num2" value="10" scope="page"/>
	<!-- <태그명 /> : 태그가 시작되자마자 종료 == 내용이 없는 요소 -->
	
	<h3>${num1}</h3>
	<h3>${num2}</h3>
	
	<hr>
	
	<h3>request scope에 세팅</h3>
	<c:set var="num2" value="20" scope="request"/>
	
	<h3>request Scope num2 : ${requestScope.num2}</h3>
	
	<hr>
	
	<h3>session, application scope에 세팅</h3>
	<c:set var="num2" value="2000" scope="session"/>
	<c:set var="num2" value="12345" scope="application"/>
	
	<h3>session Scope num2 : ${sessionScope.num2}</h3>
	<h3>application Scope num2 : ${applicationScope.num2}</h3>
	
	<h3>scope 미지정 시 좁은 범위부터 탐색(우선순위) : ${num2}</h3>
	
	<hr>
	
	<h1>2. 변수 제거(== 속성 제거) (c:remove 태그)</h1>	
	
    <c:set var="test1" value="테스트1"/>
	<%-- scope 미지정 : page --%>
	
	<h4>test1 : ${pageScope.test1}</h4>
	
	<!-- test1 제거 -->
	<c:remove var="test1" scope="page"/>
	
	<h4>제거 후 test1 : ${pageScope.test1}</h4>
	
	<hr>
	
	<h3>scope 지정해서 제거하기</h3>
	
	<c:set var="test2" value="page" scope="page"/>
	<c:set var="test2" value="request" scope="request"/>
	<c:set var="test2" value="session" scope="session"/>
	<c:set var="test2" value="application" scope="application"/>
	
	<!-- 특정 scope만 제거 -->
	<c:remove var="test2" scope="session"/>
	
	<!-- 모든 scope 제거 (scope 속성 작성 X) -->
	<c:remove var="test2"/>
	
	<ul>
		<li>${pageScope.test2}</li>
		<li>${requestScope.test2}</li>
		<li>${sessionScope.test2}</li>
		<li>${applicationScope.test2}</li>
	</ul>
	
	<hr>
	
	<h1>3. 변수 출력 (c:out 태그)</h1>

  	<c:set var="temp" value="<h1>c:out 테스트 중 입니다.</h1>"/>
  	
  	HTML 태그 해석 X : <c:out value="${temp}"/>
  	
  	<br>
  	
  	HTML 태그 해석 O : <c:out value="${temp}" escapeXml="false"/>
  	
  	<br>
  	
  	EL : EL로 출력시 escapeXml="false" 상태 적용 (HTML 해석함)
  	${temp}
</body>
</html>

- 화면 [ 1 ]
1) 변수 선언

2) 변수 제거

3) 변수 출력


- Servlet Container [ 2 ]
→ ConditionServlet

package edu.kh.jsp.jstl.controller;

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;

@WebServlet("/jstl/condition")
public class ConditionServlet extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.getRequestDispatcher("/WEB-INF/views/jstl/condition.jsp").forward(req, resp);
	}
}

- JSP [ 2 ]
→ condition ( JSTL 조건문 - if )

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%-- core 태그 : 자주 사용하는 자바 코드 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%-- format 태그 : 형식, 형변환 관련 코드 --%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSTL 조건문</title>
</head>
<body>
	<h1>1. 단일 조건문 (c:if 태그)</h1>
	<h3>c:if 테스트용 변수 선언</h3>
	<!-- 변수명 : menu, 범위 : page, 값: 카페모카 -->
	<c:set var="menu" value="카페모카" scope="page"/>
	<c:set var="price" value="45000" scope="page"/>
	
	<ul>
		<li>${menu}</li>
		<li>${price}</li>
	</ul>
	
	<c:if test="${price == 4500}">
		<h4>4500원 입니다.</h4>
	</c:if>
	
	<!-- 별도의 else 구문 존재 X -->
	<c:if test="${price != 4500}">
		<h4>4500원이 아닙니다.</h4>
	</c:if>
	
	<hr>
	
	 <%-- fmt:parseNumber 태그
	 
    	- 값을 숫자로 변환한 후 새로운 변수를 생성해서 대입
      	  (변수 생성은 선택 가능)

    	- 속성
      	1) value : 숫자로 바꾸려는 값 (필수)

      	2) pattern : value의 패턴을 인식하여 변화할 수 있게 함
        	ex) value="1,000,000"  pattern="0,000,000"
            -> 1000000

      	3) var : 변수명
      	
      	4) scope : 범위 지정

      	5) integerOnly :
        	true : 정수 부분만 변환
        	false : 정수가 아닌 부분(소수)도 변환 (기본값)
  	--%>
	
	<fmt:parseNumber value="${price}" var="parsePrice"/>
		
	<c:if test="${parsePrice <= 50000}">
		${menu}를 마실 수 있다.
	</c:if>	
	
	<c:if test="${parsePrice > 50000}">
		${menu}를 마실 수 없다.
	</c:if>
	
	<hr>
	
	<h2>2. 연속된 조건문 (c:choose / c:when / c:otherwise)</h2>
	<!-- if ~ else if ~ else -->
	
	<h4>테스트 방법</h4>
	<pre>
		주소창에 값을 직접 입력한 후에
		\${param.key} 를 이용해서 값 얻어오기
		
		ex) http://localhost:8081/JSPProject3/jstl/condition?val=100
		
		쿼리스트링(?val=100) 부분을 변경하면서 테스트
	</pre>
	
	<c:choose>
		<c:when test="${param.val > 100 }">
			${param.val}은 100보다 크다.
		</c:when>
			
		<c:when test="${param.val > 50 }">
			${param.val}은 50초과 100 이하 입니다.
		</c:when>
			
		<c:otherwise>
			${param.val}은 50 이하 입니다.
		</c:otherwise>
	</c:choose>
	
	<!-- 파라미터에 val가 존재한다면 (존재하지 않을 경우 빈칸)-->
	<c:if test="${!empty param.val}">
		<c:choose>
			<c:when test="${param.val > 100 }">
				${param.val}은 100보다 크다.
			</c:when>
			
			<c:when test="${param.val > 50 }">
				${param.val}은 50초과 100 이하 입니다.
			</c:when>
			
			<c:otherwise>
				${param.val}은 50 이하 입니다.
			</c:otherwise>
		</c:choose>
	</c:if>
</body>
</html>

- 화면
1) 단일 조건문

2) 연속된 조건문

파라미터에 val가 존재하지 않으면 빈 칸


- Servlet Container [ 3 ]
→ LoopServlet

package edu.kh.jsp.jstl.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

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

import edu.kh.jsp.model.dto.Book;

@WebServlet("/jstl/loop")
public class LoopServlet extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		List<Book> bookList = new ArrayList<>();
		
		bookList.add(new Book("소년이 온다", "한강", 15000));
	    bookList.add(new Book("어른의 행복은 조용하다", "태수", 18900));
	    bookList.add(new Book("트렌드 코리아 2025", "김난도", 18000));
	    bookList.add(new Book("행복하지 않으면 인생은 바뀌지 않는다", "브라이언 트레이시", 17550));
	    bookList.add(new Book("세이노의 가르침", "세이노", 6200));
	      
	    req.setAttribute("bookList", bookList);
		
		req.getRequestDispatcher("/WEB-INF/views/jstl/loop.jsp").forward(req, resp);
	}
}

- JSP [ 3 ]
→ Loop ( JSTL 반복문 - for )

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSTL 반복문</title>
</head>
<body>
	<h1>c:forEach 태그</h1>
	
	<h1>일반 for문 형식으로 사용하기</h1>
	<ul>
		<c:forEach var="i" begin="1" end="10" step="1">
			<li>${i}</li>
		</c:forEach>
	</ul>
	
	<hr>
	
	<c:forEach var="num" begin="1" end="6">
		<h${num}>현재 num 값 : ${num}</h${num}>
	</c:forEach>
	
	<hr>
	
	<h3>c:forEach의 step은 양수만 가능!</h3>
	
	<!-- h6 -> h1 반복 출력 -->
	<c:forEach var="num" begin="1" end="6">
		<h${7-num}>현재 num 값 : ${7-num}</h${7-num}>
	</c:forEach>
	
	<hr>
	
	<h3>bookList를 일반 for문으로 다루기</h3>
	<pre>
	   	접두사 fn (JSTL-EL)
	   	- fn(function, 기능) : 문자열,컬렉션 관련 메서드를
	                          제공하는 접두사
	
	   - 태그 형식이 아닌 EL 형식 ->  \${fn:메서드명(코드)}
	
	   - \${fn:length(배열 또는 컬렉션 또는 문자열)} : 길이 반환
	</pre>	
	
	<h4>bookList의 길이 : ${fn:length(bookList)} </h4>
	
	<c:forEach var="i" begin="0" end="${fn:length(bookList)-1}">
		<li>${i}번째 인덱스 책 이름 : ${bookList[i].title}</li>
		
		가격 : 
		<c:choose>
			<c:when test="${bookList[i].price >= 18000}">
				<span style="color: red">${bookList[i].price}원</span>
			</c:when>
				
			<c:otherwise>
				${bookList[i].price}원
			</c:otherwise>
		</c:choose>
	</c:forEach>
	
	<hr>
	
	<h1>향상된 for문 형식으로 사용하기</h1>
	
	<ul>
		<c:forEach items="${bookList}" var="book">
			<li>${book}</li>
		</c:forEach>
	</ul>
	
	<hr>
	
	<h3>varStatus 속성</h3>
	<c:forEach items="${bookList}" var="book" varStatus="vs">	
		
		<!-- vs.first : 첫 번째 반복이면 true -->
		<c:if test="${vs.first}">
			<p>---- 시작 ----</p>
		</c:if>
		
		<ul>
			<li>현재 인덱스 번호 : ${vs.index}</li>
			<li>현재 반복 수(count) : ${vs.count}</li>
			<li>현재 요소(var 속성값) : ${book}</li>
			<li>현재 요소(vs.current) : ${vs.current}</li>
		</ul>
		
		<!-- vs.last : 마지막 반복이면 true -->
		<c:if test="${vs.last}">
			<p>---- 종료 ----</p>
		</c:if>
	</c:forEach>
	
	<hr>
	
	<table border="1">
		<thead>
			<tr>
				<th>인덱스</th>
				<th>제목</th>
				<th>저자</th>
				<th>가격(원)</th>
			</tr>
		</thead>
		<tbody>
			<c:forEach items="${bookList}" var="book" varStatus="vs">
				<tr>
					<td>${vs.index}</td>
					<!-- 데이터셋 속성(data-) : html의 변수 역할
						 -> 해당 요소에 고유한 커스텀 값을 지정하고 싶은 경우 사용 -->
					<td data-price="${book.price}" class="book-title">${book.title}</td>
					<td>${book.writer}</td>
					<td>${book.price}(원)</td>
				</tr>
			</c:forEach>			
		</tbody>
	</table>
	
	<script src="/JSPProject3/resources/js/book.js"></script>
</body>
</html>

- JavaScript

// 제목 클릭 시
// alert(OOO은 XXX원 입니다.) 출력

const bookTitleList = document.querySelectorAll(".book-title");
// bookTitleList == 배열
// -> 요소를 하나씩 꺼낸 경우 == 제목 td 요소
// -> 요소를 하나씩 꺼내서 클릭된 경우라는 이벤트 리스너 추가

// 향상된 for문
for(let title of bookTitleList){
    title.addEventListener("click", e => {
        
        // 제목
        const t = e.target.innerText;

        // 가격
        // const p = e.target.nextElementSibling.nextElementSibling.innerText;
        
        // data-price 속성값 얻어오기
        const p = e.target.getAttribute("data-price");

        // alert(t + " 은(는) " + p + "원 입니다.");

        // `${백틱}`
        alert(`${t} 은/는 ${p}원 입니다.`);

        /* alert("[" + title.innerHTML + "]" + "은(는) " 
            + title.nextElementSibling.nextElementSibling.innerHTML + "입니다."); */
    })
}

- Java
→ Book Class

package edu.kh.jsp.model.dto;

public class Book {
	private String title;
	private String writer;
	private int price;
	
	public Book() {}

	public Book(String title, String writer, int price) {
		super();
		this.title = title;
		this.writer = writer;
		this.price = price;
	}

	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 int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}

	@Override
	public String toString() {
		return String.format("%s %s %d", title, writer, price);
	}
}

- 화면
1) 일반 for문 형식으로 사용

2) List 객체를 일반 for문으로 다루기

3) List 객체를 향상된 for문 형식으로 사용

4) varStatus 속성

5) 예제

각 도서 제목 클릭 시 alert 창 호출

 

'Server > Servlet & JSP' 카테고리의 다른 글

JSP 기본 개념 - 2 ( Expression Language, scope )  (0) 2025.01.01
JSP 기본 개념 - 1  (0) 2025.01.01
Servlet 기본 개념  (0) 2024.12.31