본문 바로가기

스프링 프레임워크/Spring+Oracle+MyBatis 게시판 프로젝트

[Spring] Spring + Tiles Framework 연동하기

[난 왜 Tiles Framework 란걸 찾게 되었는가?]
jsp파일로 화면을 구성하다보면 header/footer같은 공통적인 소스 들이 존재한다. 공통적인 부분은 jsp파일로 따로 분리하고, 각 화면에 해당하는jsp파일에 header/footer.jsp를 include하는 방식으로 중복되는 소스를 줄이는 방식을 이용한다.
그런데, 일단 각 화면jsp파일마다 모두 header/footer.jsp파일을 include해주는것도 귀찮지만 만약 페이지의 레이아웃이 바뀐다면 jsp파일 수 만큼 include를 수정해주는 작업을 해줘야하는 수고로움이 생긴다.

따라서! 각 화면jsp파일마다 따로 header/footer.jsp를 include해주지 않고 오로지 각 화면에 해당하는 소스만 작성하고 싶었고, 페이지의 레이아웃은 한 곳에서 설정하여 관리할 수 있도록 하고 싶었다. 이걸 가능하게 해주는게 Tiles Framework이다.



[Spring프로젝트에 Tiles Framework 적용방법]

요약하면 아래 순서대로 진행된다.

1. pom.xml에 관련 라이브러리 추가
2. servlet-context.xml에 view resolver 수정 및 추가, tiles관련 설정파일 경로 명시
   - Spring에서 DispatcherServlet이 view resolver를 통해 view단에 보여줄 화면을 구성하게 되는데, 이때 기존에  
     사용하던 InternalResourceViewResolver에서 UrlBasedViewResolver를 첫번째로 고려하도록 수정하는 것이다.
   - 브라우저에서 서버로 url호출시 처리 과정의 우선순위가 아래처럼 변경되는 것이다.
     url 호출 => @ReqeustMapping => Tiles ViewResolver => InternalResourceViewResolver

3. tiles.xml 설정파일 작성( tiles framework의 설정파일 )
4. 기본 템플릿이될 jsp 작성
5. 화면 테스트




1. pom.xml에 관련 라이브러리 추가

- <properties> 태그 안에 tiles 버전을 명시해준다. 

<properties>
	<java-version>1.8</java-version>
	<org.springframework-version>5.0.7.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
    <!-- tiles관련 추가  -->
    <org.apache.tiles-version>3.0.5</org.apache.tiles-version>		
</properties>

- tiles관련 라이브러리를 dependcy태그로 추가해준다.

<!-- Tiles Framework 관련 -->
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-servlet</artifactId>
  <version>${org.apache.tiles-version}</version>
</dependency>
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-api</artifactId>
  <version>${org.apache.tiles-version}</version>
</dependency>
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-jsp</artifactId>
  <version>${org.apache.tiles-version}</version>
</dependency>
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-core</artifactId>
  <version>${org.apache.tiles-version}</version>
</dependency> 
<dependency>
  <groupId>org.apache.tiles</groupId>
  <artifactId>tiles-template</artifactId>
  <version>${org.apache.tiles-version}</version>
</dependency> 
<!-- Tiles Framework 관련 -->

2. servlet-context.xml에 view rewolver 수정 및 추가, tiles관련 설정파일 경로 명시

- 기존 view resolver인 InternalResourceViewResolver의 우선순위를 첫번째가 아닌 2(두번째)로 바꿔준다.

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
    <!-- 기존 view resolver의 우선순위를 2로 해준다. -->
    <beans:property name="order" value="2" />
</beans:bean>

-tiles 관련 설정파일인 tiles.xml 경로 명시 및 UrlBasedViewResolver를 추가하고 우선순위를 1(첫번째)로 해준다.

<!-- Tiles 관련 추가 내용-->
<!-- Tiles관련 설정파일 -->
<beans:bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
    <beans:property name="definitions">
        <beans:list>
            <beans:value>/WEB-INF/tiles/tiles.xml</beans:value>
        </beans:list>
    </beans:property>
</beans:bean>        
<!-- Tiles의 우선순위를 1로 해준다. -->
<beans:bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <beans:property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
    <beans:property name="order" value="1" />
</beans:bean>


3. tiles.xml 설정파일 작성

<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
  "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
 
<tiles-definitions>

    <!-- 1. 기본적인 템플릿을 생성한다.
    	header, body, footer를 가진 teamplate.jsp라는 기본 레이아웃을 정의한다.
    	이 정의된 레이아웃의 name속성인 base를 상속하여 추가적으로 여러 tiles들을 만들수 있다.
    	
     -->
    <definition name="base" template="/WEB-INF/tiles/template.jsp">
        <put-attribute name="header" value="/WEB-INF/tiles/header.jsp" />
        <put-attribute name="body"   value="" />
        <put-attribute name="footer" value="/WEB-INF/tiles/footer.jsp" />
    </definition>
 
 	<!-- 2. base를 상속받은것.
 	즉, body부분만 설정한 경로대로 갈아 끼우고, 나머지 header, footer는 base의 형식대로 상속받아 오는 것이다. -->
    <definition name="*" extends="base">
        <put-attribute name="body" value="/WEB-INF/views/{1}.jsp" />
    </definition>

     <definition name="*/*" extends="base">
         <put-attribute name="body" value="/WEB-INF/views/{1}/{2}.jsp" />
     </definition>
    
    <definition name="*/*/*" extends="base">
        <put-attribute name="body" value="/WEB-INF/views/{1}/{2}/{3}.jsp" />
    </definition>
    
    
    <!-- 메뉴 미표시
    	: 페이지 중 로그인페이지 같은건 보통 header, footer모두를 레이아웃으로 가지지 않을 것이다.
    	다만, header에 js라이브러리등을 포함하고 있을 것이므로 이런 특정경로의 jsp파일들은 header만 상속받고 footer는 사용하지 않는 방식으로 할 수 있다.
     -->
    <definition name="baseEmpty" template="/WEB-INF/tiles/templateEmpty.jsp">
    </definition>
    
    <definition name="*.part" extends="baseEmpty">
        <put-attribute name="body" value="/WEB-INF/views/{1}.jsp" />
    </definition>
 
     <definition name="*/*.part" extends="baseEmpty">
         <put-attribute name="body" value="/WEB-INF/views/{1}/{2}.jsp" />
     </definition>
    
    <definition name="*/*/*.part" extends="baseEmpty">
        <put-attribute name="body" value="/WEB-INF/views/{1}/{2}/{3}.jsp" />
    </definition>        
    
</tiles-definitions>

 

4. 기본 템플릿 jsp파일 template.jsp 작성
위 3번에서 tiles.xml에서 <definition>태그에서 name속성에 작성한 header, footer에 해당하는 value값에 있는경로의
jsp파일이 <tiles:insertAttributes>태그의 name속성에 사용되는것이다.
즉, header, body, footer 라는 레이아웃으로 템플릿을 구성한 것이다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>제목</title>
</head>

<body>
 <%--    <div id="header"><tiles:insertAttribute name="header" /></div>
    <div id="body"><tiles:insertAttribute name="body" /></div>    
    <div id="footer"><tiles:insertAttribute name="footer" /></div>
  --%>
    <tiles:insertAttribute name="header" />
    <tiles:insertAttribute name="body" />    
    <tiles:insertAttribute name="footer" />
  
    <script type="text/javascript">
        $(function() {
 
        });    
    </script>    
</body>
</html>


5. 위 3번에서 작성한 footer.jsp와 header.jsp를 경로에 맞게 추해준다.


6.  화면에서 테스트
header, footer.jsp사이에 body부분에 해당하는 list.jsp파일이 위치한것을 확인할 수 있다.

참고로 아래 list.jsp 소스를 보면 header.jsp, footer.jsp를 include하는 부분이 없는걸 확인할 수 있다. 다만 목록을 보여주기위한 소스만 있게된다.

<%@ 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" %>

            <div class="row">
                <div class="col-lg-12">
                    <h1 class="page-header">BOARD LIST PAGE</h1>
                </div>
                <!-- /.col-lg-12 -->
            </div>      
            <!-- 등록버튼 -->
            <div class="row">
            	<div class="col-lg-12">
            		<button type="button" id="btnRegister" class="btn btn-outline btn-primary btn-xs pull-right">Register New Board</button>	
            	</div>
            </div>
            <div class="row">
            	<div class="col-lg-12">
            			<p></p>
            	</div>
            </div>
            <!-- /.row -->
            <div class="row">
                <div class="col-lg-12">
                    <div class="panel panel-default">

                        <!-- /.panel-heading -->
                        <div class="panel-body">
                            <table width="100%" class="table table-striped table-bordered table-hover">
                                <thead>
                                    <tr>
                                        <th>#번호</th>
                                        <th>제목</th>
                                        <th>작가</th>
                                        <th>내용</th>
                                        <th>업데이트일자</th>
                                        <th>등록일자</th>
                                    </tr>
                                </thead>
                                <tbody>
	                                <c:forEach var="board" items="${boardList}">
									    <tr>
									    	<td><c:out value="${board.bno}" /></td>
									    	<td><a href="#"><c:out value="${board.title}" /></a></td>
									    	<td><c:out value="${board.writer}" /></td>
									    	<td><c:out value="${board.content}" /></td>
									    	<td><fmt:formatDate pattern ="yyyy-MM-dd hh:mm:ss" value="${board.updateDate}" /></td>
									    	<td><fmt:formatDate pattern ="yyyy-MM-dd hh:mm:ss" value="${board.regDate}" /></td>	
									    </tr>
									</c:forEach>
                                </tbody>
                            </table>
                        </div>
                        <!-- /.panel-body -->
                    </div>
                    <!-- /.panel -->
                </div>
                <!-- /.col-lg-12 -->
            </div>
            <!-- /.row -->

	<script src="/resources/js/board/list.js"></script>	
    

 

각 jsp파일에서 사용하는 js파일의 경우 가장 하단에 script태그로 포함시키고 있다. 이 또한 따로 각 jsp파일마다 명시해주지 않아도 되도록 세팅을 하는 방법을 찾아봐야할 것 같다.