본문 바로가기
Dev/Java

Tiles를 이용한 컴포지트 뷰 구현

by vellahw 2022. 9. 30.

 

 

 

웹 어플리케이션의 상당수의 페이지는 헤더, 좌측 메뉴, 푸터가 동일한 페이지가 많으며 페이지의 구조도 거의 동일하다.

동일한 구조를 갖는 페이지들을 개발할 때 구조를 구성하는 코드가 중복될 수 있는데 Tiles를 통해 페이지를 구성하는데 사용되는 코드의 중복을 없애고 구조를 효율적으로 관리할 수 있다.

 

 

1. 컴포지트 뷰(Composite View) 패턴

컴포지트 뷰(Composite View) 패턴을 적용하면 웹 어플리케이션 개발에서 페이지 구조를 위한 코드를 매번 입력해야 하는 불편함을 줄이고 페이지의 레이아웃 구성을 위한 중복된 코드를 제거할 수 있다.

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

<table>
<tr>
    <td>
    [헤더 조각 삽입 코드]
    </td>
</tr>
<tr>
    <td>[메뉴 조각 삽입 코드]</td>
    <td>[메뉴 조각 삽입 코드]</td>
</tr>
<tr>
    <td>
    [푸터 조각 삽입 코드]
    </td>
</tr>
</table>

웹 프로그래밍에서 템플릿은 다음과 같은 형식을 갖게 된다. 레이아웃을 구성하는 각 영역에 알맞은 내용을 삽입 해주는 코드는 컴포지트 뷰 패턴을 구현한 라이브러리마다 다르다.

예를 들어 템플릿 코드에서 다음과 같이 <tiles:insertAttribute> 커스텀 태그를 이용해 코드 조각을 삽입할 수 있다.

<table>
<tr>
    <td>
    <tiles:insertAttribute name="header" />
    </td>
</tr>
<tr>
    <td><tiles:insertAttribute name="menu" /></td>
    <td><tiles:insertAttribute name="body" /></td>
</tr>
<tr>
    <td>
    <tiles:insertAttribute name="footer" />
    </td>
</tr>
</table>

동일한 레이아웃 구성을 갖는 페이지는 위 코드와 같은 템플릿 코드를 이용해서 페이지 구성과 관련된 동일한 코드를 갖게 된다.

또한, 각 영역에 어떤 내용이 삽입될지에 대한 정보를 외부의 파일을 이용해서 설정함으로써 손쉽게 페이지 구성 요소를 변경할 수 있다.

 

 

2. Tiles 이용하기

1) 필요한 7개의 jar 파일을 WEB-INF/lib 디렉터리에 추가한다.

2) 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 설정 파일의 목록을 입력 받으면 된다. 각 설정 파일의 경로는 콤마로 구분한다.

*설정 파일 목록을 입력 할 때 콤마 사이에 공백 문자가 포함 되면 해당 설정 파일을 올바르게 찾지 못하기 때문에 입력하지 않도록 주의 해야한다.

 

3) Tiles 설정 파일 작성 (tiles-hello.xml)

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

<?xml version="1.0" encoding="euc-kr"?>
<!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 설정. 템플릿 파일로 /tiles/template/layout.jsp를 사용  -->
	<definition name="hello" template="/tiles/template/layout.jsp"> 
		<!-- title 어트리부트로 문자열 값을 설정  -->
		<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 재사용  -->
	<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>

hello2는 위의 hello Definition을 상속 받았는데 extends 속성을 이용해서 설정 정보를 상속 받으면 template 및 어트리부트의 모든 값을 그대로 사용할 수 있게 된다.

또한 자식은 부모에서 정의하지 않은 어트리부트를 추가할 수 있고 부모에 정의한 어트리부트의 값을 변경할 수도 있다.

 

4) jsp 파일 작성

 4-1. 레이아웃 템플릿 (layout.jsp)

<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<!-- tiles 태그 라이브러리 사용 -->    
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<html>
<head>
<!-- tiles 어트리부트 값을 문자열로 삽입  -->
<title><tiles:getAsString name="title"/></title>
</head>
<body>
<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tr>
	<td colspan="2">
	<!-- "header" 어트리부트가 가리키는 코드 조각 삽입 -->
	<tiles:insertAttribute name="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>

 

 4-2. 템플릿의 각 구성 요소에 삽입될 JSP 

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
첫 번째 헤더입니다.

▲ header.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
두 번째 헤더입니다.

▲ header2.jsp

<%@ page contentType="text/html; charset=euc-kr" %>
메뉴

▲ menu.jsp

<%@ page contentType="text/html; charset=euc-kr" %>
푸터

▲ footer.jsp

<%@ page contentType="text/html; charset=euc-kr" %>
푸터2

▲ footer3.jsp

 

 4-3. Definition을 사용하는 JSP (hello.jsp)

<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%
	//몸체 내용에서 보여줄 데이터 전달
	request.setAttribute("greeting", "안녕하세요");
%>
<!-- "hello" Definition 삽입 -->
<tiles:insertDefinition name="hello" />

"hello" Definition

<tiles:insertDefinition name="hello" /> 코드는 현재 위치에 layout.jsp를 삽입하고

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

 4-4. "body" 어트리부트 위치에 삽입 되는 hello_body.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<strong>${greeting}</strong> 고객님.
<hr/>
사이트에 오신 걸 환영합니다.

 

hello.jsp 실행 결과
hello.jsp의 <tiles:insertDefinition> 태그의 name 값을 hello2로 바꾼 결과

 

 

5) ViewPreparer를 이용한 뷰 데이터 설정

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

ViewPreparer 인터페이스는 모든 페이지에서 공통으로 사용되는 상단, 좌측 메뉴, 하단 등의 화면을 출력하는데 필요한 데이터를 생성하는 용도로 사용한다.

 

void execute(TilesRequestContext tilesContext, AttributeContext attrContext)

ViewPreparer 인터페이스는 execute() 메소드를 선언한다.

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

 

package tiles;

public class MenuItem {
	private String name;
	private String link;
	
	public MenuItem(String name, String link) {
		this.name=name;
		this.link=link;
	}

	public String getName() {
		return name;
	}

	public String getLink() {
		return link;
	}
}
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 implements ViewPreparer {
	
	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"));
		//jsp에 삽입한 "userMenues"의 userMenus 데이터가 전달
		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"));
		//1. "adminMenus": 전달할 데이터의 이름
		//2. adminMenus를 갖는 Attrinute 객체
		//3. 추가한 데이터를 전파 할지의 여부
		attrContext.putAttribute("adminMenus", new Attribute(adminMenus), true);
	}
}

 

 5-1. tiles-hello.xml 설정 파일에 추가 작성

<definition name="home" template="/tiles/template/layout.jsp" preparer="ssol.tiles.MenuViewPreparer">
	<put-attribute name="title" value="헬로우 월드: 홈" />
	<put-attribute name="header" value="/tiles/template/header.jsp" />
	<put-attribute name="menu" value="/tiles/template/home_menu.jsp" />
	<put-attribute name="body" value="/tiles/home_body.jsp" />
	<put-attribute name="footer" value="/tiles/template/footer.jsp" />
</definition>

 

6-4. 템플릿의 각 구성요소에 삽입된 JSP

<%@ page contentType="text/html; charset=euc-kr" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:forEach var="menu" items="${userMenus}">
${menu.name}<br/>
</c:forEach>

<tiles:importAttribute name="adminMenus" />
<c:forEach var="menu" items="${adminMenus}">
${menu.name}<br/>
</c:forEach>

▲home_menu.jsp

<%@ page contentType="text/html; charset=euc-kr" %>
홈 페이지의 내용

▲home_body.jsp

<%@ page contentType="text/html; charset=euc-kr" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<tiles:insertDefinition name="home" />

▲home.jsp

 

 

6) TilesDispatcherServlet을 이용한 Tiles 사용

TilesDispatcherServlet를 사용하면 웹 요청 URI와 동일한 이름을 갖는 Definition을 바로 클라이언트에 출력할 수 있다.

 

6-1. web.xml 파일에 작성

<servlet>
	<servlet-name>TilesDispatchServlet</servlet-name>
	<servlet-class>
		org.apache.tiles.web.util.TilesDispatchServlet
	</servlet-class>
</servlet>
	
<servlet-mapping>
	<servlet-name>TilesDispatchServlet</servlet-name>
	<url-pattern>*.tiles</url-pattern>
</servlet-mapping>
  • <servlet> 태그를 이용해서 TilesDispatcherServlet을 web.xml 파일에 등록
  • <servlet-mapping>을 이용해서 TilesDispatcherServlet이 처리할 확장자 설정

URI의 확장자가 .tiles인 경우 TilesDispatcherServlet이 요청을 처리 하도록 설정함 

TilesDispatcherServlet은 요청 URI에서 확장자를 제외한 나머지 URI를 Definition의 이름으로 사용하는데 콘텍스트 경로는 제외 된다.

 

6-2. tiles 설정파일 작성 (tiles-service.xml)

<?xml version="1.0" encoding="euc-kr"?>
<!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>
	<definition name="help.home" template="/tiles/template/layout_help.jsp">
		<put-attribute name="title" value="도움말 홈" />
		<put-attribute name="header" value="/tiles/template/header_help.jsp" />
		<put-attribute name="menu" value="/tiles/template/menu_help.jsp" />
		<put-attribute name="body" value="/tiles/help/help_home.jsp" />
		<put-attribute name="footer" value="/tiles/template/footer_help.jsp" />
	</definition>
</tiles-definitions>

 

6-3. 레이아웃 템플릿 (layout_help.jsp)

<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<html>
<head>
<title><tiles:getAsString name="title"/></title>
</head>
<body>
<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tr>
	<td colspan="2">
	<tiles:insertAttribute name="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>

 

6-4. 템플릿의 각 구성요소에 삽입된 JSP

<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
안내 페이지 홈 | FAQ

▲header_help.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
메뉴

▲menu_help.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
안내 페이지입니다.

▲help_home.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
도움말 페이지가 도움이 되셨나요?

▲footer_help.jsp

 

*콘텍스트 경로를 제외하고 URL을 .tiles 로 실행한 결과

help.home.tiles
help.tiles
help2.tiles
home.tiles

 

 

댓글