이 글은 Spring 프레임워크로 개인프로젝트를 만들기위해 tiles3를 적용하는 과정을 정리한 글이다.
개발환경
windows10
spring4
java1.8
tomcat9
tiles3
jsp + bootstrap
사실 tiles3 글을 쓰고 있지만, 난 tiles3를 포기하고 Handlebars 나 Thymeleaf를 좀 파보고 적당한 것을 골라 이번 스프링 프로젝트의 레이아웃으로 적용할 예정이다.
tiles3를 적용하고 내가 경험한 문제점은 특정 tile의 갱신, 즉 메뉴를 클릭했을때 컨텐츠 부분만 갱신하게 만들기 위해서 불필요한 자바스크립트 로직이 들어가게 된다.
더 큰 문제는 자바스크립트 함수를 이용하여 콘텐츠 영역만 갱신하게 되었을때, 내가 적용한 bootstrap 테마가 정상 동작하지 않는다.
아마 렌더링 될때 뷰포트 등에서 문제가 발생하는 듯하다.(내가 공부가 부족해서 스스로 해결하기 포기했다.)
다만 나중에 tiles를 쓸일이 생길수도 있기 때문에 이렇게 기록한다. (bootstrap을 쓰지 않던가, 컨텐츠 영역만 갱신되게 할 필요가 없다면 충분히 쓸만하다고 생각하다.)
tiles 레이아웃 적용전 유의점 tiles는 레이아웃을 나눌수 있게 해주지만, 컨트롤러가 타일즈 뷰를 렌더링할 때 실질적으로 바뀌는 부분과 바뀌지 않는 부분 모두 새로 랜드링 한다. 따라서 레이아웃의 특정 부분만, 예를 들어 body나 content 부분만 갱신하기를 원한다면 tiles레이아웃을 피하길 바란다.
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --> <beans:beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"> <beans:propertyname="prefix"value="/WEB-INF/views/" /> <beans:propertyname="suffix"value=".jsp" /> <beans:propertyname="order"value="2" /><!-- tiles3 설정 --> </beans:bean>
위에서 말했듯이 tiles의 레이아웃을 정의하는 설정 파일이다. 내 경우에는 아래 처럼 설정했다. biz-template 와 sample-template 라는 두 종류의 tiles템플릿을 동시에 사용하게 설정했다. 사실 템플리 jsp는 biz_template.jsp로 동일하지만 메뉴정보를 달리 하기 위해서 템플릿을 두개로 나눠놨다.
biz_template.jsp는 레이아웃 구조를 잡고 있는 중심 jsp 파일이다. head, left-side, footer는 기본적으로 변하지 않는 고정된 부분이고, content 부분이 변경되는 부분이다.
<!DOCTYPE html> <!-- This is a starter template page. Use this page to start your new project from scratch. This page gets rid of all links and provides the needed markup only. --> <html lang="kr"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title><tiles:getAsString name="title" /></title> <!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <link rel="stylesheet" href="<c:url value='/resources/bower_components/bootstrap/dist/css/bootstrap.min.css' />"> <!-- Font Awesome --> <link rel="stylesheet" href="<c:url value='/resources/bower_components/font-awesome/css/font-awesome.min.css' />"> <!-- Ionicons --> <link rel="stylesheet" href="<c:url value='/resources/bower_components/Ionicons/css/ionicons.min.css' />"> <!-- Theme style --> <link rel="stylesheet" href="<c:url value='/resources/dist/css/AdminLTE.min.css' />"> <!-- AdminLTE Skins. We have chosen the skin-blue forthis starter page. However, you can choose any other skin. Make sure you apply the skin classtothebodytagsothechangestakeeffect. --> <linkrel="stylesheet" href="<c:url value='/resources/dist/css/skins/skin-blue.min.css' />">
<!-- Google Font --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic"> </head> <!-- BODY TAG OPTIONS: ================= Apply one or more of the following classes to get the desired effect |---------------------------------------------------------| | SKINS | skin-blue | | | skin-black | | | skin-purple | | | skin-yellow | | | skin-red | | | skin-green | |---------------------------------------------------------| |LAYOUT OPTIONS | fixed | | | layout-boxed | | | layout-top-nav | | | sidebar-collapse | | | sidebar-mini | |---------------------------------------------------------| --> <body class="hold-transition skin-blue sidebar-mini"> <div class="wrapper">
<tiles:insertAttribute name="header" />
<tiles:insertAttribute name="left-side" />
<!-- content 위치 --> <div id="bodyTile"><tiles:insertAttribute name="content" /></div>
<!-- mainfooter 위치 --> <tiles:insertAttribute name="footer" />
<!-- Control Sidebar 모바일 모드일때 사이즈 변경을 위한 바 --> <aside class="control-sidebar control-sidebar-dark"> <!-- Create the tabs --> <ul class="nav nav-tabs nav-justified control-sidebar-tabs"> <li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li> <li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li> </ul> <!-- Tab panes --> <div class="tab-content"> <!-- Home tab content --> <div class="tab-pane active" id="control-sidebar-home-tab"> <h3 class="control-sidebar-heading">Recent Activity</h3> <ul class="control-sidebar-menu"> <li> <a href="javascript:;"> <i class="menu-icon fa fa-birthday-cake bg-red"></i>
<div class="menu-info"> <h4 class="control-sidebar-subheading">Langdon's Birthday</h4> <p>Will be 23 on April 24th</p> </div> </a> </li> </ul> <!-- /.control-sidebar-menu --> <h3 class="control-sidebar-heading">Tasks Progress</h3> <ul class="control-sidebar-menu"> <li> <a href="javascript:;"> <h4 class="control-sidebar-subheading"> Custom Template Design <span class="pull-right-container"> <span class="label label-danger pull-right">70%</span> </span> </h4> <div class="progress progress-xxs"> <div class="progress-bar progress-bar-danger" style="width: 70%"></div> </div> </a> </li> </ul> <!-- /.control-sidebar-menu --> </div> <!-- /.tab-pane --> <!-- Stats tab content --> <div class="tab-pane" id="control-sidebar-stats-tab">Stats Tab Content</div> <!-- /.tab-pane --> <!-- Settings tab content --> <div class="tab-pane" id="control-sidebar-settings-tab"> <form method="post"> <h3 class="control-sidebar-heading">General Settings</h3> <div class="form-group"> <label class="control-sidebar-subheading"> Report panel usage <input type="checkbox" class="pull-right" checked> </label> <p> Some information about this general settings option </p> </div> <!-- /.form-group --> </form> </div> <!-- /.tab-pane --> </div> </aside> <!-- /.control-sidebar --> <!-- Add the sidebar's background. This div must be placed immediately after the control sidebar --> <div class="control-sidebar-bg"></div> </div> <!-- ./wrapper -->
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <!-- Optionally, you can add Slimscroll and FastClick plugins. Both of these plugins are recommended to enhance the user experience. --> </body> </html>
아래는 내용은 tiles를 통해 template.jsp의 title내용을 변경하는 부분이다. tiles는 동적으로 페이지의 구조를 바꾼다. 따라서 때에 따라 페이지의 title내용을 변경해줄 필요가 있다.
1
<title><tiles:getAsString name="title" /></title>
그리고 실제로 tiles 조각들이 채워질 공간은 아래이다. header, left-side, content, footer 총 4부분이다. left-side에 메뉴가 존재하며 메뉴를 클릭했을때 content 부분이 교체되는 형태이다. 주의할 점은 content tiles부분이 bodyTile이라는 div 태그로 감싸여 있는데, 이것은 left-side에서 메뉴를 클릭했을때 header, left-side, content, footer 모든 타일들이 refresh가 되는 것이 아니라 content 부분만 갱신하기 위한 태그이다.
1 2 3 4 5 6 7 8 9
<tiles:insertAttribute name="header" />
<tiles:insertAttribute name="left-side" />
<!-- content 위치 --> <div id="bodyTile"><tiles:insertAttribute name="content" /></div>
<!-- mainfooter 위치 --> <tiles:insertAttribute name="footer" />
4.tiles 템플릿을 채워줄 공통 타일 header.jsp, footer.jsp, left_side.jsp를 생성하자.
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!-- Left side column. contains the logo and sidebar --> <aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less --> <section class="sidebar">
이 부분이 메뉴 링크 부분이다. switchContent 함수는 스프링 컨트롤러에게 content 페이지를 요청할때, 모든 타일 header, footer, left-side, content들을 refresh하는 것이 아니라 content 타일만 갱신하기 위한 함수이다. switchContent 자바스크립트 함수를 보면 bodyTile div 태그의 내부를 지우고 대신 content 페이지를 요청하여 렌더링 결과인 html을 대신 채워준다. 위 처럼 하면 content 타일만 refresh가 된다.
5.Controller
tiles에서 가장 중요하다고 생각하는 부분은 tiles.xml과 controller이다. 그 이유는 controller가 뷰 리졸버로 전달하는 명칭에 의해 해당 뷰를 타일즈를 통해 렌더링 할 것인가의 여부, 만약 타일즈를 통해 렌더링 한다면 어떤 타일즈 템플릿을 적용하는 지가 결정 되기 때문이다.
위 컨트롤러의 마지막 read2를 보면 이 녀석만 독특하게 sample로 시작하는 뷰를 찾는다. 내 tiles.xml 파일을 보면 sample로 시작하는 타일즈 템플릿은 없다. 즉 이 녀석은 타일즈 리졸버를 거치지 않고 스프링의 내장 리졸버에 의해 렌더링 된 뷰가 화면단에 전달 된다.
//2.아래 자바스크립트가 대신 컨트롤러에 /sample/board/read2을 요청하여 그 결과물(타일즈가 적용되지 않은 내장 뷰 리졸버 html결과물)을 받아 function switchContent(url){ $('#bodyTile').children().remove(); $('#bodyTile').load(url); }
//3.template-biz.jsp 파일의 bodyTile태그 내용물을 대체한다. <!-- content 위치 --> <div id="bodyTile"><tiles:insertAttribute name="content" /></div>
개인적인 생각으로, 만약 레이아웃의 여러 부분중 특정 부분만 갱신되게 해야 한다면 tiles 레이아웃은 비추한다.