Add support for using Velocity templates

This commit is contained in:
Andy Wilkinson
2014-05-07 17:34:24 +01:00
parent b33eb95dd2
commit 2378fe0900
31 changed files with 1156 additions and 182 deletions

View File

@@ -66,6 +66,11 @@
<artifactId>tomcat-jdbc</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-templates</artifactId>

View File

@@ -28,11 +28,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.template.TemplateViewResolverConfigurer;
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.core.Ordered;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
@@ -45,7 +45,7 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
/**
* {@link EnableAutoConfiguration Auto-configuration} for FreeMarker.
*
*
* @author Andy Wilkinson
* @author Dave Syer
* @since 1.1.0
@@ -65,8 +65,8 @@ public class FreeMarkerAutoConfiguration {
@PostConstruct
public void checkTemplateLocationExists() {
if (this.properties.isCheckTemplateLocation()) {
Resource resource = this.resourceLoader
.getResource(this.properties.getTemplateLoaderPath());
Resource resource = this.resourceLoader.getResource(this.properties
.getTemplateLoaderPath());
Assert.state(resource.exists(), "Cannot find template location: " + resource
+ " (please add some templates "
+ "or check your FreeMarker configuration)");
@@ -125,26 +125,10 @@ public class FreeMarkerAutoConfiguration {
@ConditionalOnMissingBean(name = "freeMarkerViewResolver")
public FreeMarkerViewResolver freeMarkerViewResolver() {
FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setPrefix(this.properties.getPrefix());
resolver.setSuffix(this.properties.getSuffix());
resolver.setCache(this.properties.isCache());
resolver.setContentType(this.properties.getContentType());
resolver.setViewNames(this.properties.getViewNames());
resolver.setExposeRequestAttributes(this.properties
.isExposeRequestAttributes());
resolver.setExposeRequestAttributes(this.properties.isAllowRequestOverride());
resolver.setExposeRequestAttributes(this.properties
.isExposeSessionAttributes());
resolver.setExposeRequestAttributes(this.properties
.isExposeSpringMacroHelpers());
resolver.setRequestContextAttribute(this.properties
.getRequestContextAttribute());
// This resolver acts as a fallback resolver (e.g. like a
// InternalResourceViewResolver) so it needs to have low precedence
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
new TemplateViewResolverConfigurer().configureTemplateViewResolver(resolver,
this.properties);
return resolver;
}
}
}

View File

@@ -19,15 +19,19 @@ package org.springframework.boot.autoconfigure.freemarker;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.autoconfigure.template.AbstractTemplateViewResolverProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* {@link ConfigurationProperties} for configuring FreeMarker
*
* @author Dave Syer
*
* @author Andy Wilkinson
*
* @since 1.1.0
*/
@ConfigurationProperties(prefix = "spring.freemarker")
public class FreeMarkerProperties {
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {
public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";
@@ -35,138 +39,12 @@ public class FreeMarkerProperties {
public static final String DEFAULT_SUFFIX = ".ftl";
private String prefix = DEFAULT_PREFIX;
private String suffix = DEFAULT_SUFFIX;
private Map<String, String> settings = new HashMap<String, String>();
private String templateLoaderPath = DEFAULT_TEMPLATE_LOADER_PATH;
private boolean cache;
private String contentType = "text/html";
private String charSet = "UTF-8";
private String[] viewNames;
private boolean checkTemplateLocation = true;
private String requestContextAttribute;
private boolean exposeRequestAttributes = false;
private boolean exposeSessionAttributes = false;
private boolean allowRequestOverride = false;
private boolean exposeSpringMacroHelpers = true;
private Map<String, String> settings = new HashMap<String, String>();
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 String getTemplateLoaderPath() {
return this.templateLoaderPath;
}
public void setTemplateLoaderPath(String templateLoaderPath) {
this.templateLoaderPath = templateLoaderPath;
}
public String getRequestContextAttribute() {
return this.requestContextAttribute;
}
public void setRequestContextAttribute(String requestContextAttribute) {
this.requestContextAttribute = requestContextAttribute;
}
public boolean isExposeRequestAttributes() {
return this.exposeRequestAttributes;
}
public void setExposeRequestAttributes(boolean exposeRequestAttributes) {
this.exposeRequestAttributes = exposeRequestAttributes;
}
public boolean isExposeSessionAttributes() {
return this.exposeSessionAttributes;
}
public void setExposeSessionAttributes(boolean exposeSessionAttributes) {
this.exposeSessionAttributes = exposeSessionAttributes;
}
public boolean isAllowRequestOverride() {
return this.allowRequestOverride;
}
public void setAllowRequestOverride(boolean allowRequestOverride) {
this.allowRequestOverride = allowRequestOverride;
}
public boolean isExposeSpringMacroHelpers() {
return this.exposeSpringMacroHelpers;
}
public void setExposeSpringMacroHelpers(boolean exposeSpringMacroHelpers) {
this.exposeSpringMacroHelpers = exposeSpringMacroHelpers;
public FreeMarkerProperties() {
super(DEFAULT_PREFIX, DEFAULT_SUFFIX);
}
public Map<String, String> getSettings() {
@@ -177,4 +55,11 @@ public class FreeMarkerProperties {
this.settings = settings;
}
public String getTemplateLoaderPath() {
return this.templateLoaderPath;
}
public void setTemplateLoaderPath(String templateLoaderPath) {
this.templateLoaderPath = templateLoaderPath;
}
}

View File

@@ -0,0 +1,158 @@
/*
* 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.template;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
/**
* Abstract base class for {@link ConfigurationProperties} for
* {@link AbstractTemplateViewResolver view resolvers}.
*
* @author Andy Wilkinson
* @since 1.1.0
*/
public abstract class AbstractTemplateViewResolverProperties {
private String prefix;
private String suffix;
private boolean cache;
private String contentType = "text/html";
private String charSet = "UTF-8";
private String[] viewNames;
private boolean checkTemplateLocation = true;
private String requestContextAttribute;
private boolean exposeRequestAttributes = false;
private boolean exposeSessionAttributes = false;
private boolean allowRequestOverride = false;
private boolean exposeSpringMacroHelpers = true;
protected AbstractTemplateViewResolverProperties(String defaultPrefix,
String defaultSuffix) {
this.prefix = defaultPrefix;
this.suffix = defaultSuffix;
}
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 String getRequestContextAttribute() {
return this.requestContextAttribute;
}
public void setRequestContextAttribute(String requestContextAttribute) {
this.requestContextAttribute = requestContextAttribute;
}
public boolean isExposeRequestAttributes() {
return this.exposeRequestAttributes;
}
public void setExposeRequestAttributes(boolean exposeRequestAttributes) {
this.exposeRequestAttributes = exposeRequestAttributes;
}
public boolean isExposeSessionAttributes() {
return this.exposeSessionAttributes;
}
public void setExposeSessionAttributes(boolean exposeSessionAttributes) {
this.exposeSessionAttributes = exposeSessionAttributes;
}
public boolean isAllowRequestOverride() {
return this.allowRequestOverride;
}
public void setAllowRequestOverride(boolean allowRequestOverride) {
this.allowRequestOverride = allowRequestOverride;
}
public boolean isExposeSpringMacroHelpers() {
return this.exposeSpringMacroHelpers;
}
public void setExposeSpringMacroHelpers(boolean exposeSpringMacroHelpers) {
this.exposeSpringMacroHelpers = exposeSpringMacroHelpers;
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.template;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
/**
* Helper class for use by configuration classes that provide an
* {@link AbstractTemplateViewResolver} bean.
*
* @author Andy Wilkinson
*/
public class TemplateViewResolverConfigurer {
/**
* Configures the {@code resolver} using the given {@code properties} and defaults.
*
* @param resolver The resolver to configure
* @param properties The properties to use to configure the resolver
*/
public void configureTemplateViewResolver(AbstractTemplateViewResolver resolver,
AbstractTemplateViewResolverProperties properties) {
resolver.setPrefix(properties.getPrefix());
resolver.setSuffix(properties.getSuffix());
resolver.setCache(properties.isCache());
resolver.setContentType(properties.getContentType());
resolver.setViewNames(properties.getViewNames());
resolver.setExposeRequestAttributes(properties.isExposeRequestAttributes());
resolver.setAllowRequestOverride(properties.isAllowRequestOverride());
resolver.setExposeSessionAttributes(properties.isExposeSessionAttributes());
resolver.setExposeSpringMacroHelpers(properties.isExposeSpringMacroHelpers());
resolver.setRequestContextAttribute(properties.getRequestContextAttribute());
// This resolver acts as a fallback resolver (e.g. like a
// InternalResourceViewResolver) so it needs to have low precedence
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
}
}

View File

@@ -0,0 +1,136 @@
/*
* 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.velocity;
import java.io.IOException;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.servlet.Servlet;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.VelocityException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.template.TemplateViewResolverConfigurer;
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.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.ui.velocity.VelocityEngineFactory;
import org.springframework.ui.velocity.VelocityEngineFactoryBean;
import org.springframework.util.Assert;
import org.springframework.web.servlet.view.velocity.VelocityConfig;
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Velocity.
*
* @author Andy Wilkinson
* @since 1.1.0
*/
@Configuration
@ConditionalOnClass(VelocityEngine.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties(VelocityProperties.class)
public class VelocityAutoConfiguration {
@Autowired
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
@Autowired
private VelocityProperties properties;
@PostConstruct
public void checkTemplateLocationExists() {
if (this.properties.isCheckTemplateLocation()) {
Resource resource = this.resourceLoader.getResource(this.properties
.getResourceLoaderPath());
Assert.state(resource.exists(), "Cannot find template location: " + resource
+ " (please add some templates "
+ "or check your Velocity configuration)");
}
}
protected static class VelocityConfiguration {
@Autowired
protected VelocityProperties properties;
protected void applyProperties(VelocityEngineFactory factory) {
factory.setResourceLoaderPath(this.properties.getResourceLoaderPath());
Properties velocityProperties = new Properties();
velocityProperties.putAll(this.properties.getProperties());
factory.setVelocityProperties(velocityProperties);
}
}
@Configuration
@ConditionalOnNotWebApplication
public static class VelocityNonWebConfiguration extends VelocityConfiguration {
@Bean
@ConditionalOnMissingBean
public VelocityEngineFactoryBean velocityConfiguration() {
VelocityEngineFactoryBean velocityEngineFactoryBean = new VelocityEngineFactoryBean();
applyProperties(velocityEngineFactoryBean);
return velocityEngineFactoryBean;
}
}
@Configuration
@ConditionalOnClass(Servlet.class)
@ConditionalOnWebApplication
public static class VelocityWebConfiguration extends VelocityConfiguration {
@Bean
@ConditionalOnMissingBean(VelocityConfig.class)
public VelocityConfigurer velocityConfigurer() {
VelocityConfigurer configurer = new VelocityConfigurer();
applyProperties(configurer);
return configurer;
}
@Bean
public VelocityEngine velocityEngine(VelocityConfigurer configurer)
throws VelocityException, IOException {
return configurer.createVelocityEngine();
}
@Bean
@ConditionalOnMissingBean(name = "velocityViewResolver")
public VelocityViewResolver velocityViewResolver() {
VelocityViewResolver resolver = new VelocityViewResolver();
new TemplateViewResolverConfigurer().configureTemplateViewResolver(resolver,
this.properties);
resolver.setToolboxConfigLocation(this.properties.getToolboxConfigLocation());
resolver.setDateToolAttribute(this.properties.getDateToolAttribute());
resolver.setNumberToolAttribute(this.properties.getNumberToolAttribute());
return resolver;
}
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.velocity;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.autoconfigure.template.AbstractTemplateViewResolverProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* {@link ConfigurationProperties} for configuring Velocity
*
* @author Andy Wilkinson
*
* @since 1.1.0
*/
@ConfigurationProperties(prefix = "spring.velocity")
public class VelocityProperties extends AbstractTemplateViewResolverProperties {
public static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:/templates/";
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = ".vm";
private String dateToolAttribute;
private String numberToolAttribute;
private Map<String, String> properties = new HashMap<String, String>();
private String resourceLoaderPath = DEFAULT_RESOURCE_LOADER_PATH;
private String toolboxConfigLocation;
public VelocityProperties() {
super(DEFAULT_PREFIX, DEFAULT_SUFFIX);
}
public String getDateToolAttribute() {
return this.dateToolAttribute;
}
public void setDateToolAttribute(String dateToolAttribute) {
this.dateToolAttribute = dateToolAttribute;
}
public String getNumberToolAttribute() {
return this.numberToolAttribute;
}
public void setNumberToolAttribute(String numberToolAttribute) {
this.numberToolAttribute = numberToolAttribute;
}
public Map<String, String> getProperties() {
return this.properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public String getResourceLoaderPath() {
return this.resourceLoaderPath;
}
public void setResourceLoaderPath(String resourceLoaderPath) {
this.resourceLoaderPath = resourceLoaderPath;
}
public String getToolboxConfigLocation() {
return this.toolboxConfigLocation;
}
public void setToolboxConfigLocation(String toolboxConfigLocation) {
this.toolboxConfigLocation = toolboxConfigLocation;
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.velocity;
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
* Velocity view templates
*
* @author Andy Wilkinson
* @since 1.1.0
*/
public class VelocityTemplateAvailabilityProvider implements TemplateAvailabilityProvider {
@Override
public boolean isTemplateAvailable(String view, Environment environment,
ClassLoader classLoader, ResourceLoader resourceLoader) {
if (ClassUtils.isPresent("org.apache.velocity.app.VelocityEngine", classLoader)) {
String loaderPath = environment.getProperty(
"spring.velocity.resourceLoaderPath",
VelocityProperties.DEFAULT_RESOURCE_LOADER_PATH);
String prefix = environment.getProperty("spring.velocity.prefix",
VelocityProperties.DEFAULT_PREFIX);
String suffix = environment.getProperty("spring.velocity.suffix",
VelocityProperties.DEFAULT_SUFFIX);
return resourceLoader.getResource(loaderPath + prefix + view + suffix)
.exists();
}
return false;
}
}

View File

@@ -31,6 +31,7 @@ org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
@@ -46,4 +47,5 @@ org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.velocity.VelocityTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider

View File

@@ -0,0 +1,198 @@
/*
* 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.velocity;
import java.io.File;
import java.io.StringWriter;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
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 org.springframework.web.servlet.view.velocity.VelocityConfigurer;
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
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 {@link VelocityAutoConfiguration}.
*
* @author Andy Wilkinson
*/
public class VelocityAutoConfigurationTests {
private AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
@Before
public void setupContext() {
this.context.setServletContext(new MockServletContext());
}
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void defaultConfiguration() {
registerAndRefreshContext();
assertThat(this.context.getBean(VelocityViewResolver.class), notNullValue());
assertThat(this.context.getBean(VelocityConfigurer.class), notNullValue());
}
@Test(expected = BeanCreationException.class)
public void nonExistentTemplateLocation() {
registerAndRefreshContext("spring.velocity.resourceLoaderPath:"
+ "classpath:/does-not-exist/");
}
@Test
public void emptyTemplateLocation() {
new File("target/test-classes/templates/empty-directory").mkdir();
registerAndRefreshContext("spring.velocity.resourceLoaderPath:"
+ "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 customContentType() throws Exception {
registerAndRefreshContext("spring.velocity.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.velocity.prefix:prefix/");
MockHttpServletResponse response = render("prefixed");
String result = response.getContentAsString();
assertThat(result, containsString("prefixed"));
}
@Test
public void customSuffix() throws Exception {
registerAndRefreshContext("spring.velocity.suffix:.freemarker");
MockHttpServletResponse response = render("suffixed");
String result = response.getContentAsString();
assertThat(result, containsString("suffixed"));
}
@Test
public void customTemplateLoaderPath() throws Exception {
registerAndRefreshContext("spring.velocity.resourceLoaderPath:classpath:/custom-templates/");
MockHttpServletResponse response = render("custom");
String result = response.getContentAsString();
assertThat(result, containsString("custom"));
}
@Test
public void disableCache() {
registerAndRefreshContext("spring.velocity.cache:false");
assertThat(this.context.getBean(VelocityViewResolver.class).getCacheLimit(),
equalTo(0));
}
@Test
public void customFreeMarkerSettings() {
registerAndRefreshContext("spring.velocity.properties.directive.parse.max.depth:10");
assertThat(this.context.getBean(VelocityConfigurer.class).getVelocityEngine()
.getProperty("directive.parse.max.depth"), equalTo((Object) "10"));
}
@Test
public void renderTemplate() throws Exception {
registerAndRefreshContext();
VelocityConfigurer velocity = this.context.getBean(VelocityConfigurer.class);
StringWriter writer = new StringWriter();
Template template = velocity.getVelocityEngine().getTemplate("message.vm");
template.process();
VelocityContext velocityContext = new VelocityContext();
velocityContext.put("greeting", "Hello World");
template.merge(velocityContext, writer);
assertThat(writer.toString(), containsString("Hello World"));
}
@Test
public void renderNonWebAppTemplate() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
VelocityAutoConfiguration.class);
try {
VelocityEngine velocity = context.getBean(VelocityEngine.class);
StringWriter writer = new StringWriter();
Template template = velocity.getTemplate("message.vm");
template.process();
VelocityContext velocityContext = new VelocityContext();
velocityContext.put("greeting", "Hello World");
template.merge(velocityContext, writer);
assertThat(writer.toString(), containsString("Hello World"));
}
finally {
context.close();
}
}
private void registerAndRefreshContext(String... env) {
EnvironmentTestUtils.addEnvironment(this.context, env);
this.context.register(VelocityAutoConfiguration.class);
this.context.refresh();
}
public String getGreeting() {
return "Hello World";
}
private MockHttpServletResponse render(String viewName) throws Exception {
VelocityViewResolver resolver = this.context.getBean(VelocityViewResolver.class);
View view = resolver.resolveViewName(viewName, Locale.UK);
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;
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.velocity;
import org.junit.Test;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.mock.env.MockEnvironment;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Tests for {@link VelocityTemplateAvailabilityProvider}.
*
* @author Andy Wilkinson
*/
public class VelocityTemplateAvailabilityProviderTests {
private final TemplateAvailabilityProvider provider = new VelocityTemplateAvailabilityProvider();
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
private final MockEnvironment environment = new MockEnvironment();
@Test
public void availabilityOfTemplateInDefaultLocation() {
assertTrue(this.provider.isTemplateAvailable("home", this.environment, getClass()
.getClassLoader(), this.resourceLoader));
}
@Test
public void availabilityOfTemplateThatDoesNotExist() {
assertFalse(this.provider.isTemplateAvailable("whatever", this.environment,
getClass().getClassLoader(), this.resourceLoader));
}
@Test
public void availabilityOfTemplateWithCustomLoaderPath() {
this.environment.setProperty("spring.velocity.resourceLoaderPath",
"classpath:/custom-templates/");
assertTrue(this.provider.isTemplateAvailable("custom", this.environment,
getClass().getClassLoader(), this.resourceLoader));
}
@Test
public void availabilityOfTemplateWithCustomPrefix() {
this.environment.setProperty("spring.velocity.prefix", "prefix/");
assertTrue(this.provider.isTemplateAvailable("prefixed", this.environment,
getClass().getClassLoader(), this.resourceLoader));
}
@Test
public void availabilityOfTemplateWithCustomSuffix() {
this.environment.setProperty("spring.velocity.suffix", ".freemarker");
assertTrue(this.provider.isTemplateAvailable("suffixed", this.environment,
getClass().getClassLoader(), this.resourceLoader));
}
}

View File

@@ -0,0 +1 @@
custom

View File

@@ -0,0 +1 @@
home

View File

@@ -0,0 +1 @@
Message: ${greeting}

View File

@@ -0,0 +1 @@
prefixed

View File

@@ -114,6 +114,8 @@
<thymeleaf-extras-springsecurity3.version>2.1.1.RELEASE</thymeleaf-extras-springsecurity3.version>
<thymeleaf-layout-dialect.version>1.2.4</thymeleaf-layout-dialect.version>
<tomcat.version>7.0.53</tomcat.version>
<velocity.version>1.7</velocity.version>
<velocity-tools.version>2.0</velocity-tools.version>
</properties>
<prerequisites>
<maven>3.0.0</maven>
@@ -267,6 +269,11 @@
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
@@ -450,6 +457,16 @@
<artifactId>tomcat-jsp-api</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>${velocity.version}</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>${velocity-tools.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>

View File

@@ -94,6 +94,7 @@ content into your application; rather pick only the properties that you need.
spring.freemarker.exposeSpringMacroHelpers=false
spring.freemarker.prefix=
spring.freemarker.requestContextAttribute=
spring.freemarker.settings.*=
spring.freemarker.suffix=.ftl
spring.freemarker.templateEncoding=UTF-8
spring.freemarker.templateLoaderPath=classpath:/templates/
@@ -103,17 +104,36 @@ content into your application; rather pick only the properties that you need.
spring.groovy.template.allowRequestOverride=false
spring.groovy.template.allowSessionOverride=false
spring.groovy.template.cache=true
spring.groovy.template.configuration.*= # See Groovy's TemplateConfiguration
spring.groovy.template.contentType=text/html
spring.groovy.template.prefix=classpath:/templates/
spring.groovy.template.suffix=.tpl
spring.groovy.template.templateEncoding=UTF-8
spring.groovy.template.viewNames= # whitelist of view names that can be resolved
spring.groovy.template.configuration.*= # See Groovy's TemplateConfiguration
# VELOCITY TEMPLATES ({sc-spring-boot-autoconfigure}}/velocity/VelocityAutoConfiguration.{sc-ext}[VelocityAutoConfiguration])
spring.velocity.allowRequestOverride=false
spring.velocity.allowSessionOverride=false
spring.velocity.cache=true
spring.velocity.checkTemplateLocation=true
spring.velocity.contentType=text/html
spring.velocity.dateToolAttribute=
spring.velocity.exposeRequestAttributes=false
spring.velocity.exposeSessionAttributes=false
spring.velocity.exposeSpringMacroHelpers=false
spring.velocity.numberToolAttribute=
spring.velocity.prefix=
spring.velocity.properties.*=
spring.velocity.requestContextAttribute=
spring.velocity.resourceLoaderPath=classpath:/templates/
spring.velocity.suffix=.ftl
spring.velocity.templateEncoding=UTF-8
spring.velocity.viewNames= # whitelist of view names that can be resolved
# INTERNATIONALIZATION ({sc-spring-boot-autoconfigure}/MessageSourceAutoConfiguration.{sc-ext}[MessageSourceAutoConfiguration])
spring.messages.basename=messages
spring.messages.cacheSeconds=-1
spring.messages.encoding=UTF-8
spring.messages.cacheSeconds=-1
[[common-application-properties-security]]
# SECURITY ({sc-spring-boot-autoconfigure}/security/SecurityProperties.{sc-ext}[SecurityProperties])

View File

@@ -41,6 +41,9 @@ The following auto-configuration classes are from the `spring-boot-autoconfigure
|{sc-spring-boot-autoconfigure}/freemarker/FreeMarkerAutoConfiguration.{sc-ext}[FreeMarkerAutoConfiguration]
|{dc-spring-boot-autoconfigure}/freemarker/FreeMarkerAutoConfiguration.{dc-ext}[javadoc]
|{sc-spring-boot-autoconfigure}/groovy/templates/GroovyTemplateAutoConfiguration.{sc-ext}[GroovyTemplateAutoConfiguration]
|{dc-spring-boot-autoconfigure}/groovy/templates/GroovyTemplateAutoConfiguration.{dc-ext}[javadoc]
|{sc-spring-boot-autoconfigure}/orm/jpa/HibernateJpaAutoConfiguration.{sc-ext}[HibernateJpaAutoConfiguration]
|{dc-spring-boot-autoconfigure}/orm/jpa/HibernateJpaAutoConfiguration.{dc-ext}[javadoc]
@@ -95,6 +98,9 @@ The following auto-configuration classes are from the `spring-boot-autoconfigure
|{sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[ThymeleafAutoConfiguration]
|{dc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{dc-ext}[javadoc]
|{sc-spring-boot-autoconfigure}/velocity/VelocityAutoConfiguration.{sc-ext}[VelocityAutoConfiguration]
|{dc-spring-boot-autoconfigure}/velocity/VelocityAutoConfiguration.{dc-ext}[javadoc]
|{sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[WebMvcAutoConfiguration]
|{dc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{dc-ext}[javadoc]

View File

@@ -813,20 +813,28 @@ added.
``freeMarkerViewResolver''. It looks for resources in a loader path (externalized to
`spring.freemarker.templateLoaderPath`, default ``classpath:/templates/'') by
surrounding the view name with a prefix and suffix (externalized to `spring.freemarker.prefix`
and `spring.freemarker.suffix`, defaults ``'' and ``.ftl'' respectively). It can be overriden
and `spring.freemarker.suffix`, with empty and ``.ftl'' defaults respectively). It can be overriden
by providing a bean of the same name.
* If you use Groovy templates (actually if groovy-templates is on your classpath) you
also have a `Groovy TemplateViewResolver` with id
* If you use Groovy templates (actually if groovy-templates is on your classpath) you will
also have a `Groovy TemplateViewResolver` with id
``groovyTemplateViewResolver''. It looks for resources in a loader path by
surrounding the view name with a prefix and suffix (externalized to `spring.groovy.template.prefix`
and `spring.groovy.template.suffix`, defaults ``classpath:/templates/'' and ``.tpl'' respectively). It can be overriden
by providing a bean of the same name.
surrounding the view name with a prefix and suffix (externalized to
`spring.groovy.template.prefix` and `spring.groovy.template.suffix`, defaults
``classpath:/templates/'' and ``.tpl'' respectively). It can be overriden by providing a bean of
the same name.
* If you use Velocity you will also have a `VelocityViewResolver` with id ``velocityViewResolver''.
It looks for resources in a loader path (externalized to `spring.velocity.resourceLoaderPath`,
default ``classpath:/templates/'') by surrounding the view name with a prefix and suffix
(externalized to `spring.velocity.prefix' and `spring.velocity.suffix`, with empty and ``.vm''
defaults respectively). It can be overridden by providing a bean of the same name.
Check out {sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[`WebMvcAutoConfiguration`],
{sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[`ThymeleafAutoConfiguration`],
{sc-spring-boot-autoconfigure}/groovy/template/GroovyTemplateAutoConfiguration.{sc-ext}['GroovyTemplateAutoConfiguration'] and
{sc-spring-boot-autoconfigure}/freemarker/FreeMarkerAutoConfiguration.{sc-ext}['FreeMarkerAutoConfiguration']
{sc-spring-boot-autoconfigure}/freemarker/FreeMarkerAutoConfiguration.{sc-ext}[`FreeMarkerAutoConfiguration`],
{sc-spring-boot-autoconfigure}/groovy/template/GroovyTemplateAutoConfiguration.{sc-ext}[`GroovyTemplateAutoConfiguration`] and
{sc-spring-boot-autoconfigure}/velocity/VelocityAutoConfiguration.{sc-ext}[`VelocityAutoConfiguration`]
@@ -1279,12 +1287,13 @@ The Actuator installs a ``whitelabel'' error page that you will see in browser c
you encounter a server error (machine clients consuming JSON and other media types should
see a sensible response with the right error code). To switch it off you can set
`error.whitelabel.enabled=false`, but normally in addition or alternatively to that you
will want to add your own error page replacing the whitelabel one. If you are using
Thymeleaf or FreeMarker you can do this by adding an `error.html` or `error.ftl` template
respectively. In general what you need is a `View` that resolves with a name of `error`,
and/or a `@Controller` that handles the `/error` path. Unless you replaced some of the
default configuration you should find a `BeanNameViewResolver` in your `ApplicationContext`
so a `@Bean` with id `error` would be a simple way of doing that.
will want to add your own error page replacing the whitelabel one. Exactly how you do this
dependns on the templating technology that you are using. For example, if you are using
Thymeleaf you would add an `error.html` template and if you are using FreeMarker you would
add an `error.ftl` template. In general what you need is a `View` that resolves with a name
of `error`, and/or a `@Controller` that handles the `/error` path. Unless you replaced some
of the default configuration you should find a `BeanNameViewResolver` in your
`ApplicationContext` so a `@Bean` with id `error` would be a simple way of doing that.
Look at {sc-spring-boot-autoconfigure}/web/ErrorMvcAutoConfiguration.{sc-ext}[`ErrorMvcAutoConfiguration`] for more options.
@@ -1403,6 +1412,13 @@ If you are using Groovy templates, then set `spring.groovy.template.cache` to `f
for other Groovy customization options.
[[howto-reload-velocity-content]]
=== Reload Velocity templates without restarting the container
If you are using Velocity, then set `spring.velocity.cache` to `false`. See
{sc-spring-boot-autoconfigure}/velocity/VelocityAutoConfiguration.{sc-ext}[`VelocityAutoConfiguration`]
for other Velocity customization options.
[[howto-reload-java-classes-without-restarting]]
=== Reload Java classes without restarting the container
Modern IDEs (Eclipse, IDEA, etc.) all support hot swapping of bytecode, so if you make a

View File

@@ -906,27 +906,26 @@ and it will be silently ignored by most build tools if you generate a jar.
[[boot-features-spring-mvc-template-engines]]
==== Template engines
As well as REST web services, you can also use Spring MVC to serve
dynamic HTML content. Spring MVC supports a variety of templating
technologies including: Velocity, FreeMarker and JSPs. Many
As well as REST web services, you can also use Spring MVC to serve dynamic HTML content. Spring
MVC supports a variety of templating technologies including Velocity, FreeMarker and JSPs. Many
other templating engines also ship their own Spring MVC integrations.
Spring Boot includes auto-configuration support for the Thymeleaf,
[FreeMarker](http://freemarker.org/docs/) and
[Groovy](http://beta.groovy-lang.org/docs/groovy-2.3.0/html/documentation/markup-template-engine.html)
templating engines. Thymeleaf is an XML/XHTML/HTML5 template engine
that can work both in web and non-web environments. If allows you to
create natural templates that can be correctly displayed by browsers
and therefore work also as static prototypes. Your FreeMarker, Groovy
and Thymeleaf templates will be picked up automatically from
`src/main/resources/templates`.
Spring Boot includes auto-configuration support for the following templating engines:
- http://freemarker.org/docs/[FreeMarker]
- http://beta.groovy-lang.org/docs/groovy-2.3.0/html/documentation/markup-template-engine.html[Groovy]
- http://www.thymeleaf.org[Thymeleaf]
- http://velocity.apache.org[Velocity]
When you're using one of these templating engines with the default configuration, your templates
will be picked up automatically from `src/main/resources/templates`.
TIP: JSPs should be avoided if possible, there are several
<<boot-features-jsp-limitations, known limitations>> when using them with embedded
servlet containers.
[[boot-features-error-handling]]
==== Error Handling
Spring Boot provides an `/error` mapping by default that handles all errors in a

View File

@@ -258,6 +258,9 @@ and Hibernate.
|`spring-boot-starter-thymeleaf`
|Support for the Thymeleaf templating engine, including integration with Spring.
|`spring-boot-starter-velocity`
|Support for the Velocity templating engine
|`spring-boot-starter-web`
|Support for full-stack web development, including Tomcat and `spring-webmvc`.

View File

@@ -49,6 +49,7 @@
<module>spring-boot-sample-web-static</module>
<module>spring-boot-sample-web-jsp</module>
<module>spring-boot-sample-web-ui</module>
<module>spring-boot-sample-web-velocity</module>
<module>spring-boot-sample-websocket</module>
<module>spring-boot-sample-xml</module>
</modules>

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-web-velocity</artifactId>
<name>Spring Boot Web Velocity Sample</name>
<description>Spring Boot Web Velocity Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<m2eclipse.wtp.contextRoot>/</m2eclipse.wtp.contextRoot>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,33 @@
/*
* 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 sample.velocity;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class SampleWebVelocityApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleWebVelocityApplication.class, args);
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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 sample.velocity;
import java.util.Date;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class WelcomeController {
@Value("${application.message:Hello World}")
private String message = "Hello World";
@RequestMapping("/")
public String welcome(Map<String, Object> model) {
model.put("time", new Date());
model.put("message", this.message);
return "welcome";
}
}

View File

@@ -0,0 +1,2 @@
application.message: Hello, Andy
spring.velocity.dateToolAttribute: dateTool

View File

@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<body>
Something went wrong: ${status} ${error}
</body>
</html>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<body>
<span>Time:</span>
<ul>
<li>From controller: $time</li>
<li>From velocity: $dateTool</li>
</ul>
<span>Message: $message</span>
</body>
</html>

View File

@@ -0,0 +1,80 @@
/*
* 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 sample.velocity;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Basic integration tests for Velocity application.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SampleWebVelocityApplication.class)
@WebAppConfiguration
@IntegrationTest("server.port=0")
@DirtiesContext
public class SampleWebVelocityApplicationTests {
@Value("${local.server.port}")
private int port;
@Test
public void testVelocityTemplate() throws Exception {
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
"http://localhost:" + this.port, String.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
assertTrue("Wrong body:\n" + entity.getBody(),
entity.getBody().contains("Hello, Andy"));
}
@Test
public void testVelocityErrorTemplate() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
ResponseEntity<String> responseEntity = new TestRestTemplate().exchange(
"http://localhost:" + this.port + "/does-not-exist", HttpMethod.GET,
requestEntity, String.class);
assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode());
assertTrue("Wrong body:\n" + responseEntity.getBody(), responseEntity.getBody()
.contains("Something went wrong: 404 Not Found"));
}
}

View File

@@ -43,6 +43,7 @@
<module>spring-boot-starter-test</module>
<module>spring-boot-starter-thymeleaf</module>
<module>spring-boot-starter-tomcat</module>
<module>spring-boot-starter-velocity</module>
<module>spring-boot-starter-web</module>
<module>spring-boot-starter-websocket</module>
</modules>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-starter-velocity</artifactId>
<name>Spring Boot Velocity Starter</name>
<description>Spring Boot Velocity Starter</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
</dependencies>
</project>