boot automatic configuration freemarker lack freemarkerVariables
What do you mean by "freemarkerVariables"? Can you please show what you're currently having to configure that the auto-configuration should be able to configure for you?
in freemarker automatic configuration , it lack of freemarkerVariables configuration
it lack of freemarkerVariables configuration
freemarker:
settings:
object_wrapper: com.control.back.halo.basic.utils.FreemarkerObjectWrapper
datetime_format: yyyy-MM-dd HH:mm:ss
date_format: yyyy-MM-dd
time_format: HH:mm:ss
@ConfigurationProperties(prefix = "spring.freemarker")
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {
it is no freemarkerVariables
but FreeMarkerConfigurationFactory has freemarkerVariables,i need it
I need a solution
Ok, so you'd like to be able to set the freemarkerVariables
property on either the auto-configured FreeMarkerConfigurationFactoryBean
or on the auto-configured FreeMarkerConfigurer
bean, correct? Both are subclasses of FreeMarkerConfigurationFactory
.
What variables do you want to be able to set? Can you please provide some specific examples? Please note that values other than maps, lists and scalar values are not well-suited to being set via application.properties
.
shiro:
realm: com.control.back.halo.authorization.shiro.realm.UserRealm
login-url: /login.html
success-url: /index.html
unauthorized-url: /
#filter chian
filterChainDefinitions:
"/login": anon
"/login/**": anon
"/logout": logout
"/css/**": anon
"/fonts/**": anon
"/img/**": anon
"/js/**": anon
"/**": authc
i use shiro ,and definition a ShiroProperties,i hope freemarkerVariables use map definition . yes?
@ConfigurationProperties(prefix = "shiro")
public class ShiroProperties {
/**
* Custom Realm
*/
private String realm;
/**
* URL of login
*/
private String loginUrl;
/**
* URL of success
*/
private String successUrl;
/**
* URL of unauthorized
*/
private String unauthorizedUrl;
/**
* filter chain
*/
private Map<String, String> filterChainDefinitions;
/**
*
*/
private String ehacheConfig;
According to the yaml's document,it can configure the map ,Why not do it
@ohalo Please take the time to format your comments as it will make them much easier to read. Also, please keep this issue focused on FreeMarker. Your latest example appears to be solely about Shiro. I still need some examples of the freemarker variables that you are trying to set.
@ConfigurationProperties(prefix = "freemarker")
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {
public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = ".ftl";
/**
* Well-known FreeMarker keys which will be passed to FreeMarker's Configuration.
*/
private Map<String, String> settings = new HashMap<String, String>();
private Map<String, String> freemarkerVariables = new HashMap<String, String>();
and configuration is
#freemarker
freemarker:
settings:
object_wrapper: com.control.back.halo.basic.utils.FreemarkerObjectWrapper
datetime_format: yyyy-MM-dd HH:mm:ss
date_format: yyyy-MM-dd
time_format: HH:mm:ss
freemarker-variables:
base: http://127.0.0.1:80
in FreeMarkerAutoConfiguration ,and join factory.setFreemarkerVariables(this.properties.getFreemarkerVariables());
```
protected static class FreeMarkerConfiguration {
@Autowired
protected FreeMarkerProperties properties;
protected void applyProperties(FreeMarkerConfigurationFactory factory) {
factory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath());
factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess());
factory.setDefaultEncoding(this.properties.getCharsetName());
Properties settings = new Properties();
settings.putAll(this.properties.getSettings());
factory.setFreemarkerSettings(settings);
factory.setFreemarkerVariables(this.properties.getFreemarkerVariables());
}
}
```
Is that ok?sorry my english
The formatting is much better, thank you. Unfortunately, it's not really what it was looking for.
You've shown how what you're asking for could be implemented in Spring Boot and I already know how to do that. What I don't know is what _values_ you want to set in freemarkerVariables
. You've shown one example which is setting base
to http://127.0.0.1:80
. What other variables would you like to be able to set and what values might they have? I am asking because the values in freemarkerVariables
can be anything (it's a Mapapplication.properties
or application.yml
aren't a good way to set some types of Object
. As I said above, it's only suited to setting maps, lists and scalar values.
If you want to configure something that's more complex, or you just want to do this without an enhancement to Spring Boot, then registering a BeanPostProcessor
for the FreeMarkerConfigurer
or FreeMarkerConfigurationFactoryBean
may be what you need to do.
ok , i understand you,because application.properties or application.yml aren't a good way to set some types of Object,thank you
because application.properties or application.yml aren't a good way to set some types of Object
Yes, that's right. Can you please share some examples of the values that you would like to set?
i want set String values ,not Object value,like: url(static resource url:img,js,css;and other system's url)
@ohalo It's still not clear what properties you're setting and what you expect to happen. I think the best way to proceed is if you could provide a small focused sample application that shows the problem.
@druidDataSource com.alibaba.druid.pool.DruidDataSource
@driverClass com.mysql.jdbc.Driver
#freemarker
freemarker:
settings:
object_wrapper: com.control.back.halo.basic.utils.FreemarkerObjectWrapper
datetime_format: yyyy-MM-dd HH:mm:ss
date_format: yyyy-MM-dd
time_format: HH:mm:ss
template_update_delay : 0
freemarker-variables:
base: http://127.0.0.1:8080
siteName: speedbuy
druidDataSource: *druidDataSource
driverClass: *driverClass
I'm not convinced that we should support this out of the box. AFAICT most of our other template engines don't have properties that we set. Mustache does have a MustacheEnvironmentCollector
which allows Spring Environment variables to be accessed, but there is no variables
section in its @ConfigurationProperties
.
We feel like the properties is a little restrictive and a customizer might be a better option. We can use FreemarkerConfigurationFactory.setFreemarkerVariables()
.
We could also consider a more general solution, for all ViewResolvers
extending UrlBasedViewResolver
. This class has a UrlBasedViewResolver.setAttributesMap(Map<String, Object)
method that adds those attributes to all views resolved (see javadoc).
Those attributes will be available in the model when the template is being rendered.
I want the customizer. Now I implement like this (no need to custom freemarker).
public class FreeMarkerVariablesInterceptor extends HandlerInterceptorAdapter {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
modelAndView.addObject("key", new Value());
}
}
thanks
A solution:
spring:
freemarker:
settings:
auto_import: "/spring.ftl as spring , /fragment/global.ftl as _global_"
global.ftl:
<#assign static_server = "http://127.0.0.1">
Use global variable:
${_global_.static_server}
Or put global variable to ServletContext
public class HomeApp extends SpringBootServletInitializer {
@Override
protected WebApplicationContext createRootApplicationContext
(ServletContext servletContext) {
WebApplicationContext ctx = super.createRootApplicationContext(servletContext);
HomeAppConfig conf = ctx.getBean(HomeAppConfig.class);
servletContext.setAttribute("_config_",conf);
return ctx;
}
}
@moqi2011
thanks
@Configuration
public class FreemarkerConfiguration extends FreeMarkerAutoConfiguration.FreeMarkerWebConfiguration {
@Value("${ctx.static}")
private String ctx;
@Value("${ctx.custom}")
private Integer custom;
@Override
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = super.freeMarkerConfigurer();
Map<String, Object> sharedVariables = new HashMap<>();
if (custom != null && custom == 1) {
sharedVariables.put("sctx", ctx);
}
configurer.setFreemarkerVariables(sharedVariables);
return configurer;
}
}
workd for me
@ohalo
Spring Boot 2.0 breaks the solution provided by @wo8335224, as FreeMarkerWebConfiguration
is replaced by FreeMarkerServletWebConfiguration, which is unfortunately package-private and thus cannot be subclassed.
A currently working solution is to configure freemarker.template.Configuration
bean:
@Configuration
public class FreemarkerConfig {
public FreemarkerConfig(freemarker.template.Configuration configuration) throws TemplateModelException {
configuration.setSharedVariable("name", "whatever type of value");
}
}
Internally FreeMarkerConfigurer#setFreemarkerVariables
delegates its work to freemarker.template.Configuration#setAllSharedVariables
.
Hey @bianjp !
Yes, you can do this, but you'll lose some auto-configuration.
So better use BeanPostProcessor
.
@Component
class FreeMarkerPostProcessor : BeanPostProcessor {
override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any {
if (bean is FreeMarkerConfigurer) {
bean.setFreemarkerVariables(mapOf(
"globalVar" to "globalVarValue"
))
}
return bean
}
}
Thanks @satahippy. Java version:
@Configuration
public class CustomFreeMarkerConfig implements BeanPostProcessor {
Object sharedWithAllFreeMarkerTemplatesObj = new Object();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof FreeMarkerConfigurer) {
FreeMarkerConfigurer configurer = (FreeMarkerConfigurer) bean;
Map<String, Object> sharedVariables = new HashMap<>();
sharedVariables.put("globalVar", sharedWithAllFreeMarkerTemplatesObj);
configurer.setFreemarkerVariables(sharedVariables);
}
return bean;
}
}
[edit: my original comment confused Before/After Initialization)
I feel like there should be some easier, built-in way, of doing this, but I haven't found it yet. Related question on StackOverflow: https://stackoverflow.com/questions/52730368/how-to-make-globally-shared-objects-available-to-freemarker-templates-in-spring
To be able to use FreeMarkerConfigurationFactory
in a customizer, we need a framework change. I've opened https://github.com/spring-projects/spring-framework/issues/23054
Most helpful comment
We feel like the properties is a little restrictive and a customizer might be a better option. We can use
FreemarkerConfigurationFactory.setFreemarkerVariables()
.