From c7a3c64b40c325c06bec9b6eec63f51c0340aed4 Mon Sep 17 00:00:00 2001 From: Tom McClure Date: Thu, 15 Dec 2016 21:35:29 -0800 Subject: [PATCH] Initial 0.1.0 release --- README.md | 72 +++++++ pom.xml | 171 +++++++++++++++++ .../x5/template/spring/ChunkTemplateView.java | 175 ++++++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/com/x5/template/spring/ChunkTemplateView.java diff --git a/README.md b/README.md index f31cf9e..65597c2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,74 @@ # chunk-springmvc Chunk Templates for Spring MVC + +Facilitates swapping in the Chunk Template engine for Spring MVC projects +in place of jsp or another template engine. + +### Quick start: + +Add the following to your dispatcher-servlet.xml: +``` + + + + + + + + + + + + + + + + + + + + + + +``` + +Complete project setup guide here: +http://www.x5software.com/chunk/wiki/Spring_MVC + +### Notes + +MVC Framework localized messages (defined in messages.properties etc) +are available via a custom tag command: +``` +{% messages.msg.name %} +``` + +Messages can be parameterized like so: ``{% messages.msg.name(`$a`,`$b`) %}`` + +A special request context tag is available, usually {$rc} but the name is +configurable. + +The following request context values are available: +``` + {$rc.uri} + {$rc.context_path} + {$rc.servlet_path} + {$rc.scheme} + {$rc.method} + {$rc.server_name} + {$rc.remote_addr} + {$rc.remote_host} + {$rc.remote_user} +``` + +### Using bean getters in a template + +When exposing beans (or POJO member variables) in a model, keep in mind that +Chunk always converts ``camelCase`` to ``snake_case``. + +So, ``x.getFavoriteColor()`` will be available in the template as +``{% $x.favorite_color %}`` -- and ``x.isBigAndHairy()`` must be checked +like so: +``` +{% if $x.big_and_hairy %}...{% endif %} +``` diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e6c1c73 --- /dev/null +++ b/pom.xml @@ -0,0 +1,171 @@ + + 4.0.0 + com.x5dev + chunk-springmvc + jar + 0.1.0 + Chunk Templates for Spring MVC + Chunk Templates plugin for Spring MVC framework + http://www.x5software.com/chunk/wiki/Spring_MVC + + + UTF-8 + + + + org.sonatype.oss + oss-parent + 7 + + + + + MIT License + http://www.opensource.org/licenses/mit-license.php + repo + + + + + scm:git:git@github.com:tomj74/chunk-springmvc.git + scm:git:git@github.com:tomj74/chunk-springmvc.git + scm:git:git@github.com:tomj74/chunk-springmvc.git + + + + + com.x5dev + chunk-templates + [3.2.4,4.0.0) + + + javax.servlet + servlet-api + 2.5 + provided + + + org.springframework + spring-core + 4.1.5.RELEASE + compile + + + org.springframework + spring-web + 4.1.5.RELEASE + compile + + + org.springframework + spring-webmvc + 4.1.5.RELEASE + compile + + + + + + goredsoxgo + Tom McClure + tom@dagblastit.com + http://www.dagblastit.com/ + X5 Software + http://www.x5software.com/ + + architect + developer + + -8 + + http://tinyurl.com/TomMcClureAvatar + + + + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.0.4 + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.3 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.5 + 1.5 + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + + + release-sign-artifacts + + + performRelease + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.1 + + + sign-artifacts + verify + + sign + + + + + + + + + + diff --git a/src/main/java/com/x5/template/spring/ChunkTemplateView.java b/src/main/java/com/x5/template/spring/ChunkTemplateView.java new file mode 100644 index 0000000..59f85a1 --- /dev/null +++ b/src/main/java/com/x5/template/spring/ChunkTemplateView.java @@ -0,0 +1,175 @@ +package com.x5.template.spring; + +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.core.io.Resource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.web.servlet.support.RequestContext; +import org.springframework.web.servlet.view.InternalResourceView; + +import com.x5.template.Chunk; +import com.x5.template.Snippet; +import com.x5.template.Theme; +import com.x5.template.ThemeConfig; +import com.x5.template.filters.FilterArgs; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * ChunkTemplateView facilitates swapping in the Chunk Template engine + * for Spring MVC projects. + * + * Messages are available via {% messages.msg.name %} + * Messages can be parameterized like so: {% messages.msg.name(`$a`,`$b`) %} + * + * A special request context tag is available, usually {$rc} but the name is + * configurable. + * + * The following request context values are available: + * {$rc.uri} + * {$rc.context_path} + * {$rc.servlet_path} + * {$rc.scheme} + * {$rc.method} + * {$rc.server_name} + * {$rc.remote_addr} + * {$rc.remote_host} + * {$rc.remote_user} + * + * When exposing beans in a model, keep in mind that Chunk always converts + * camelCase to snake_case. So, x.getFavoriteColor() will be available in the + * template as {% $x.favorite_color %} and x.isBigAndHairy() can be checked + * like so: {% if $x.big_and_hairy %}...{% endif %} + */ +public class ChunkTemplateView extends InternalResourceView +{ + private static Theme theme = null; + + @Override + protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) + throws Exception + { + Resource templateFile = getApplicationContext().getResource(getUrl()); + + String rcKey = getRequestContextAttribute(); + RequestContext rc = (RequestContext)model.get(rcKey); + + Theme theme = getTheme(templateFile.getFile().getParent()); + Chunk chunk = theme.makeChunk(getBeanName()); + chunk.setLocale(rc.getLocale()); + chunk.setMultiple(model); + chunk.set(rcKey, mapifyRequestContext(rc, request)); + + PrintWriter writer = response.getWriter(); + chunk.render(writer); + writer.flush(); + writer.close(); + } + + private Map mapifyRequestContext(RequestContext rc, HttpServletRequest request) + { + Map rcMap = new HashMap(); + + // expose some potentially useful info to the template via the {$rc} tag + rcMap.put("uri", rc.getRequestUri()); + rcMap.put("context_path", rc.getContextPath()); + rcMap.put("servlet_path", rc.getPathToServlet()); + rcMap.put("scheme", request.getScheme()); + rcMap.put("method", request.getMethod()); + rcMap.put("server_name", request.getServerName()); + rcMap.put("remote_addr", request.getRemoteAddr()); + rcMap.put("remote_host", request.getRemoteHost()); + rcMap.put("remote_user", request.getRemoteUser()); + + return rcMap; + } + + private Theme getTheme(String path) + { + if (theme == null) { + Map params = new HashMap(); + // If no theme path (for include/exec references) is specified + // in the config, default to the path of the invoked template file. + params.put(ThemeConfig.THEME_PATH, path); + + Map configParams = getConfigParams(); + if (configParams != null) { + for (String key : configParams.keySet()) { + String paramName = key; + String paramValue = configParams.get(key); + // blank values are considered not-provided + if (paramValue != null && paramValue.trim().length() > 0) { + params.put(paramName, paramValue); + } + } + } + ThemeConfig config = new ThemeConfig(params); + theme = new Theme(config); + theme.addProtocol( new MessagesProtocol() ); + } + + return theme; + } + + @SuppressWarnings("unchecked") + private Map getConfigParams() + { + try { + Object config = getApplicationContext().getBean("chunkTemplatesConfig"); + return (Map)config; + } catch (NoSuchBeanDefinitionException e) { + return null; + } + } + + class MessagesProtocol implements com.x5.template.ContentSource + { + public MessagesProtocol() {} + + public String fetch(String resource) + { + FilterArgs argParser = new FilterArgs(resource); + Object[] args = argsAsObjArray(argParser); + String messageRef = argParser.getFilterName(); + Locale locale = LocaleContextHolder.getLocale(); + + return getApplicationContext().getMessage(messageRef, args, locale); + } + + private Object[] argsAsObjArray(FilterArgs parser) + { + String[] args = parser.getFilterArgs(); + if (args == null || args.length == 0) { + return new Object[0]; + } + + Object[] oArgs = new Object[args.length]; + for (int i=0; i