forked from spring-projects/spring-framework
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support Groovy Markup templating in Spring MVC
Solution #1 This commit adds support for Groovy templating, available as of Groovy 2.3.0 (and 2.3.1 for advanced use cases, such as layouts and fragments). To enable this, one should create a new GroovyMarkupViewResolver Bean in their application context. Issue: SPR-11789
- Loading branch information
Showing
17 changed files
with
726 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
...ng-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright 2002-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.web.servlet.view.groovy; | ||
|
||
import groovy.text.Template; | ||
import org.springframework.web.servlet.view.AbstractTemplateView; | ||
|
||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
|
||
import java.io.BufferedWriter; | ||
import java.util.Locale; | ||
import java.util.Map; | ||
|
||
/** | ||
* View using Groovy Markup Templates. | ||
* | ||
* @author Brian Clozel | ||
* @since 4.1 | ||
* @see GroovyMarkupViewResolver | ||
*/ | ||
public class GroovyMarkupView extends AbstractTemplateView { | ||
|
||
private final Template template; | ||
|
||
public GroovyMarkupView(Template template) { | ||
this.template = template; | ||
} | ||
|
||
@Override | ||
protected void renderMergedTemplateModel(Map<String, Object> model, | ||
HttpServletRequest request, HttpServletResponse response) throws Exception { | ||
this.template.make(model).writeTo(new BufferedWriter(response.getWriter())); | ||
} | ||
|
||
/** | ||
* This class is using a pre-compiled groovy template, | ||
* so the template file URL is of no use here. | ||
*/ | ||
@Override | ||
protected boolean isUrlRequired() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean checkResource(Locale locale) throws Exception { | ||
return this.template != null; | ||
} | ||
} |
174 changes: 174 additions & 0 deletions
174
...c/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupViewResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
/* | ||
* Copyright 2002-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.web.servlet.view.groovy; | ||
|
||
import java.net.URL; | ||
import java.net.URLClassLoader; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Locale; | ||
|
||
import groovy.text.Template; | ||
import groovy.text.markup.MarkupTemplateEngine; | ||
import groovy.text.markup.TemplateConfiguration; | ||
|
||
import org.springframework.context.ApplicationContextException; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.web.servlet.View; | ||
import org.springframework.web.servlet.view.AbstractTemplateViewResolver; | ||
import org.springframework.web.servlet.view.AbstractView; | ||
|
||
/** | ||
* Convenience subclass of {@link org.springframework.web.servlet.view.AbstractTemplateViewResolver} | ||
* that supports {@link GroovyMarkupView} (i.e. Groovy XML/XHTML markup templates) and custom subclasses of it. | ||
* | ||
* This ViewResolver requires Groovy 2.3.0 and higher and uses by default an instance of a | ||
* {@link groovy.text.markup.MarkupTemplateEngine}. | ||
* | ||
* @author Brian Clozel | ||
* @author Dave Syer | ||
* @since 4.1 | ||
* @see groovy.text.markup.MarkupTemplateEngine | ||
*/ | ||
public class GroovyMarkupViewResolver extends AbstractTemplateViewResolver { | ||
|
||
private MarkupTemplateEngine engine; | ||
|
||
private final TemplateConfiguration templateConfiguration; | ||
|
||
/** | ||
* Create a GroovyTemplateViewResolver initialized with a {@link MarkupTemplateEngine} | ||
* that's configured with: | ||
* <ul> | ||
* <li>a default {@link TemplateConfiguration} | ||
* <li>a {@link MarkupTemplateResolver} for resolving templates | ||
* <li>a parent classLoader to be used by Groovy to load code and resources within templates | ||
* </ul> | ||
* | ||
* @see #createParentLoaderForTemplates() | ||
*/ | ||
public GroovyMarkupViewResolver() throws Exception { | ||
this(null); | ||
} | ||
|
||
/** | ||
* Create a GroovyTemplateViewResolver using a {@link MarkupTemplateEngine} | ||
* configured with the provided {@link TemplateConfiguration}. | ||
*/ | ||
public GroovyMarkupViewResolver(TemplateConfiguration templateConfiguration) throws Exception { | ||
this.templateConfiguration = | ||
(templateConfiguration != null) ? templateConfiguration : new TemplateConfiguration(); | ||
this.setViewClass(requiredViewClass()); | ||
} | ||
|
||
@Override | ||
protected Class<?> requiredViewClass() { | ||
return GroovyMarkupView.class; | ||
} | ||
|
||
/** | ||
* Set the @{link MarkupTemplateEngine} to use for compiling {@link Template}s. | ||
* This will override the TemplateConfiguration provided in the constructor, | ||
* as well as the default engine configuration. | ||
*/ | ||
public void setEngine(MarkupTemplateEngine engine) { | ||
this.engine = engine; | ||
} | ||
|
||
@Override | ||
protected void initApplicationContext() { | ||
try { | ||
super.initApplicationContext(); | ||
if (this.engine == null) { | ||
this.engine = new MarkupTemplateEngine(this.createParentLoaderForTemplates(), | ||
this.templateConfiguration, new MarkupTemplateResolver()); | ||
} | ||
} catch (Exception exc) { | ||
throw new ApplicationContextException("Could not initialize Groovy Template engine", exc); | ||
} | ||
} | ||
|
||
/** | ||
* Create a parent class loader to be used by the Groovy class loader when | ||
* loading and compiling templates. | ||
*/ | ||
protected ClassLoader createParentLoaderForTemplates() throws Exception { | ||
Resource[] resources = this.getApplicationContext().getResources(this.getPrefix()); | ||
if (resources.length > 0) { | ||
List<URL> urls = new ArrayList<URL>(); | ||
for (Resource resource : resources) { | ||
if (resource.exists()) { | ||
urls.add(resource.getURL()); | ||
} | ||
} | ||
return new URLClassLoader(urls.toArray(new URL[urls.size()]), | ||
getApplicationContext().getClassLoader()); | ||
} | ||
else { | ||
return getApplicationContext().getClassLoader(); | ||
} | ||
} | ||
|
||
/** | ||
* This resolver supports i18n, so cache keys should contain the locale. | ||
*/ | ||
@Override | ||
protected Object getCacheKey(String viewName, Locale locale) { | ||
return viewName + "_" + locale; | ||
} | ||
|
||
@Override | ||
protected View loadView(String viewName, Locale locale) throws Exception { | ||
|
||
URL viewURL = getViewURL(viewName, locale); | ||
if(viewURL == null) { | ||
return null; | ||
} | ||
else { | ||
Template template = this.engine.createTemplate(viewURL); | ||
GroovyMarkupView view = new GroovyMarkupView(template); | ||
|
||
view.setUrl(viewURL.getPath()); | ||
String contentType = getContentType(); | ||
if (contentType != null) { | ||
view.setContentType(contentType); | ||
} | ||
view.setServletContext(getServletContext()); | ||
view.setRequestContextAttribute(getRequestContextAttribute()); | ||
view.setAttributesMap(getAttributesMap()); | ||
|
||
return (View)getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName); | ||
} | ||
} | ||
|
||
private URL getViewURL(String viewName, Locale locale) throws Exception{ | ||
|
||
Resource resource = getApplicationContext().getResource(getPrefix() + viewName | ||
+ "_" + locale.toString().replace("-", "_") + getSuffix()); | ||
|
||
if (!resource.exists()) { | ||
resource = getApplicationContext().getResource(getPrefix() + viewName | ||
+ "_" + locale.getLanguage() + getSuffix()); | ||
} | ||
if (!resource.exists()) { | ||
resource = getApplicationContext().getResource(getPrefix() + viewName + getSuffix()); | ||
} | ||
|
||
return resource.exists() ? resource.getURL() : null; | ||
} | ||
|
||
} |
67 changes: 67 additions & 0 deletions
67
...mvc/src/main/java/org/springframework/web/servlet/view/groovy/MarkupTemplateResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* 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.web.servlet.view.groovy; | ||
|
||
import groovy.text.markup.MarkupTemplateEngine; | ||
import groovy.text.markup.TemplateConfiguration; | ||
import groovy.text.markup.TemplateResolver; | ||
|
||
import java.io.IOException; | ||
import java.net.URL; | ||
import java.util.Locale; | ||
|
||
import org.springframework.context.i18n.LocaleContextHolder; | ||
|
||
/** | ||
* A custom {@link groovy.text.markup.TemplateResolver template resolver} which resolves | ||
* templates using the locale found in the thread locale. This resolver ignores the | ||
* template engine configuration locale. | ||
* | ||
* @author Cedric Champeau | ||
* @author Brian Clozel | ||
* @since 4.1 | ||
* @see LocaleContextHolder | ||
*/ | ||
public class MarkupTemplateResolver implements TemplateResolver { | ||
|
||
private ClassLoader templateClassLoader; | ||
|
||
@Override | ||
public void configure(final ClassLoader templateClassLoader, final TemplateConfiguration configuration) { | ||
this.templateClassLoader = templateClassLoader; | ||
} | ||
|
||
@Override | ||
public URL resolveTemplate(final String templatePath) throws IOException { | ||
MarkupTemplateEngine.TemplateResource resource = MarkupTemplateEngine.TemplateResource.parse(templatePath); | ||
Locale locale = LocaleContextHolder.getLocale(); | ||
URL url = this.templateClassLoader | ||
.getResource(resource.withLocale(locale.toString().replace("-", "_")).toString()); | ||
if (url == null) { | ||
url = this.templateClassLoader | ||
.getResource(resource.withLocale(locale.getLanguage()).toString()); | ||
} | ||
if (url == null) { | ||
url = this.templateClassLoader.getResource(resource.withLocale(null).toString()); | ||
} | ||
if (url == null) { | ||
throw new IOException("Unable to load template:" + templatePath); | ||
} | ||
return url; | ||
} | ||
|
||
} |
9 changes: 9 additions & 0 deletions
9
spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/package-info.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
|
||
/** | ||
* Support classes for the integration of | ||
* <a href="http://beta.groovy-lang.org/docs/groovy-2.3.0/html/documentation/markup-template-engine.html"> | ||
* Groovy Templates</a> as Spring web view technology. | ||
* Contains a View implementation for Groovy templates. | ||
*/ | ||
package org.springframework.web.servlet.view.groovy; | ||
|
Oops, something went wrong.