Language/JSP

9월 30일 D+47 [JSP 20장 : Tiles 이용 레이아웃 템플릿]

구일일구 2022. 9. 30. 16:20
반응형

 컴포지트 뷰 패턴 (Composite View Pattern)

: 새로운 페이지를 추가할 때마다 페이지 구조와 관련된 코드를 작성해 주어야 하는데, 이 경우 각각의 페이지는 레이아웃을 위한 코드를 중복해서 갖게 됨

이 경우 전체 페이지에 대해 레이아웃 구조를 일부 변경해야 할 경우, 모든 페이지의 코드를 수정해 주어야 하는 불편함이 따름

컴포지트 뷰 패턴을 적용하여 위의 불편함을 해소할 수 있다.

컴포지트 뷰 패턴의 핵심은 레이아웃 구성 정보를 담고 있는 템플릿을 생성한다는 것

 

Tiles 2

- 컴포지트 뷰 패턴 구현 프레임워크

- 설치 : txt 파일 보고 따라하기

tiles.txt
0.01MB


필요한 jar 파일을 WEB-INF/lib 디렉터리에 복사하기

src > main > WEB-INF > lib 에 넣기

commons-beanutils-1.8.0.jar
0.22MB
commons-digester-1.8.1.jar
0.14MB
commons-logging-api-1.1.jar
0.04MB
tiles-api-2.1.2.jar
0.02MB
tiles-core-2.1.2.jar
0.13MB
tiles-jsp-2.1.2.jar
0.05MB
tiles-servlet-2.1.2.jar
0.05MB


list.jsp에서 forward하여 값을 넘길 필요가 없게됨. 앞으로는 이름만 가지고 쓰면 됨


 web.xml에 tiles 초기화 설정 추가하기

<servlet>
	<servlet-name>tiles</servlet-name>
	<servlet-class>org.apache.tiles.web.startup.TilesServlet</servlet-class>
	<init-param>
		<param-name>
		org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
		</param-name>
		<param-value>
		/WEB-INF/tiles-hello.xml,/WEB-INF/tiles-service.xml
		</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

 

TilesServlet을 설정할 때 <load-on-startup> 옵션을 줘서 웹 어플리케이션이 초기화 될 때, TilesServlet이 실행되도록 해야 함

초기화 파라미터를 이용해 org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG 초기화 파라미터의 값으로 

Tiles 설정 파일의 목록을 입력받으면 됨 : 각 설정 파일의 경로는 콤마로 구분(공백이 들어가지 않도록 하기!)

org.apache.tiles.... 초기화 파라미터를 설정하지 않을 경우, 기본값은 /WEB-INF/tiles.xml이다.


 tiles 설정 파일 작성 : tiles-hello.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
	"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
	"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
	
<tiles-definitions>
	//이름이 hello인 Definition 설정 , 템플릿 파일로 /template/layout.jsp를 사용함
	<definition name="hello" template="/tiles/template/layout.jsp">
    			//title attribute로 문자열 값을 설정함
			<put-attribute name="title" value="헬로우 월드" />
			//각 영역에 삽입될 JSP를 지정함
			<put-attribute name="header" value="/tiles/template/header.jsp" />
			<put-attribute name="menu" value="/tiles/template/menu.jsp" />
			<put-attribute name="body" value="/tiles/hello_body.jsp" />
			<put-attribute name="footer" value="/tiles/template/footer.jsp" />
	</definition>
	
    	//hello에 정의된 것을 그대로 상속받아서 쓰고, 바꿀 부분만 새롭게 설정 : 코드를 줄임
	<definition name="hello2" extends="hello">
			<put-attribute name="title" value="헬로우 월드2" />
			<put-attribute name="header" value="/tiles/template/header2.jsp" />
			<put-attribute name="footer" value="/tiles/template/footer2.jsp" /> 
	</definition>
	
</tiles-definitions>

Tiles 설정 파일은 어떤 JSP를 템플릿으로 사용하고, 템플릿의 각 영역을 어떤 내용으로 채울지에 대한 정보를 설정함

tiles-hello.xml 파일은 Tiles 설정 파일로, 두 개의 Definition을 설정하고 있음

Definition은 템플릿의 각 내용을 어떻게 채울지에 대한 정보를 정의함

위 코드)hello Definition은 템플릿 파일로 layout.jsp를 사용, 템플릿의 title의 어트리뷰트 값을 '헬로우 월드'로 설정, footer 어트리뷰트의 값을 '/template/footer.jsp' 로 설정함


레이아웃 템플릿 JSP 파일 작성: template/layout.jsp

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>  <!-- tiles와 관련된 태그 라이브러리 사용 -->
<html>
<head>
	<title><tiles:getAsString name="title" /></title> <!-- 'title'어트리뷰트의 값을 문장뎔로 삽입 -->
</head>
<body>

<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tr>
	<td colspan="2">
	<tiles:insertAttribute name="header" /> <!-- 'header'어트리뷰트가 가리키는 코드 조각 삽입 -->
	</td>
</tr>
<tr>
	<td valign="top"><tiles:insertAttribute name="menu" /></td>
	<td valign="top"><tiles:insertAttribute name-="body" /></td>

</tr>
<tr>
	<td colspan="2">
	<tiles:insertAttribute name="footer" />
	</td>
</tr>
</table>
</body>
</html>

템플릿 파일은 각 어트리뷰트의 값을 어느 위치에 어떻게 삽입할지를 결정함

Tiles의 템플릿 파일은 동일한 페이지 구성을 갖는 화면을 위한 레이아웃 관련 코드를 포함하고 있으며,

Tiles가 제공하는 태그를 이용해 각 영역에 어떤 값을 삽입할지를 결정함

위 코드) layout.jsp는 <table> 태그를 이용해 레이아웃 구조를 잡고 있음.

<tiles:getAsString>태그 : 해당 어트리뷰트의 값을 현재 위치에 문자열로 삽입함 : "title"어트리뷰트의 값을 문자열로 삽입함 ➡️ "hello2" Definition을 사용할 경우 <tiles:getAsString name="title" /> 코드는 현재 위치에 "헬로우 월드2" 문자열을 삽입함

<tiles:insertAttribute>태그 : 어트리뷰트 값에 해당하는 JSP를 <jsp:include>와 동일한 방식으로 현재 위치에 삽입함 ➡️ <tiles:insertAttribute name="header" /> 태그는 Definition에서 정의한 "header" 어트리뷰트 값인 "/template/header2.jsp"의 실행결과를 현재 위치에 삽입함


 템플릿의 각 구성요소에 삽입된 JSP 작성

 

앞의 Tiles 설정 파일에서 <put-attribute> 태그를 이용해 각 영역에 삽입될 JSP 파일을 값으로 설정해주었음

예제 Tiles 설정 파일 : header.jsp / header2.jsp / footer.jsp / footer2.jsp / menu.jsp 를 각각 "header", "footer", "menu" 어트리뷰트 값으로 설정하고 잇음

그냥 간단하게 작성해서 테스트함


 Definition을 사용하는 JSP 파일 작성

 

실제로 Definition을 사용해서 필요한 화면을 삽입하기

Definition을 사용하려면, Tiles가 제공하는 커스텀 태그 중 <tiles:insertDefinition> 태그를 사용하면 됨

<%@  taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
...
<tiles:insertDefinition name="hello" />

insertDefinition 태그는 name 속성을 이용해 사용할 Definition의 이름을 지정함

"hello" Definition을 사용한다고 했으니, 현재 위치에 layout.jsp를 삽입

layout.jsp의 각 <tiles:insertAttribute>위치에는 header.jsp, menu.jsp, hello_body.jsp, footer.jsp가 삽입됨


View Preparer를 이용한 뷰 데이터 설정하기

package tiles;

import java.util.ArrayList;
import java.util.List;

import org.apache.tiles.Attribute;
import org.apache.tiles.AttributeContext;
import org.apache.tiles.context.TilesRequestContext;
import org.apache.tiles.preparer.ViewPreparer;

public class MenuViewPreparer {
	
	public void execute(TilesRequestContext tilesContext, AttributeContext attrContext) {
		List<MenuItem> userMenus = new ArrayList<MenuItem>();
		userMenus.add(new MenuItem("메뉴1", "link1"));
		userMenus.add(new MenuItem("메뉴2", "link2"));
		userMenus.add(new MenuItem("메뉴3", "link3"));
		tilesContext.getRequestScope().put("userMenus", userMenus);
		
		List<MenuItem> adminMenus = new ArrayList<MenuItem>();
		adminMenus.add(new MenuItem("관리메뉴1", "link1"));
		adminMenus.add(new MenuItem("관리메뉴2", "link2"));
		adminMenus.add(new MenuItem("관리메뉴3", "link3"));
		attrContext.putAttribute("adminMenus", new Attribute(adminMenus), true);
	}
}

메뉴나 상단 화면을 출력하기 위해 필요한 데이터가 존재

Tiles는 모든 페이지에서 공통으로 사용되는 상단, 좌측 메뉴, 하단 등의 화면을 출력하는 데 필요한 데이터를 생성하는 용도로 사용하기에 알맞은 ViewPreparer 인터페이스를 제공하고 잇음

ViewPreparer 인터페이스는 다음의 메서드를 선언함

void execute(TilesRequestContext tilesContext, AttributeContext attrContext)

execute() 메서드는 TilesRequestContext나 AttributeContext를 이용해서 여러 페이지에 공통으로 적용되는 영역에서 필요로 하는 데이터를 전달할 수 있음

TilesRequestContext.getRequestScope() 메서드가 리턴하는 Map에 뷰에 전달하고 싶은 데이터의 이름과 값을 삽입하면 JSP에 삽입한 데이터가 전달됨

TilesRequestContext.getRequestScope()로 데이터를 전달한 경우, JSP 페이지는 다음과 같이 request 기본 객체의 속성이나 EL을 이용해 전달받은 값을 사용할 수 있다

<%
    List<MenuItem> menuItems = (List<MenuItem>) request.getAttribute("userMenus");
%>
<c:forEach var="menu" items="${userMenus}">
...
</c:forEach>

 

뷰에 데이터를 전달하는 두 번째 방법은 AttributeContext.putAttribute() 메서드를 사용하는 것

attrContext.putAttribute("adminMenus", new Attribute(adminMenus), true);

첫 번째 파라미터 : 전달할 데이터의 이름

두 번째 파라미터 : 설정할 데이터의 값을 가진 Attribute 객체

세 번째 파라미터 : AttributeContext에 추가한 데이터를 전파할지의 여부를 설정 : true로 지정하여 JSP에서 설정한 데이터를 사용할 수 있게 됨

JSP에서 AttributeContext로 설정한 데이터를 사용하려면 다음과 같이 <tiles:importAttribute>태그를 이용하면 됨

<tiles:importAttribute name="adminMenus" />

<c:forEach var="menu" items="${adminMenus">

${menu.name}

</c:forEach>

<tiles:importAttribute> 태그는 기본적으로 PAGE 영역의 동일한 이름을 갖는 속성에 전달받은 데이터를 설정

만약 특정한 영역의 속성으로 추가하고 싶다면 scope 속성을 사용하면 됨 : page, request, session, application이 올 수 있음

<tiles:importAttribute name="adminMenus" scope="request" />

완성

taglib 있어야하고,

include는 <tiles:insertAttribute name="header" /> 이렇게 바꾸기

그렇게 다 바꾸고 나면, deleteForm / list / read/ writeForm / updateForm 없애도 된다는..!

url에서 프로젝트명 바로 뒤에 hello.tiles로 적어야 jsp가 돌아감니다..!

 

http://localhost:9009/imageBoard/home.tiles ➡️ home이 실행됨 : 저절로 tiles는 사라진다고 생각하면 됨

반응형