손권남 GitHub
kwon37xi / freemarker-template-inheritance Goto Github PK
View Code? Open in Web Editor NEWFreemarker layout with template inheritance directives.
License: Apache License 2.0
Freemarker layout with template inheritance directives.
License: Apache License 2.0
손권남 GitHub
미리 Directive들의 맵을 util:map으로 생성해 두고, Spring에서는 해당 선언을 import 하여 바로 지어 넣을 수 있게 변경한다.
This is dashboard.html page code
<!-- main area -->
<div class="main-content">
<#assign message="This is message"/>
<@layout.block name="content">
<!--This is ok.-->
${message}
</@layout.block>
</div>
<!-- /main area -->
This is subpage code.
<@layout.put block="content">
<!--this tag only write subpage !!!-->
<#assign security=JspTaglibs["/WEB-INF/tlds/security.tld"] />
<div class="row">
<div class="panel panel-default">
<div class="panel-body">
<!--This is bad-->
${message}
<@security.authorize access="hasRole('ADMIN')">
login as admin
</@security.authorize>
</div>
</div>
</div>
</@layout.put>
<@layout.extends name="layouts/dashboard.html" />
안녕하세요.
스프링 부트 2.0 환경에서 freemarker-starter를 이용하며 template-inheritence를 사용하고자 하는데요.
README.md 에 설정하는 방식을 사용할 경우 application.yml에 등록된 settings 값을 가져오지 못하는 현상이 있었습니다.
원인은 FreeMarkerServletWebConfiguration
클래스에서
FreeMarkerConfigurer
빈을 등록할때 applyProperties
메소드를 통해서 settings 값을 넣어주고 있는데 해당 빈은 이미 지정된 FreeMarkerConfigurer
빈이 없을때만 등록하게 되어 있어서 가이드된 방식에서는 FreeMarkerConfigurer
을 새로 등록하기 때문에 해당 메소드를 호출하지 않아서 세팅이 되지 않는듯해 보입니다.
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({ Servlet.class, FreeMarkerConfigurer.class })
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration {
protected FreeMarkerServletWebConfiguration(FreeMarkerProperties properties) {
super(properties);
}
@Bean
@ConditionalOnMissingBean(FreeMarkerConfig.class)
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
applyProperties(configurer);
return configurer;
}
이를 해결하고자 freemarker-starter 에서 세팅한 FreeMarkerConfigurer
빈을 사용하고자 아래와 같이 설정을 수정했는데요.
@Configuration
public class LayoutConfig {
@Autowired
FreeMarkerConfigurer freemarkerConfig;
@PostConstruct
@ConditionalOnBean(FreeMarkerConfigurer.class)
public void setFreeMarkerLayoutDirectives () {
Map<String, TemplateModel> freemarkerLayoutDirectives = new HashMap<>();
freemarkerLayoutDirectives.put("extends", new ExtendsDirective());
freemarkerLayoutDirectives.put("block", new BlockDirective());
freemarkerLayoutDirectives.put("put", new PutDirective());
Map<String, Object> freemarkerVariables = new HashMap<>();
freemarkerVariables.put("layout", freemarkerLayoutDirectives);
freemarkerConfig.setFreemarkerVariables(freemarkerVariables);
}
}
실제 템플릿을 할 경우 등록한 freemarkerVariables 값이 null 이라는 오류가 발생하는 것 같습니다.
<@layout.extends name="layouts/base.ftl">
<@layout.put block="head">
<head>
<title>Home Template</title>
</head>
</@layout.put>
<@layout.put block="contents">
<div id="home">
Mon Apr 02 17:52:52 KST 2018
There was an unexpected error (type=Internal Server Error, status=500).
The following has evaluated to null or missing: ==> layout.extends [in template "index.ftl" at line 1, column 3] ---- Tip: It's the step after the last dot that caused this error, not those before it. ---- Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)?? ---- ---- FTL stack trace ("~" means nesting-related): - Failed at: @layout.extends name="layouts/base.ftl" [in template "index.ftl" at line 1, column 1] ----
settings 값만 추가하는 경우라면 FreeMarkerProperties 파일을 인젝션 받아서 세팅해주면 될 것 같긴 합니다만, freemarker-starter 에서 어떠한 설정을 추가로 해주는지 알기 어려우니 FreeMarkerConfigurer
빈을 새로 만들지 않고 기존에 스타터에서 만든 빈을 인젝션 받아서 사용하고 싶습니다.
이러한 오류가 나타나는 원인이 무엇인지 해결책이 있는지 궁금합니다.
감사합니다.
Freemarker has built in support for macros which allow to achieve (kind of) template inheritance:
macros
<#-- base.ftl -->
<#macro content></#macro>
<#macro display_page>
<html>
<body>
<@content/>
</body>
</html>
</#macro>
<#-- child.ftl -->
<#include "base.ftl">
<#macro content>
Example content
</#macro>
<@display_page/>
kwon37xi inheritance
<#-- base.ftl -->
<html>
<body>
<@layout.block name="header"></@layout.block>
</body>
</html>
<#-- child.ftl -->
<@layout.extends name="base.ftl">
<@layout.put block="contents">
Example content
</@layout.put>
</@layout.extends>
QUESTION
Although kwon37xi inheritance contains nicer markup and some additional features like append/prepend is there any other advantage to use kwon37xi inheritance instead of macros? Have you tried any performance tests etc?
This would be good topic to extend Readme as well
like python framework jinja2 ?
Currently I'm using sample freemarker java config to use free marker:
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() {
final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setCache(true);
resolver.setPrefix("");
resolver.setSuffix(".ftl");
resolver.setContentType("text/html; charset=UTF-8");
return resolver;
}
@Bean
public FreeMarkerConfigurer freemarkerConfig() throws IOException, TemplateException {
final FreeMarkerConfigurationFactory factory = new FreeMarkerConfigurationFactory();
factory.setTemplateLoaderPath("classpath:templates");
factory.setDefaultEncoding("UTF-8");
final FreeMarkerConfigurer result = new FreeMarkerConfigurer();
result.setConfiguration(factory.createConfiguration());
return result;
}
}
Could you create example with spring, freemarker, your template inheritance using java config instead of xml config?
hi.
I have a web, include 3 page.the relationship as shown below:
A.ftl is base、B.ftl extend A.ftl、C.ftl extend B.ftl。
A.ftl and B.ftl normal work,but the C.ftl didn't work。
thx.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.