Freemarker知识点整理
关于自定义Directive的介绍:https://freemarker.apache.org/docs/pgui_datamodel_directive.html
还可以这样初始化:
<#-- Maybe you have directives that you have implemented in FTL --> <#macro something> ... </#macro> <#-- Now you can't use <#macro upper>, but instead you can: --> <#assign upper = "com.example.UpperDirective"?new()>
?new()一个directive
标准上还是用Configuration.setSharedVariable("content",contentDirective); 这种写法比较好。
(2) Directive设定输出内容时,c为null时也需要输出,这样页面才能通过
[#if value??]进行为空的判断
env.setVariable("value", ObjectWrapper.DEFAULT_WRAPPER.wrap(c));
(3)自定义组件控制内容输出,freemarker自定义权限检查逻辑也可用这种机制实现
[@content_attach_list type="doc"] 附件列表: [#list value as item] <p>附件${item_index+1}:<a href="${item.attachPath}" target="_blank">${item.attachOriname}</a></p> [/#list] [/@content_attach_list]
如自定义附件列表组件,若想没有附件时不显示附件列表文字,需要在自定义组件控制输出:
//没有数据则不输出组件内容 if (body != null && list!= null && !list.isEmpty()) { body.render(env.getOut()); }
(4)自定义组件加入freemarker配置
方法1:直接加入,页面可直接用content_attach_list作为名字
configuration.setSharedVariable("content_attach_list",contentAttachListDirective);
方法2:通过hash加入,一次性加入多个,这样页面可以使用cms.hasPermission,cms.hasAnyRoles等形式访问组件
configuration.setSharedVariable("cms", new ShiroTags()); //其中ShiroTags为 public class ShiroTags extends SimpleHash { public ShiroTags() { this.put("authenticated", new AuthenticatedTag()); this.put("guest", new GuestTag()); this.put("hasAnyRoles", new HasAnyRolesTag()); this.put("hasPermission", new HasPermissionTag()); } }
(5) 与SpringBoot+Freemarker 国际化支持
需要注意freemarker的一个配置项(默认为true,但有的项目可能设置为了false):
spring.freemarker.expose-spring-macro-helpers=true
需要为true,否则spring.ftl中的springMacroRequestContext会找不到。
另外通过application.properties设定message路径不起作用(Springboot 2.0.5),
spring.messages.basename=i18n/messages
spring.messages.encoding=UTF-8
经过debug时发现,在org.springframework.context.support.AbstractApplicationContext中初始化MessageSource是按beanName来找的,调试发现没有找到,
不太清楚为啥,感觉可能是版本问题,找不到然后就用的Empty的资源类,那肯定是找不到对应的消息的【此处SpringBoot处理的不太好,还不如报个错了,弄个空的类,搞的莫名其妙】
protected void initMessageSource() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); // Make MessageSource aware of parent MessageSource. if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) { HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource; if (hms.getParentMessageSource() == null) { // Only set parent context as parent MessageSource if no parent MessageSource // registered already. hms.setParentMessageSource(getInternalParentMessageSource()); } } if (logger.isDebugEnabled()) { logger.debug("Using MessageSource [" + this.messageSource + "]"); } } else { // Use empty MessageSource to be able to accept getMessage calls. DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource = dms;
因此改为通过java配置设定,代码如下:
@Configuration
public class WebConfig implements WebMvcConfigurer {
...
@Bean
public MessageSource messageSource(){
//wanghc
//设定文件加载类,通过配置文件设置无效,在此处直接通过bean来设定
//注意,必须为messageSource这个bean名字才可以
//另外文字可直接写入配置文件,指定编码即可,不需要再转换文件ascii了
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}