본문 바로가기

백엔드/자바

스프링부트 뷰 템플릿 (타임리프, 제이에스피)

반응형

동적화면을 표시하기 위해 스프링 부트에서 사용가능한 다양한 도구가 존재합니다. 오늘은 어떠한 툴을 어떻게 연결하는 지와 사용방법을 살펴보겠습니다.

목차

공통설정

작업에 필요한 공통 디펜던시들 먼저 설치하겠습니다.

디펜던시

스프링 웹

자동 설정 등 웹애플리케이션 개발에 필요한 기능 제공

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Devtools

코드 수정을 애플리케이션 재 구동 없이 화면에 반영하기 위한 라이브 리로딩 기능 제공

<dependency>  
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>    
</dependency>

단, 해당 기능의 작동을 위해서는 자동빌드와 구동 중 빌드가 켜져있어야 함

▶ 자동빌드 켜기

Setting -> Build, Execution, Development -> Compiler. 'Build project automatically' 체크

▶ 구동 중 빌 켜기

Setting -> Advanced Settings. 'Allow auto-make to start even if developed application is currently running' 체


※ 자동저장 기능을 함께 사용할 수도 있습니다.

▶ 자동저장 켜기

Setting -> Appearance & Behavior -> System settings


스태틱 파일경로

스프링부트에서 사용가능한 스태틱 파일 경로는 아래와 같습니다.

/META-INF/resources
/resources
/static
/public

타임리프

타임리프는 서블릿 기반의 웹과 스탠드어론 환경에서 모두 작동가능한 자바 템플릿 엔진으로 JSP와 동일한 기능을 수행하지만 파일에 .html 익스텐션을 사용합니다.

디펜던시

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

컨트롤러 설정

컨트롤러 패키지를 만들고 아래와 같이 컨트롤러를 생성하고 엔드포인트를 만듭니다. 엔드포인트 메서드에서 반환되는 값은 템플릿 파일의 이름이 됩니다.

템플릿 생성 없이 앱을 구동하고 해당 주소를 열면 아래와 같이 오류가 뜹니다.

템플릿 설정

main -> resource -> template 아래 컨트롤러에 설정한 이름으로 템플릿 파일생성

템플릿 파일에 아래 태그 추가

<html xmlns:th="https://www.thymeleaf.org">

동적가치 사용하기

▶ 동적가치 전달하기

Model 인터페이스를 통해 아래처럼 템플릿으로 값을 전달 (첫 번째 매개변수는 키, 두 번째 매개변수는 값)

public String homeMain(Model model) {
  model.addAttribute("name", "dynamic");
  return "home";
}

▶ 동적가치 사용

동적가치의 사용은 ${<변수이름>}의 형태로 사용

<span th:text="${name}"></span>

프래그먼트

타임리프는 앵귤러나 리액트처럼 컴포넌트를 활용 가능합니다. 프래그먼트 설정은 아래처럼 fragment와 id 속성을 통해서 합니다.

▶ 프래그먼트 생성

<nav th:fragment="header" id="fragment-h">
    <h1 id="fragment">Header</h1>
</nav>

 프래그먼트 호출

프래그먼트 호출은 아래와 같이 세 가지 방법으로 가능

 

include

호스트 태그 안에 프래그멘트 태그를 제외한 내용만 가져옴

<div th:include="fragment/demo :: header">

insert

호스트 태그 안에 내용을 포함 프래그멘트 태그 전체를 가져옴

<div th:insert="fragment/demo :: header">

replace

호스트 태그를 프래그멘트 태그로 교체

<div th:replace="fragment/demo :: header">

태그예시

▶ 문자표시

<span th:text="${#strings.toUpperCase(name)}"></span>

▶ 지역변수 설정

<div th:with="variable = ${name}, a=10, b=20">
  <p th:text="${a} * ${b}"></p>
</div>

▶ 조건문

<p th:text="${elvis}? 'true':'false'"></p>
<p th:if="${elvis}">True</p>
<p th:unless="${elvis}">False</p>
<div th:switch="${elvis}">
  <p th:case="true">True</p>
  <p th:case="false">False</p>
</div>

▶ 반복문

<div th:each="i, status: ${list}">
  <p th:style="${status.odd} ? 'color:red' : 'color':green"></p>
  <p th:text="${status.index}">${i}</p>
  <p th:text="${status.count}">${i}</p>
  <p th:text="${status.size}">${i}</p>
  <p th:text="${status.first}">${i}</p>
  <p th:text="${status.last}">${i}</p>
</div>

▶ 폼

<form th:action="@{/formSubmit} method="GET">
  <input type="text" name="userName" />
</form>

템플릿에서 param으로 사용하기

<body>
  <p>
    name: <span th:text="${param.userName}" />
  </p>
</body>

▶ 경로에 아이디 전송하기

<form th:action="@{/update/save/{id}(id=${book.id})}">
<a th:href="@{/books/remove/{id}(id=${books.id})}"</a>

▶ 컨트롤러에서 객체받기

<form th:object="${book}">
  <div>
    <label for="isbn">ISBN</label>
    <input type="text" th:field="*{isbn}" id="isbn" placeholder="ISBN"/>
  </div>
  <div>
    <label for="name">Book Name</label>
    <input type="text" th:field="*{name}" id="name" placeholder="Book Name"/>
  </div>
</form>

▶ 컨트롤러에서 리디렉션

return "redirect:/books";

 

자바스크립트, 스타일 연결하기

<script type="text/javascript" th:src="@{js/index.js}"></script>
<link rel="stylesheet" type="text/css" th:href="@{css/main.css}"/>

▶ Using Class Style

<p th:text="Class" class="<className>"

제이에스피

JSP (Java Server Pages)는 서브릿의 진화된 형태, 동적 웹 페이지 구현을 위한 도구들의 집합입니다. 자바 코드가 포함된 HTML의 형태로 HTML태그와 자바코드를 한 파일에서 작성가능하며 '.jsp' 익스텐션을 가집니다.

작동원리

제이에스피 코드는 웹서버에서 가공되는데 (클라이언트 머신 아님) 제이에스피가 작동하기 위해 필요한 도구들은 아래와 같습니다.

▶ JSP engine

JSP 파일을 읽고 서블릿으로 변환하며 서블릿은 서버에서 실행된 후 HTML 생성합니다.

 웹서버

클라이언트로 요청을 받고 처리,

 아파치 톰캣

오픈소스 웹서버, 서브렛 컨테이너로 서브렛이나 JSP를 구동하여 다이내믹 웹페이지 구현. 

 JavaEE (Enterprise Edition)

컴포넌트 중 하나로 자바코드가 실행 가능한 순수 자바 HTTP웹 서버 제공

 Java Runtime Environment(JRE)

자바 애플리케이션 실행을 위한 환경제공

태그형태

제이에스피 태그의 시작과 끝은 아래와 같이 표시

<% %>

동적가치 주입 태그

<%= %>

디펜던시

스프링 부트 3.0 버전부터 javax 패키지 이름이 jakarta로 바뀌면서 버전에 따라 설치해야 하는 디펜던시가 다릅니다. 버전에 따라 아래 디펜던시를 pom.xlm의 디펜던시 칸에 추가

스프링 부트 3.0 버전 이상

참고로, 스프링부트 3.0 이상 버전인 경우 java 17 이상 사용해야 합니다.

▶ jsp 파일을 톰캣 서버에 컴파일

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
</dependency>

자카르타 EE 플랫폼에서 웹을 사용하기 위한 표준

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
</dependency>

Jstl 디펜던시

<dependency>
    <groupId>jakarta.servlet.jsp.jstl</groupId>
    <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
</dependency>

<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>jakarta.servlet.jsp.jstl</artifactId>
</dependency>

스프링 부트 3.0 이전 버전

▶ jsp 파일을 톰캣 서버에 컴파일

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
</dependency>

▶ Jstl 디펜던시

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>  
    <version>1.2</version>
</dependency>

▶ 공통

 

충돌방지

스프링 부트 런타임에서 제공되는 톰캣과 Jsp 파일 컴파일을 위해 추가한 디펜던시가 충돌하는 것을 방지를 위해 'provided' 추가 필요

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

파일위치 설정

컴파일 파일 (war, jar)에 제이에스피 파일이 포함되도록 제이에스피 파일의 위치를 application.properties파일에 아래와 같이 설정

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

예를 들어, 컨테이너에 'book'을 반환하면 반환되는 해당 값이 파일 명이 되고 prefix는 파일명 앞에, suffix는 파일명 뒤에 옴

구동환경 설정

구동환경은 독립환경과 웹환경이 있으며 아래 코드를 사용하여 웹환경으로 전환 가능

▶ 독립환경 (standalone)

단일머신에서 작동하는 방식으로 네트워크 통신 불필요

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TestJstlApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestJstlApplication.class, args);
    }
}

 웹환경

웹 서버에서 프로그램이 구동되며 클라이언트와 네트워크 프로토콜 (HTTP 등)을 통해 교신. 애플리케이션 서블릿 등을 런타임 서버와 구동필요

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class TestJstlApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(TestJstlApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(TestJstlApplication.class, args);
    }
}

제이에스티엘

제이에스티엘[JSTL(JavaServer Pages Standard Tag Library)]은 제이에스피 애플리케이션에 필요한 기능(조건, 반복 등)들을 태그로 제공하는 라이브러리입니다. 

태그구성

제이에스티엘 태그는 Core, Formatting, SQL, XML, Function으로 나누어지며, 각 기능을 사용하려면 각 기능을 제공하는 기본태그 추가 후 원하는 기능 사용

▶ Core

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

Formatting

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

SQL

<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>

 XML

<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>

 JSTL Functions

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

컨트롤러 생성

컨트롤러 패키지를 생성하고 클래스 생성 후 @Controller 어노테이션으로 컨테이너 등록 후 메서드 (엔드포인트)를 추가, 메서드에서 반환되는 값은 제이에스피 파일의 경로를 찾기 위한 주소가 되므로 화면에 표시할 제이에스피 파일명과 일치하게 됩니다.


※ 컨트롤러 어노테이션 중 @RestController는 제이에스피와 사용이 불가한데 이유는 아래와 같습니다.

 

@Controller는 화면만 반환하며 데이터는 반환 불가

@Controller

@RestController는 @Controller와 @ResponseBody의 기능을 합친 어노테이션으로 모든 컨트롤러의 메서드에 적용되며 데이터(JSON, XML 등)를 반환할 수 있게 합니다. 

@RestController

따라서, @RestController는 제이에스피와 기능 부분에 중복되어 제이에스피와 사용불가


템플릿 생성

main폴더 아래 webapp폴더를 생성하고 application.properties에서 설정한 대로 하위 폴더를 생성 후 제이에스피 파일 생성. 이때 파일이름은 컨트롤러에서 반환하는 이름과 일치해야 함

태그예시

형식설정 태그

<%@ 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="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>

제이에스티엘 코어

▶ 동적가치 표시

<c:out value="${book}"/>

※ Model 인터페이스를 통해 컨트롤러에서 동적 가치 지정하여 템플릿으로 전송가능

model.addAttribute("book", "book");


▶ 지역변수 지정

<c:set value="JSTL" var="title"/>

▶ 지역변수 제거 (널 처리)

<c:remove var="title"/>

▶ 에러처리

<c:catch var ="error">
    <% int x = Integer.valueOf("a");%>
</c:catch>
<c:out value="${error}"/>

▶ 조건문

<c:if test="true">True</c:if>
<c:if var="result" test="true">${result}</c:if>
<c:out value="${num % 2 eq 0 ? 'even': 'odd'}"/>
<%@ page import="java.util.Calendar" %>

<c:set value="<%= Calendar.getInstance().get(Calendar.SECOND)%>" var="seconds"/>
<c:choose>
    <c:when test="${seconds le 30 }">
        <c:out value="${seconds} is less than 30"/>
    </c:when>
        <c:when test="${seconds eq 30 }">
    <c:out value="${seconds} is equal to 30"/>
        </c:when>
    <c:otherwise>
        <c:out value="${seconds} is greater than 30"/>
    </c:otherwise>
</c:choose>

▶ 반복문

<c:forEach var="i" items="1,4,5,6,7,8,9">
    <c:out value="${i}"/><p>
</c:forEach>
<c:forTokens 
  items = "Tom:Will:Jack:Amy" 
  delims = ":" var = "name">
    <c:out value = "Name: ${name}"/><p>
</c:forTokens>

▶ 가져오기 (라이브러리사용, 해당 경로의 컨텐츠 노출)

<%@ page import="java.util.Calendar" %>
<c:set value="<%= Calendar.getInstance().get(Calendar.SECOND)%>" var="seconds"/>

/* var 속성 사용하여 지역변수에 불러온 값 저장 */
<%@ page var="date" import="java.util.Calendar" %>
<c:set value="<%= date.getInstance().get(date.SECOND)%>" var="seconds"/>

▶ 리디렉션

<c:url value = "./random.jsp" var = "url">
    <c:param name = "parameter_1" value = "1234"/>
    <c:param name = "parameter_2" value = "abcd"/>
</c:url>
<a href="${url}">Click</a>

<c:redirect url="./random.jsp"/>

제이에스티엘 포멧

▶ 날짜시간

<c:set var="now" value="<%= new java.util.Date()%>"/>
<fmt:formatDate type="time" value="${now}"/>
<c:set var="today" value="28-03-2018"/>
<fmt:parseDate value="${today}" var="parsedDate" pattern="dd-MM-yyyy"/>
<c:out value="${parsedDate}"/>

▶ 숫자

<c:set var="fee" value="35050.10"/>
<fmt:formatNumber value="${fee}" type="currency"/>
<fmt:formatNumber value="${fee}" type="number"/>
<fmt:formatNumber value="${fee}" type="percent"/>
    
<fmt:parseNumber var="i" type="number" value="${fee}"/>
<c:out value="${i}"/>

▶ 번들, 지역언어, 지역시간

<fmt:bundle basename="com.baeldung.jstl.bundles.CustomMessage" prefix="verb.">
    <fmt:message key="go"/><br/>
    <fmt:message key="come"/><br/>
    <fmt:message key="sit"/><br/>
    <fmt:message key="stand"/><br/>
</fmt:bundle>
<fmt:setBundle basename="com.baeldung.jstl.bundles.CustomMessage" var="lang"/>
<fmt:setLocale value="fr_FR"/>
<fmt:timeZone value="${zone}">
    <fmt:formatDate value="${now}" timeZone="${zn}" 
      type="both"/>
</fmt:timeZone>
<fmt:setTimeZone value="GMT+9"/>
<fmt:setBundle basename = "com.baeldung.jstl.bundles.CustomMessage" var = "lang"/>
<fmt:message key="verb.go" bundle="${lang}"/>

▶ 인코딩 타입

<fmt:requestEncoding value = "UTF-8" />

제이에스티엘 함수

▶ 문자관련

<c:set var = "string1" value = "This is first string"/>
/* contains (sub string) */
<c:if test = "${fn:contains(string1, 'first')}">
    <p>Found 'first'<p>
</c:if>

<c:if test = "${fn:containsIgnoreCase(string1, 'FIRST')}">
    <p>Found 'FIRST' string<p>
</c:if>

/* starts with */
<c:if test = "${fn:startsWith(string1, 'This')}">
    <p>starts with 'This'</p>
</c:if>

/* ends with */
<c:if test="${fn:endsWith(string1, 'string')}">
    <p>ends with 'string'<p>
</c:if>

/* escape XML mark up */
<p>${fn:escapeXml(string1)}</p>

/* index of */
<p>Index: ${fn:indexOf(string1, "first")}</p>

/* split */
<c:set var = "string3" value = "${fn:split(string1, ' ')}" />
<c:out value="${string3}"/>

/* join */
<c:set var = "string4" value = "${fn:join(string3, '-')}" />
<c:out value="${string4}"/>

/* length */
<p>Length: ${fn:length(string1)}</p>

/* replace */
<c:set var = "string3" value = "${fn:replace(string1, 'first', 'third')}" />

/* sub string: 주어진 인덱스 범위의 문자 추출 */
<c:set var = "string3" value = "${fn:substring(string1, <startIndex>, <endIndex>)}" />

/* sub string: 주어진 문자 이후의 문자 추출 */
<c:set var = "string3" value = "${fn:substringAfter(string1, 'is')}" />

/* sub string: 주어진 문자 이전의 문자 추출 */
<c:set var = "string3" value = "${fn:substringBefore(string1, 'is')}" />

/* to lowercase */
<c:set var = "string3" value = "${fn:toLowerCase(string1)}" />

/* to uppercase */
<c:set var = "string3" value = "${fn:toUpperCase(string1)}" />

/* trim */
<c:set var = "string1" value = "This is first String    "/>

이상으로 스프링부트에서 사용가능한 뷰 템플릿들을 살펴보았습니다.


참고

JSP - Standard Tag Library (JSTL) Tutorial | Tutorialspoint

 

JSP - Standard Tag Library (JSTL) Tutorial

JSP Standard Tag Library (JSTL) Tutorial - In this chapter, we will understand the different tags in JSP. The JavaServer Pages Standard Tag Library (JSTL) is a collection of useful JSP tags which encapsulates the core functionality common to many JSP appli

www.tutorialspoint.com

A Guide to the JSTL Library | Baeldung

 

728x90
반응형