티스토리 뷰

Springboot에서 지원을 하는 Template Engine은 Thymeleaf, Freemarker, Velocity 등이 있다. 이중 freemarker로 프로젝트 구성을 하게 되었다. freemarker 자체만으로 Tiles에서 하는 화면 구성을 해줄수도 있지만 기존의 잘 짜여진 tiles 구조와 설정 등을 그대로 들고 오기 위해 freemarker와 tiles를 결합한 구성이 필요했다. 생각보다는 쉽지 않았다. 


1. dependency 추가

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-freemarker</artifactId>
    <version>3.0.8</version>
</dependency>
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-extras</artifactId>
    <version>3.0.8</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

freemarker만 단독으로 쓴다 했을때는 spring-boot-starter-freemarker 를 끼고 사용을 하면 되는데 tiles와 결합해서 사용을 하려면 위와 같은 dependency 추가가 필요하다. tomcat-embed-jasper와 jstl은 taglib 사용을 위해 어느 경우에나 필요하다. 

 

2. tiles-layout.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="main" template="/WEB-INF/freemarker/layout/main.ftl" templateType="freemarker">
        <put-attribute name="toparea" value="/WEB-INF/freemarker/layout/toparea.ftl" />
        <put-attribute name="contents" value="/WEB-INF/freemarker/layout/contentarea.ftl" />
        <put-attribute name="bottomarea" value="/WEB-INF/freemarker/layout/bottomarea.ftl" />
    </definition>
    
    <definition name="WILDCARD:freemarker.*" extends="main" templateType="freemarker">
        <put-attribute name="contents" value="/templates/freemarker/{1}.ftl" />
    </definition>
    
    <definition name="WILDCARD:freemarker.*/*" extends="main" templateType="freemarker">
        <put-attribute name="contents" value="/templates/freemarker/{1}/{2}.ftl" />
    </definition>
</tiles-definitions>

그다음은 화면 구성을 담당하는 tiles-layout.xml 을 작성해본다. (필자는 쉽게 porting하기 위해 WEB-INF 아래에 위와 같은 파일들을 위치시켰지만 이런 구조를 하지 않아도 되며 resources 하위에만 있으면 된다.)

전체 화면을 main 이라고 정의하였고 이것은 main.ftl 이라는 template으로 구현을 해놨다고 보면 된다. main 하위에는 top, content, bottom이 있고 각 ftl로 정의를 해놓았다. 그리고 중요한건 4째줄에 main을 정의할때 templateType="freemarker" 를 꼭 작성해주어야한다. 

 

10번째줄은 contents를 어떻게 구성을 할지에 대한 정의이다. main을 extends 받아서 contents 부분만 override 하는것이다. 즉 freemarker.hello 라는 view를 요청받았을때 /templates/freemarker/hello.ftl 이라는 페이지로 연결해주는 역할을 한다. wildcard가 2개인 경우는 14번째줄을 참고하고 더 depth가 깊어진다면 */*/*/*, {1}/{2}/{3}/{4} 이런식으로 여러개의 definition을 정의해놓으면 된다. 

 

3. 각 layout 작성

main.ftl

<#assign tiles=JspTaglibs["http://tiles.apache.org/tags-tiles"]>

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="utf-8">
</head>
<body>
    <@tiles.insertAttribute name="toparea"/>
    <@tiles.insertAttribute name="contents"/>
    <@tiles.insertAttribute name="bottomarea"/>
</body>

</html>

main, 즉 화면 구성은 top, content, bottom 으로 구성한다는 뜻이다. @tiles 라는 tag를 사용하기 위해 맨 윗줄과 같이 JspTaglibs를 활용한다. 

 

toparea.ftl

<!DOCTYPE html>
<html lang="ko">
<body>
==================================================================================<br/>
this is top area<br/>
==================================================================================<br/>
</body>
</html>

contentarea.ftl

<!DOCTYPE html>
<html lang="ko">
<body>

</body>
</html>

bottomarea.ftl

<!DOCTYPE html>
<html lang="ko">
<body>
==================================================================================<br/>
this is bottom area<br/>
==================================================================================<br/>
</body>
</html>

이런식으로 각 화면구성을 담당하는 부분들에 대해 각각 정의하였다.

기대하는바는 freemarker.hello 라는 view 요청이 들어오면 이건 <definition name="WILDCARD:freemarker.*" 부분에서 받아줄것이고 이 definition은 main을 extends 하고 있으므로 위의 top, content, bottom 구성을 다 가지고 오고 그중에서 content는 hello.ftl로 갈아치는것이다. 

 

4. Config 파일 작성

spring-boot-starter-freemarker를 사용하는 방식과 설정이 다르다. spring-boot-starter-freemarker를 사용한다면 application.yml (or properties)에서 하는 정의만으로 설정을 할 수 있지만 tiles와 freemarker를 같이 사용하다보니 설정을 하는데 있어서 어려움이 있었다. 다음과 같은 방식으로 설정을 해준다. 

 

FreeMarkerConfig.java

@Configuration
public class FreeMarkerConfig {

    @Bean
    public UrlBasedViewResolver tilesViewResolver() {
        UrlBasedViewResolver urlBasedViewResolver = new UrlBasedViewResolver();
        urlBasedViewResolver.setViewClass(TilesView.class);
        return urlBasedViewResolver;
    }

    @Bean
    public TilesConfigurer tilesConfigurer() {
        TilesConfigurer tilesConfigurer = new TilesConfigurer();
        tilesConfigurer.setCompleteAutoload(true);
        tilesConfigurer.setDefinitions("classpath*:/META-INF/resources/WEB-INF/freemarker/layout-definition/tiles-layout.xml");
        tilesConfigurer.setTilesInitializer(new CompleteAutoloadTilesInitializer() {
            @Override
            protected AbstractTilesContainerFactory createContainerFactory(ApplicationContext context) {
                return new CompleteAutoloadTilesContainerFactory() {
                    @Override
                    protected void registerAttributeRenderers(BasicRendererFactory rendererFactory, ApplicationContext applicationContext, TilesContainer container, AttributeEvaluatorFactory attributeEvaluatorFactory) {
                        super.registerAttributeRenderers(rendererFactory, applicationContext, container, attributeEvaluatorFactory);
                        FreemarkerRendererBuilder freemarkerRenderer = FreemarkerRendererBuilder.createInstance();
                        freemarkerRenderer.setApplicationContext(applicationContext);
                        freemarkerRenderer.setParameter("ContentType", "text/html;charset=UTF-8");
                        freemarkerRenderer.setParameter("default_encoding", "UTF-8");
                        freemarkerRenderer.setParameter("ClasspathTlds", "/META-INF/tld/tiles-jsp.tld, /META-INF/spring.tld");
                        rendererFactory.registerRenderer("freemarker", freemarkerRenderer.build());
                    }
                };
            }
        });
        return tilesConfigurer;
    }
}

UrlBasedViewResolver를 선언해서 view 요청이 오면 TilesView에서 처리를 하게 해주고 TilesConfig에서는 기존에 definition 설정만 하던것과는 다르게 TilesInitializer를 해줘야 한다. 즉 tiles가 freemarker라는것으로 매핑이 될 수 있도록 해줘야 한다. 28번째줄에 있는 freemarker는 tiles-layout.xml 작성시 templateType과 일치가 되어야한다. 이렇게 해줘야지 tiles와 freemarker를 동시에 사용할 수 있다. 

 

5. Controller 작성

@Controller
public class FreemarkerController {
    
    private static final String FREEMARKER_FLAG = "freemarker.";
    
    @GetMapping(value ="/hello")
    public String hello(Map<String, String> model) {
        model.put("message", "hello freemarker!");
        return FREEMARKER_FLAG + "hello";
    }
}

그다음은 sample controller 작성이다. 일반적인 Controller 작성과는 다르지 않다. 주의할점은 tiles-layout.xml 에 작성한 definition에 맞게 return을 해줘야 한다는것이다. 필자는 freemarker.hello 라는 return 값을 주었다. 

 

6. hello.ftl 작성

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>welcome</title>
</head>
<body>
    <h1>This is freemarker sample.</h1>
    <h2>${message}</h2>
</body>
</html>

마지막으로는 contents 영역에 들어갈, 위의 controller로부터 전달받은 view를 작성하는것이다. 위의 내용이 3. 각 layout 작성 부분의 contentarea.ftl 을 대체하게 된다. 즉 top과 bottom은 그대로 있고 content만 hello.ftl로 갈아끼워지는것이다. controller로부터 받은 message 값이 rendering 된다. 

hello.ftl은 tiles-layout.xml 에 정의한 /templates/hello.ftl 위치에 있으면 된다. 

 

이렇게 구성이 다 되었으면 springboot embedded tomcat을 기동하고 호출을 해보자. 

freemarker + tiles + springboot

위와 같이 의도한대로 화면 구성이 되어짐을 확인할 수 있다. 

 

freemarker의 자세한 사용법은 다음을 참조하도록 하자. 

 

Getting Started with template writing

This chapter is a very rough introduction to FreeMarker. The chapters after this will go over things in much greater detail. Nonetheless, once you have read this chapter, you will be able to write simple but useful FreeMarker templates.

freemarker.apache.org

 

끝!

댓글
최근에 올라온 글
최근에 달린 댓글
«   2024/05   »
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