Add Groovy template engine support for Spring MVC apps
Default suffix .tpl. If groovy-templates is on the classpath user can now add templates and get them rendered and resolved in an MVC app. TODO: Macro helpers for message rendering etc. See gh-878
This commit is contained in:
parent
938609fdc0
commit
da2e25f90d
|
|
@ -66,6 +66,11 @@
|
||||||
<artifactId>tomcat-jdbc</artifactId>
|
<artifactId>tomcat-jdbc</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.groovy</groupId>
|
||||||
|
<artifactId>groovy-templates</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.zaxxer</groupId>
|
<groupId>com.zaxxer</groupId>
|
||||||
<artifactId>HikariCP</artifactId>
|
<artifactId>HikariCP</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.groovy.template;
|
||||||
|
|
||||||
|
import groovy.text.TemplateEngine;
|
||||||
|
import groovy.text.markup.BaseTemplate;
|
||||||
|
import groovy.text.markup.MarkupTemplateEngine;
|
||||||
|
import groovy.text.markup.TemplateConfiguration;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.servlet.Servlet;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.groovy.template.web.GroovyTemplateViewResolver;
|
||||||
|
import org.springframework.boot.autoconfigure.groovy.template.web.LocaleAwareTemplate;
|
||||||
|
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconfiguration support for Groovy templates in MVC. By default creates a
|
||||||
|
* {@link MarkupTemplateEngine} configured from {@link GroovyTemplateProperties}, but you
|
||||||
|
* can override that by providing a {@link TemplateEngine} of a different type.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(TemplateEngine.class)
|
||||||
|
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
|
||||||
|
@EnableConfigurationProperties(GroovyTemplateProperties.class)
|
||||||
|
public class GroovyTemplateAutoConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GroovyTemplateProperties properties;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void checkTemplateLocationExists() {
|
||||||
|
if (this.properties.isCheckTemplateLocation()) {
|
||||||
|
Resource resource = this.resourceLoader.getResource(this.properties
|
||||||
|
.getPrefix());
|
||||||
|
Assert.state(resource.exists(), "Cannot find template location: " + resource
|
||||||
|
+ " (please add some templates "
|
||||||
|
+ "or check your FreeMarker configuration)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({ Servlet.class, LocaleContextHolder.class })
|
||||||
|
@ConditionalOnWebApplication
|
||||||
|
public static class GroovyWebConfiguration implements BeanClassLoaderAware {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GroovyTemplateProperties properties;
|
||||||
|
|
||||||
|
private ClassLoader classLoader = GroovyWebConfiguration.class.getClassLoader();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(TemplateEngine.class)
|
||||||
|
public TemplateEngine groovyTemplateEngine() throws Exception {
|
||||||
|
TemplateConfiguration configuration = this.properties.getConfiguration();
|
||||||
|
if (configuration.getBaseTemplateClass() == BaseTemplate.class) {
|
||||||
|
// Enable locale-dependent includes
|
||||||
|
configuration.setBaseTemplateClass(LocaleAwareTemplate.class);
|
||||||
|
}
|
||||||
|
return new MarkupTemplateEngine(createParentLoaderForTemplates(),
|
||||||
|
configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassLoader createParentLoaderForTemplates() throws Exception {
|
||||||
|
return new URLClassLoader(new URL[] { this.resourceLoader.getResource(
|
||||||
|
this.properties.getPrefix()).getURL() }, this.classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(name = "groovyTemplateViewResolver")
|
||||||
|
public GroovyTemplateViewResolver groovyTemplateViewResolver(TemplateEngine engine) {
|
||||||
|
GroovyTemplateViewResolver resolver = new GroovyTemplateViewResolver();
|
||||||
|
resolver.setPrefix(this.properties.getPrefix());
|
||||||
|
resolver.setSuffix(this.properties.getSuffix());
|
||||||
|
resolver.setCache(this.properties.isCache());
|
||||||
|
resolver.setContentType(this.properties.getContentType());
|
||||||
|
resolver.setCharSet(this.properties.getCharSet());
|
||||||
|
resolver.setViewNames(this.properties.getViewNames());
|
||||||
|
resolver.setTemplateEngine(engine);
|
||||||
|
|
||||||
|
// This resolver acts as a fallback resolver (e.g. like a
|
||||||
|
// InternalResourceViewResolver) so it needs to have low precedence
|
||||||
|
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 6);
|
||||||
|
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.groovy.template;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link TemplateAvailabilityProvider} that provides availability information for Groovy
|
||||||
|
* view templates
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
public class GroovyTemplateAvailabilityProvider implements TemplateAvailabilityProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTemplateAvailable(String view, Environment environment,
|
||||||
|
ClassLoader classLoader, ResourceLoader resourceLoader) {
|
||||||
|
if (ClassUtils.isPresent("groovy.text.TemplateEngine", classLoader)) {
|
||||||
|
String prefix = environment.getProperty("spring.groovy.template.prefix",
|
||||||
|
GroovyTemplateProperties.DEFAULT_PREFIX);
|
||||||
|
String suffix = environment.getProperty("spring.groovy.template.suffix",
|
||||||
|
GroovyTemplateProperties.DEFAULT_SUFFIX);
|
||||||
|
return resourceLoader.getResource(prefix + view + suffix).exists();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.groovy.template;
|
||||||
|
|
||||||
|
import groovy.text.markup.TemplateConfiguration;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties(prefix = "spring.groovy.template")
|
||||||
|
public class GroovyTemplateProperties {
|
||||||
|
|
||||||
|
public static final String DEFAULT_PREFIX = "classpath:/templates/";
|
||||||
|
|
||||||
|
public static final String DEFAULT_SUFFIX = ".tpl";
|
||||||
|
|
||||||
|
private String prefix = DEFAULT_PREFIX;
|
||||||
|
|
||||||
|
private String suffix = DEFAULT_SUFFIX;
|
||||||
|
|
||||||
|
private boolean cache;
|
||||||
|
|
||||||
|
private String contentType = "text/html";
|
||||||
|
|
||||||
|
private String charSet = "UTF-8";
|
||||||
|
|
||||||
|
private String[] viewNames;
|
||||||
|
|
||||||
|
private boolean checkTemplateLocation = true;
|
||||||
|
|
||||||
|
private TemplateConfiguration configuration = new TemplateConfiguration();
|
||||||
|
|
||||||
|
public void setCheckTemplateLocation(boolean checkTemplateLocation) {
|
||||||
|
this.checkTemplateLocation = checkTemplateLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCheckTemplateLocation() {
|
||||||
|
return this.checkTemplateLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getViewNames() {
|
||||||
|
return this.viewNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setViewNames(String[] viewNames) {
|
||||||
|
this.viewNames = viewNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCache() {
|
||||||
|
return this.cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCache(boolean cache) {
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return this.contentType
|
||||||
|
+ (this.contentType.contains(";charset=") ? "" : ";charset="
|
||||||
|
+ this.charSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(String contentType) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCharSet() {
|
||||||
|
return this.charSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCharSet(String charSet) {
|
||||||
|
this.charSet = charSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrefix() {
|
||||||
|
return this.prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrefix(String prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSuffix() {
|
||||||
|
return this.suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuffix(String suffix) {
|
||||||
|
this.suffix = suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfiguration(TemplateConfiguration configuration) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateConfiguration getConfiguration() {
|
||||||
|
return this.configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.groovy.template.web;
|
||||||
|
|
||||||
|
import groovy.text.Template;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.web.servlet.view.AbstractUrlBasedView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
public class GroovyTemplateView extends AbstractUrlBasedView {
|
||||||
|
|
||||||
|
private final Template template;
|
||||||
|
|
||||||
|
public GroovyTemplateView(Template template) {
|
||||||
|
this.template = template;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderMergedOutputModel(Map<String, Object> model,
|
||||||
|
HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||||
|
applyContentType(response);
|
||||||
|
this.template.make(model).writeTo(new BufferedWriter(response.getWriter()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply this view's content type as specified in the "contentType" bean property to
|
||||||
|
* the given response.
|
||||||
|
* @param response current HTTP response
|
||||||
|
* @see #setContentType
|
||||||
|
*/
|
||||||
|
protected void applyContentType(HttpServletResponse response) {
|
||||||
|
if (response.getContentType() == null) {
|
||||||
|
response.setContentType(getContentType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.groovy.template.web;
|
||||||
|
|
||||||
|
import groovy.text.SimpleTemplateEngine;
|
||||||
|
import groovy.text.Template;
|
||||||
|
import groovy.text.TemplateEngine;
|
||||||
|
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.springframework.beans.propertyeditors.LocaleEditor;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.web.servlet.View;
|
||||||
|
import org.springframework.web.servlet.view.UrlBasedViewResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
public class GroovyTemplateViewResolver extends UrlBasedViewResolver {
|
||||||
|
|
||||||
|
private TemplateEngine engine = new SimpleTemplateEngine();
|
||||||
|
|
||||||
|
private String charSet = "UTF-8";
|
||||||
|
|
||||||
|
public GroovyTemplateViewResolver() {
|
||||||
|
setViewClass(GroovyTemplateView.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param engine the engine to set
|
||||||
|
*/
|
||||||
|
public void setTemplateEngine(TemplateEngine engine) {
|
||||||
|
this.engine = engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param charSet the charSet to set
|
||||||
|
*/
|
||||||
|
public void setCharSet(String charSet) {
|
||||||
|
this.charSet = charSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected View loadView(String viewName, Locale locale) throws Exception {
|
||||||
|
Resource resource = resolveResource(viewName, locale);
|
||||||
|
if (resource == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Template template = this.engine.createTemplate(new InputStreamReader(resource
|
||||||
|
.getInputStream(), this.charSet));
|
||||||
|
GroovyTemplateView view = new GroovyTemplateView(template);
|
||||||
|
view.setApplicationContext(getApplicationContext());
|
||||||
|
view.setServletContext(getServletContext());
|
||||||
|
view.setContentType(getContentType());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resource resolveResource(String viewName, Locale locale) {
|
||||||
|
String l10n = "";
|
||||||
|
if (locale != null) {
|
||||||
|
LocaleEditor localeEditor = new LocaleEditor();
|
||||||
|
localeEditor.setValue(locale);
|
||||||
|
l10n = "_" + localeEditor.getAsText();
|
||||||
|
}
|
||||||
|
return resolveFromLocale(viewName, l10n);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resource resolveFromLocale(String viewName, String locale) {
|
||||||
|
Resource resource = getApplicationContext().getResource(
|
||||||
|
getPrefix() + viewName + locale + getSuffix());
|
||||||
|
if (resource == null || !resource.exists()) {
|
||||||
|
if (locale.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int index = locale.lastIndexOf("_");
|
||||||
|
return resolveFromLocale(viewName, locale.substring(0, index));
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.groovy.template.web;
|
||||||
|
|
||||||
|
import groovy.text.markup.BaseTemplate;
|
||||||
|
import groovy.text.markup.MarkupTemplateEngine;
|
||||||
|
import groovy.text.markup.TemplateConfiguration;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
public abstract class LocaleAwareTemplate extends BaseTemplate {
|
||||||
|
|
||||||
|
public LocaleAwareTemplate(MarkupTemplateEngine templateEngine, Map<?, ?> model,
|
||||||
|
Map<String, String> modelTypes, TemplateConfiguration configuration) {
|
||||||
|
super(localize(templateEngine), model, modelTypes, localize(configuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MarkupTemplateEngine localize(MarkupTemplateEngine templateEngine) {
|
||||||
|
TemplateConfiguration templateConfiguration = templateEngine
|
||||||
|
.getTemplateConfiguration();
|
||||||
|
ClassLoader parent = templateEngine.getTemplateLoader().getParent();
|
||||||
|
return new MarkupTemplateEngine(parent, localize(templateConfiguration));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TemplateConfiguration localize(TemplateConfiguration configuration) {
|
||||||
|
TemplateConfiguration result = new TemplateConfiguration(configuration);
|
||||||
|
result.setLocale(LocaleContextHolder.getLocale());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.groovy.template;
|
||||||
|
|
||||||
|
import groovy.text.TemplateEngine;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.boot.autoconfigure.groovy.template.web.GroovyTemplateViewResolver;
|
||||||
|
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||||
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.mock.web.MockServletContext;
|
||||||
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||||
|
import org.springframework.web.servlet.View;
|
||||||
|
import org.springframework.web.servlet.support.RequestContext;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for GroovyTemplateAutoConfiguration.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
public class GroovyTemplateAutoConfigurationTests {
|
||||||
|
|
||||||
|
private AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setupContext() {
|
||||||
|
this.context.setServletContext(new MockServletContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void close() {
|
||||||
|
LocaleContextHolder.resetLocaleContext();
|
||||||
|
if (this.context != null) {
|
||||||
|
this.context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultConfiguration() {
|
||||||
|
registerAndRefreshContext();
|
||||||
|
assertThat(this.context.getBean(GroovyTemplateViewResolver.class), notNullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = BeanCreationException.class)
|
||||||
|
public void nonExistentTemplateLocation() {
|
||||||
|
registerAndRefreshContext("spring.groovy.template.prefix:"
|
||||||
|
+ "classpath:/does-not-exist/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyTemplateLocation() {
|
||||||
|
new File("target/test-classes/templates/empty-directory").mkdir();
|
||||||
|
registerAndRefreshContext("spring.groovy.template.prefix:"
|
||||||
|
+ "classpath:/templates/empty-directory/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultViewResolution() throws Exception {
|
||||||
|
registerAndRefreshContext();
|
||||||
|
MockHttpServletResponse response = render("home");
|
||||||
|
String result = response.getContentAsString();
|
||||||
|
assertThat(result, containsString("home"));
|
||||||
|
assertThat(response.getContentType(), equalTo("text/html;charset=UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void includesViewResolution() throws Exception {
|
||||||
|
registerAndRefreshContext();
|
||||||
|
MockHttpServletResponse response = render("includes");
|
||||||
|
String result = response.getContentAsString();
|
||||||
|
assertThat(result, containsString("here"));
|
||||||
|
assertThat(response.getContentType(), equalTo("text/html;charset=UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void localeViewResolution() throws Exception {
|
||||||
|
LocaleContextHolder.setLocale(Locale.FRENCH);
|
||||||
|
registerAndRefreshContext();
|
||||||
|
MockHttpServletResponse response = render("includes", Locale.FRENCH);
|
||||||
|
String result = response.getContentAsString();
|
||||||
|
assertThat(result, containsString("voila"));
|
||||||
|
assertThat(response.getContentType(), equalTo("text/html;charset=UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customContentType() throws Exception {
|
||||||
|
registerAndRefreshContext("spring.groovy.template.contentType:application/json");
|
||||||
|
MockHttpServletResponse response = render("home");
|
||||||
|
String result = response.getContentAsString();
|
||||||
|
assertThat(result, containsString("home"));
|
||||||
|
assertThat(response.getContentType(), equalTo("application/json;charset=UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customPrefix() throws Exception {
|
||||||
|
registerAndRefreshContext("spring.groovy.template.prefix:classpath:/templates/prefix/");
|
||||||
|
MockHttpServletResponse response = render("prefixed");
|
||||||
|
String result = response.getContentAsString();
|
||||||
|
assertThat(result, containsString("prefixed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customSuffix() throws Exception {
|
||||||
|
registerAndRefreshContext("spring.groovy.template.suffix:.groovytemplate");
|
||||||
|
MockHttpServletResponse response = render("suffixed");
|
||||||
|
String result = response.getContentAsString();
|
||||||
|
assertThat(result, containsString("suffixed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customTemplateLoaderPath() throws Exception {
|
||||||
|
registerAndRefreshContext("spring.groovy.template.prefix:classpath:/custom-templates/");
|
||||||
|
MockHttpServletResponse response = render("custom");
|
||||||
|
String result = response.getContentAsString();
|
||||||
|
assertThat(result, containsString("custom"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableCache() {
|
||||||
|
registerAndRefreshContext("spring.groovy.template.cache:false");
|
||||||
|
assertThat(
|
||||||
|
this.context.getBean(GroovyTemplateViewResolver.class).getCacheLimit(),
|
||||||
|
equalTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderTemplate() throws Exception {
|
||||||
|
registerAndRefreshContext();
|
||||||
|
TemplateEngine engine = this.context.getBean(TemplateEngine.class);
|
||||||
|
Writer writer = new StringWriter();
|
||||||
|
engine.createTemplate(new ClassPathResource("templates/message.tpl").getFile())
|
||||||
|
.make(new HashMap<String, Object>(Collections.singletonMap("greeting",
|
||||||
|
"Hello World"))).writeTo(writer);
|
||||||
|
assertThat(writer.toString(), containsString("Hello World"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerAndRefreshContext(String... env) {
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context, env);
|
||||||
|
this.context.register(GroovyTemplateAutoConfiguration.class);
|
||||||
|
this.context.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MockHttpServletResponse render(String viewName) throws Exception {
|
||||||
|
return render(viewName, Locale.UK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MockHttpServletResponse render(String viewName, Locale locale)
|
||||||
|
throws Exception {
|
||||||
|
GroovyTemplateViewResolver resolver = this.context
|
||||||
|
.getBean(GroovyTemplateViewResolver.class);
|
||||||
|
View view = resolver.resolveViewName(viewName, locale);
|
||||||
|
assertThat(view, notNullValue());
|
||||||
|
HttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE,
|
||||||
|
this.context);
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
view.render(null, request, response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
yield "custom"
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
yield "home"
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
yield "here"
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
yield "voila"
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
yield "include"
|
||||||
|
include template: "included.tpl"
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
yield "Message: ${greeting}"
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
yield "prefixed"
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
yield """
|
||||||
|
suffixed
|
||||||
|
"""
|
||||||
|
|
@ -106,8 +106,9 @@
|
||||||
<spring-plugin.version>1.1.0.RELEASE</spring-plugin.version>
|
<spring-plugin.version>1.1.0.RELEASE</spring-plugin.version>
|
||||||
<spring-amqp.version>1.3.2.RELEASE</spring-amqp.version>
|
<spring-amqp.version>1.3.2.RELEASE</spring-amqp.version>
|
||||||
<spring-mobile.version>1.1.1.RELEASE</spring-mobile.version>
|
<spring-mobile.version>1.1.1.RELEASE</spring-mobile.version>
|
||||||
|
<spring-retry.version>1.1.0.RELEASE</spring-retry.version>
|
||||||
<spring-security.version>3.2.3.RELEASE</spring-security.version>
|
<spring-security.version>3.2.3.RELEASE</spring-security.version>
|
||||||
<spring-security-oauth.version>2.0.0.RC2</spring-security-oauth.version>
|
<spring-security-oauth.version>2.0.0.RELEASE</spring-security-oauth.version>
|
||||||
<spring-security-jwt.version>1.0.2.RELEASE</spring-security-jwt.version>
|
<spring-security-jwt.version>1.0.2.RELEASE</spring-security-jwt.version>
|
||||||
<thymeleaf.version>2.1.3.RELEASE</thymeleaf.version>
|
<thymeleaf.version>2.1.3.RELEASE</thymeleaf.version>
|
||||||
<thymeleaf-extras-springsecurity3.version>2.1.1.RELEASE</thymeleaf-extras-springsecurity3.version>
|
<thymeleaf-extras-springsecurity3.version>2.1.1.RELEASE</thymeleaf-extras-springsecurity3.version>
|
||||||
|
|
@ -994,6 +995,11 @@
|
||||||
<artifactId>spring-mobile-device</artifactId>
|
<artifactId>spring-mobile-device</artifactId>
|
||||||
<version>${spring-mobile.version}</version>
|
<version>${spring-mobile.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.retry</groupId>
|
||||||
|
<artifactId>spring-retry</artifactId>
|
||||||
|
<version>${spring-retry.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-acl</artifactId>
|
<artifactId>spring-security-acl</artifactId>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue