본문 바로가기
Dev/Spring

스프링 Tiles 2 연동을 이용한 레이아웃 템플릿 처리

by vellahw 2022. 10. 20.

 

 

다수의 웹 페이지는 동일한 페이지 구성을 갖고 있다. 각각의 페이지가 상단과 하단은 동일한 내용을 출력하고 내용 부분만 각자 알맞은 내용을 출력하는 경우가 많다.

레이아웃이 동일하고 공통된 내용이 들어가는 영역이 많은 경우에는 Tiles와 같은 템플릿 Library를 사용해서 레이아웃을 처리하면 뷰 관련 코드에서 레이아웃을 처리하기 위한 코드의 중복을 제거할 수 있다는 장점이 있다.

SPRING은 널리 사용되고 있는 템플릿 Library인 Tiles2 버전을 지원하고 있다.

 

🎈 Tiles 2 연동하기

Tiles 2 연동을 위해서는 다음의 jar 파일을 lib 디렉터리에 추가해 주어야 한다.

  • tiles-api-2.1.x.jar, tiles-core-2.1.x.jar, tiles-jsp-2.1.x.jar
    commons-beanutils.jar, commons-digester.jar, commons-logging.jar
    SPRING webmvc Module

 

SPRING 설정 파일에 다음의 두 가지 내용 또한 설정해야 한다.

  • TilesConfigurer를 이용하여 Tiles 2 레이아웃 설정 파일 명시
  • UrlBasedViewResolver의 viewClass 프로퍼티를 TilesView로 지정

 

 

💡. Tiles 2 연동을 이용한 레이아웃 템플릿 처리 예제 : 로그인 폼

 

1) web.xml 파일에 servlet 설정 추가

1
2
3
4
5
6
7
8
9
10
<servlet>
    <servlet-name>dispatcherTiles2</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
 
<servlet-mapping>
    <servlet-name>dispatcherTiles2</servlet-name>
    <url-pattern>/tiles2/*</url-pattern>         
</servlet-mapping>
cs

 

2) Tiles2 설정 파일 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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>
    <definition name="base_layout" template="/WEB-INF/viewtiles2/template/layout.jsp"
                preparer="menuPreparer">
        <put-attribute name="header" value="/WEB-INF/viewtiles2/template/header.jsp" />
        <put-attribute name="footer" value="/WEB-INF/viewtiles2/template/footer.jsp" />
    </definition>
    <definition name="loginForm" extends="base_layout">
        <put-attribute name="title" value="로그인폼" />
        <put-attribute name="body" value="/WEB-INF/viewtiles2/loginForm.jsp" />
    </definition>
    <definition name="loginSuccess" extends="base_layout">
        <put-attribute name="title" value="로그인 성공" />
        <put-attribute name="body" value="/WEB-INF/viewtiles2/loginSuccess.jsp" />
    </definition>
<tiles-definitions>
cs

▲/WEB-INF/tiles2def/tilesdef.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    <bean class="controller.LoginController">
            <property name="authenticator">
                <bean class="controller.MockAuthenticator" />
            </property>    
        </bean>
 
    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>messages.validation</value>
                <value>messages.label</value>
            </list>
        </property>    
    </bean>
    
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
        <property name="alwaysUseFullPath" value="false" />
    </bean>
    
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="alwaysUseFullPath" value="false" />    
        <property name="cacheSeconds" value="0" />
    </bean>
    
    <bean id="tilesConfigurer"
        class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles2def/tilesdef.xml</value>
            </list>
        </property>    
    </bean>
    
     <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView" />    
    </bean>
</beans>
cs

▲/WEB-INF/dispatcherTiles2-servlet.xml

TilesConfigurer 클래스와 TilesView 클래스는 모두 Tiles2 패키지에 포함된 클래스이다.

TilesConfigurer bean 객체는 definitions 속성을 이용해서 Tiles 설정 파일 목록을 전달받는다.

 

3) 커맨드 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package controller;
 
public class LoginCommand {
    
    private String id;
    private String password;
    private String loginType;
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getLoginType() {
        return loginType;
    }
    public void setLoginType(String loginType) {
        this.loginType = loginType;
    }
}
cs

 

4) 컨트롤러 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package controller;
 
import java.util.ArrayList;
import java.util.List;
 
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
@Controller
@RequestMapping("/login/login.do")
public class LoginController {
    
    private Authenticator authenticator;
 
    @ModelAttribute("login")
    public LoginCommand formBacking() {
        return new LoginCommand();
    }
    
    @RequestMapping(method = RequestMethod.GET)
    public String form() {
        return "loginForm";
    }
    
    @RequestMapping(method = RequestMethod.POST)
    public String submit(@ModelAttribute("login") LoginCommand loginCommand, BindingResult result) {
        new LoginCommandValidator().validate(loginCommand, result);
        
        if(result.hasErrors()) {
            return "loginForm";
        }
        
        try {
            authenticator.authenticate(loginCommand.getId(), loginCommand.getPassword());
            return "loginSuccess";
            
        } catch (AuthenticationException ex) {
            result.reject("invalidIdOrPassword"new Object[] { loginCommand.getId() }, null);
            return "loginForm";
        }
    }
    
    @ModelAttribute("loginTypes")
    protected List<String> referenceData() throws Exception {
        List<String> loginTypes = new ArrayList<String>();
        loginTypes.add("일반회원");
        loginTypes.add("기업회원");
        loginTypes.add("헤드헌터회원");
        return loginTypes;
    }
    
    public void setAuthenticator(Authenticator authenticator) {
        this.authenticator = authenticator;
    }
}
 
cs

▲controller.LoginController

1
2
3
4
5
6
7
8
9
10
11
package controller;
 
public class MockAuthenticator implements Authenticator {
 
    @Override
    public void authenticate(String id, String password) {
        if(!id.equals("codingco")) {
            throw new AuthenticationException("invalid id " + id);
        }
    }
}
cs

▲controller.MockAuthenticator

TilesView Class는 컨트롤러가 지정한 뷰 이름과 동일한 이름을 갖는 <definition> 태그를 사용하여 뷰를 생성한다.

LoginController 클래스에서 뷰 이름을 loginForm으로 지정했다. 이 경우 name 속성의 값이 loginForm인 태그의 정보를 사용한다.

즉, layout.jsp를 레이아웃 템플릿으로 사용하고, 헤더와 푸터에 각각 header.jsp와 footer.jsp를 삽입하고, 그리고 내용에는 loginForm.jsp를 사용하게 된다.

위에서 작성한 tilesdef.xml

 

5) 레이아웃 템플릿 파일 작성

레이아웃 템플릿 파일은 Tiles2가 제공하는 커스텀 태그를 이용하여 레이아웃 정보를 설정한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title><tiles:getAsString name="title"/></title>
</head>
<body>
<tiles:insertAttribute name="header" />
<hr/>
<tiles:insertAttribute name="body" />
<hr/>
<tiles:insertAttribute name="footer" />
</body>
</html>
cs

▲/template/layout.jsp

1
2
3
4
<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:forEach var="menu" items="${menuList}">${menu}></c:forEach> |
환영합니다!
cs

▲/template/header.jsp

1
2
<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
스프링 예제
cs

▲/template/footer.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title><spring:message code="login.form.title" /></title>
</head>
<body>
<form:form commandName="login">
<form:errors />
<p>
    <label for="loginType"><spring:message code="login.form.type" /></label>
    <form:select path="loginType" items="${loginTypes}" />
</p>
<p>
    <label for="id"><spring:message code="login.form.id" /></label>
    <form:input id="id" path="id" />
    <form:errors path="id" />
</p>
<p>
    <label for="password"><spring:message code="login.form.password" /></label>
    <form:password id="password" path="password" />
    <form:errors path="password" />
</p>
<p>
    <input type="submit" value="<spring:message code="login.form.submit" />">
</p>
</form:form>
</body>
</html>
cs

▲/viewtiles2/loginForm.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR" %> 로그인 성공 로그인에 성공했습니다.

▲/viewtiles2/loginSuccess.jsp

 

실행 결과 확인

 

MockAuthenticator 클래스에서 지정한 아이디로 로그인 했을 시 성공 화면으로 리턴됨

 

댓글