오늘은 tiles 설정을 하면서 애를 먹었던 일기를 작성해보려고 한다. 이 글이 tiles 설정을 하려는 사람들에게 도움이 될 수 있으면 좋겠다.
tiles란?
화면의 레이아웃을 지정하여 공통으로 쓰이는 코드를 개별로 작성하지 않고 적용 및 관리를 편리하게 할 수 있도록 해주는 템플릿 엔진입니다.
tiles 설정 1. pom.xml에 관련 dependency 추가(버전 통일)
//pom.xml
<!-- JSP, JSTL 설정 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>11.0.0-M24</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- tiles 설정 -->
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-core</artifactId>
<version>3.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>3.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-servlet</artifactId>
<version>3.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-extras</artifactId>
<version>3.0.8</version>
</dependency>
jstl 로 jsp 파일에서 tiles 위치를 잡아주고 있기 때문에 같이 넣어주는 게 좋다.
tiles-extras 는 없어도 괜찮지만 completeAutoLoad 관련 에러가 발생한다면 해당 dependency를 추가해서 정의를 해줘야하는데 자세한 내용은 관련 소스와 함께 아래에서 설명할 예정!
이렇게 dependency를 추가했다면 tiles 관련 bean을 설정해줘야 하는데 dispatcher-servlet.xml 에도 무관하지만 나는 따로 파일을 만들었다. (이게 삽질의 원인이 될 줄은 꿈에도 몰랐지만..)
tiles 설정 2. tiles configurer 와 UrlBasedViewResolver 설정
//context-tiles.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- tiles 설정 : JSP head 태그 공통화 -->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/config/spring/tiles-definitions.xml</value>
</list>
</property>
<!-- completeAutoLoad 속성제거 -->
<property name="checkRefresh" value="true" />
</bean>
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
<property name="order" value="1" />
</bean>
</beans>
tiles의 ViewResolver는 UrlBasedViewResolver로 설정해줘야 한다. tilesConfigurer 는 tiles의 레이아웃 즉 header, body, footer 설정을 담고 있는 파일 tiles-definitions.xml 을 지정해주면 된다.
위 코드로 적용했는데 의존성이 없다는 에러가 난다면 pom.xml의 tiles-extras 라는 의존성이 있는지 확인하자.
없다면 checkRefresh 라는 프로퍼티는 지워야한다. 이 프로퍼티는 tiles-extras 에 있는 속성이기 때문에 확인 필수!
tiles 설정 3. tiles-definitions.xml 파일
//tiles-definitions.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<definition name="defaultTemplate" template="/WEB-INF/views/layout/default.jsp">
<put-attribute name="header" value="/WEB-INF/views/layout/header.jsp" />
<put-attribute name="body" value="" />
<put-attribute name="footer" value="/WEB-INF/views/layout/footer.jsp" />
</definition>
<!-- <definition name="mainPage" extends="defaultTemplate">
<put-attribute name="body" value="/WEB-INF/views/main/login.jsp" />
</definition>
-->
<definition name="/*/*" extends="defaultTemplate">
<put-attribute name="body" value="/WEB-INF/views/{1}/{2}.jsp" />
</definition>
</tiles-definitions>
mainPage 이 부분은 테스트용으로 기재했으며 controller 에서 return 값을 "mainPage"로 했을 때 적용되는 걸 볼 수 있었다. 하지만 나는 유동적으로 변경이 되길 바랬기 때문에 definition name="/*/*" 로 설정해서 {1}, {2} 로 유동적으로 값이 바뀔 수 있도록 지정했다.
즉, definition name == controller or modelandview setViewname 값
이렇게 3가지 설정이 끝났다면 이제 레이아웃의 jsp 파일을 만들 차례!
tiles 설정 4. 레이아웃 jsp 파일 만들기
//default.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<!DOCTYPE html>
<html>
<head>
<tiles:insertAttribute name="header" />
</head>
<body>
<tiles:insertAttribute name="body" />
<tiles:insertAttribute name="footer" />
</body>
</html>
//header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<!-- 공통 css, js -->
<link rel="stylesheet" type="text/css" href="/resources/css/style.css">
<script type="text/javascript" src="/resources/js/common.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<!-- favicon error 대체 -->
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
//footer.jsp
</html>
이렇게 각 3개의 파일을 만들면 되는데 제일 중요한 건 default.jsp
tiles 태그 라이브러리를 추가한 뒤에 jstl 태그로 입력해준다. 이걸 위해서 pom.xml 에 jstl dependency가 있어야함 없다면 꼭 추가!
tiles설정 4. dispatcher-servlet.xml 이 아닌 따로 tiles 설정파일을 만들었다면 dispatcher-servlet.xml 에 import 시켜줘야함!
//dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 스프링 어노테이션 활성화 -->
<mvc:annotation-driven />
<!-- 인터셉터 로그 기록을 위해 설정 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.spring.interceptor.LogInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
<!-- js, css 매핑 -->
<mvc:resources location="/resources/" mapping="/resources/**" />
<context:component-scan base-package="com.spring">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
<property name="order" value="2" />
</bean>
<!-- jsonview 설정 -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="0" />
</bean>
<bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
<property name="contentType" value="application/json;charset=UTF-8"></property>
</bean>
<!-- tiles 설정 -->
<!-- viewResolver 순서 JsonView -> UrlBased -> Internal -->
<import resource="/spring/context-tiles.xml" />
</beans>
아래 쪽에 tiles 설정 처럼 import 시켜줘야한다. 그리고 순서도 굉장히 중요한데,
tiles 뷰리졸버는 jsp 보다 먼저, jsonView 보다는 나중에 적용이 되어야 하기 때문에 순서는
JsonView 0 -> UrlBased 1 -> Internal 2 이렇게 지정을 해줘야한다. 이렇게 글로만 쓰면 애매할 것 같아 해당 부분만 아래 모은 건 이렇다.
<!-- jsonview order : 0 -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="0" />
</bean>
<bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
<property name="contentType" value="application/json;charset=UTF-8"></property>
</bean>
<!-- tilesViewResolver order : 1 -->
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
<property name="order" value="1" />
</bean>
<!-- JSP ViewResolver order : 2 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
<property name="order" value="2" />
</bean>
적용된 Login.jsp 와 LoginController.java 공유
//login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<!-- 페이지 전용 js -->
<script type="text/javascript" src="/resources/js/main/login.js"></script>
</head>
<body>
<form id="pageForm" action="/main/userLogin" method="post">
<div class="pageDiv">
<label for="userId">ID</label>
<input type="text" id="userId" name="userId">
<label for="userPw">PW</label>
<input type="password" id="userPw" name="userPw">
<button id="loginBtn" type="submit">login</button>
</div>
</form>
</body>
</html>
//LoginController.java
package com.spring.main.controller;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.spring.main.service.LoginService;
@Controller
public class LoginController {
private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
@Autowired
private LoginService service;
@RequestMapping("/")
public ModelAndView home() {
ModelAndView mv = new ModelAndView();
mv.setViewName("/main/login");
return mv;
}
@RequestMapping("/main/userLogin")
public ModelAndView userLogin(@RequestParam Map<String, Object> paramMap, HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = new ModelAndView();
Boolean result = service.userLogin(paramMap);
if(result) {
mv.setViewName("redirect:/board/boardMain");
}else {
mv.setViewName("redirect:/main/login");
mv.addObject("login failed");
}
return mv;
}
}
mv.setViewName("/main/login") -> 이렇게 하면 tiles-definitions.xml 의 {1} 은 main, {2} 는 login 이런 식으로 적용이 되는 걸 알 수 있다.
이렇게 테스트 하면 적용이 잘되는 걸 알 수 있다!
그동안 tiles 설정파일을 따로 만든다면 dispatcher-servlet.xml 에 import를 해줘야하는 지 모르고 삽질을 굉장히 오래했었다.. web.xml 에 정의했던 context-*.xml 로 다 적용이 되는 줄로만 알고있었는데..
그렇게 새롭게 알게된 사실도 있고 내 힘으로 설정을 해냈다는게 굉장히 뿌듯!
tiles 설정을 하려는 사람들에게 도움이 될 수 있기를!
'IT 개발 > BackEnd' 카테고리의 다른 글
[Eclipse/Spring] ModelAndView를 이용한 페이지 이동 방법 (1) | 2025.03.26 |
---|---|
[Eclipse/Spring] 프로젝트 세팅하기(JDK17/SPRING 6/tomcat 10) (2) | 2025.03.20 |
[SpringBoot] Spring Security 학습법 & 실무 적용 방법 (0) | 2025.03.07 |
[SpringBoot] H2 연동을 위한 dependency 및 properties (0) | 2025.02.21 |
[SpringBoot] JSP 파일 수정 후 새로고침시 적용 안될 경우 (3) | 2025.02.18 |