diff --git a/.gitignore b/.gitignore index 42889b4..e7ab442 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -.idea/ -target/ +.idea/ +target/ *.iml /.settings/ /.classpath diff --git a/README.md b/README.md index 7f927ea..65378b6 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,34 @@ The following reflects the default settings. + + +## Version 2.3.24 - Spring support & type conversion handling +Since version 2.3.24 , this plugin provided accessibility for spring bean , and Struts2 type conversion error handling support. + +### How to use Spring Bean + +* use result type : thymeleaf-spring +* in html template : ${beans.[BeanName]} +* struts.properties : struts.thymeleaf.templateEngineName=spring + +### Hot to use Type conversion support field. + +use this namespace : sth +this diarect supported value and errorclass such as thymeleaf spring support. + +Code example : + + + + ... + + ... + ## License @@ -84,4 +111,4 @@ The following reflects the default settings. 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. \ No newline at end of file + limitations under the License. diff --git a/changelog.2.3.22.txt b/changelog.2.3.22.txt new file mode 100644 index 0000000..3d5f64d --- /dev/null +++ b/changelog.2.3.22.txt @@ -0,0 +1,6 @@ +ChangeLog 2.3.16.3 -> 2.3.22 + +* Add new result-type : "thymeleaf-spring" , usable to spring beans '${beans.(beanName)}'. +* Add new diarect for Struts2 Type convertion error output, namespace and attribute 'sth:field'. +* Add support output Struts2 'Field error' , named 'field'. An example usage ${field['task']}. + diff --git a/pom.xml b/pom.xml index f4d97fe..0c1dfda 100644 --- a/pom.xml +++ b/pom.xml @@ -1,94 +1,120 @@ - 4.0.0 - org.codework - struts2-thymeleaf-plugin - jar - 2.3.16.3 - struts2-thymeleaf-plugin - http://www.codework.org/struts2-thymeleaf-plugin - - UTF-8 - 2.3.16.3 - 2.1.3.RELEASE - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + org.codework + struts2-thymeleaf-plugin + jar + ${struts2.version} + struts2-thymeleaf-plugin + http://www.codework.org/struts2-thymeleaf-plugin + + UTF-8 + 2.3.24 + 2.1.4.RELEASE + 4.1.6.RELEASE + - - - maven-org-repo - http://repo1.maven.org/maven2/ - - - - - javax.servlet - servlet-api - 2.5 - provided - + + + maven-org-repo + http://repo1.maven.org/maven2/ + + + apache.snapshots + ASF Maven 2 Snapshot + https://repository.apache.org/content/groups/snapshots/ + + + + + javax.servlet + servlet-api + 2.5 + provided + - - org.apache.struts - struts2-core - ${struts2.version} - + + org.apache.struts + struts2-core + ${struts2.version} + - - org.thymeleaf - thymeleaf - ${thymeleaf.version} - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - true - 256m - 512m - 1.6 - 1.6 - ${project.build.sourceEncoding} - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-idea-plugin - 2.2 - - true - true - 1.6 - 1.6 - - - - + + org.thymeleaf + thymeleaf + ${thymeleaf.version} + + + org.thymeleaf + thymeleaf-spring4 + ${thymeleaf.version} + + + org.springframework + spring-context + ${spring.version} + + + org.springframework + spring-web + ${spring.version} + + + org.springframework + spring-webmvc + ${spring.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + true + 256m + 512m + 1.6 + 1.6 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-idea-plugin + 2.2 + + true + true + 1.6 + 1.6 + + + + \ No newline at end of file diff --git a/src/main/java/org/codework/struts/plugins/thymeleaf/StrutsContext.java b/src/main/java/org/codework/struts/plugins/thymeleaf/StrutsContext.java index b4e71e5..81a4cb2 100644 --- a/src/main/java/org/codework/struts/plugins/thymeleaf/StrutsContext.java +++ b/src/main/java/org/codework/struts/plugins/thymeleaf/StrutsContext.java @@ -15,17 +15,18 @@ */ package org.codework.struts.plugins.thymeleaf; -import com.opensymphony.xwork2.LocaleProvider; -import org.thymeleaf.context.WebContext; - import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.thymeleaf.context.WebContext; + +import com.opensymphony.xwork2.LocaleProvider; + /** * Extends the {@link org.thymeleaf.context.WebContext} to provide access to the * Struts action. - *

+ * * For actions that implement the {@link com.opensymphony.xwork2.LocaleProvider} * interface (i.e., actions that extend ActionSupport), the action's locale will * be used in this context. Otherwise, the context will default to the diff --git a/src/main/java/org/codework/struts/plugins/thymeleaf/ThymeleafResult.java b/src/main/java/org/codework/struts/plugins/thymeleaf/ThymeleafResult.java index e093974..71b537f 100644 --- a/src/main/java/org/codework/struts/plugins/thymeleaf/ThymeleafResult.java +++ b/src/main/java/org/codework/struts/plugins/thymeleaf/ThymeleafResult.java @@ -15,17 +15,18 @@ */ package org.codework.struts.plugins.thymeleaf; -import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.Result; -import com.opensymphony.xwork2.inject.Inject; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsConstants; import org.codework.struts.plugins.thymeleaf.spi.TemplateEngineProvider; import org.thymeleaf.TemplateEngine; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.Result; +import com.opensymphony.xwork2.inject.Inject; /** * Renders a Thymeleaf template as the result of invoking a Struts action. @@ -40,7 +41,7 @@ public class ThymeleafResult implements Result { /** * The result parameter name to set the name of the template to. - *

+ * * IMPORTANT! Struts2 will look for this field reflectively to determine which * parameter is the default. This allows us to have a simplified result * configuration. Don't remove it! diff --git a/src/main/java/org/codework/struts/plugins/thymeleaf/ThymeleafSpringResult.java b/src/main/java/org/codework/struts/plugins/thymeleaf/ThymeleafSpringResult.java new file mode 100644 index 0000000..fc95a03 --- /dev/null +++ b/src/main/java/org/codework/struts/plugins/thymeleaf/ThymeleafSpringResult.java @@ -0,0 +1,142 @@ +/* + * Copyright 2013 Steven Benitez. + * + * 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.codework.struts.plugins.thymeleaf; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsConstants; +import org.codework.struts.plugins.thymeleaf.spi.TemplateEngineProvider; +import org.springframework.context.ApplicationContext; +import org.springframework.web.context.WebApplicationContext; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.spring4.context.SpringWebContext; + +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ActionSupport; +import com.opensymphony.xwork2.LocaleProvider; +import com.opensymphony.xwork2.Result; +import com.opensymphony.xwork2.inject.Inject; + +/** + * Renders a Thymeleaf-Spring template as the result of invoking a Struts action. + * + * @author Steven Benitez ( Update A-pZ ) + */ +public class ThymeleafSpringResult implements Result { + private String defaultEncoding = "UTF-8"; + private TemplateEngineProvider templateEngineProvider; + private String templateName; + + /** + * The result parameter name to set the name of the template to. + * + * IMPORTANT! Struts2 will look for this field reflectively to determine + * which parameter is the default. This allows us to have a simplified + * result configuration. Don't remove it! + */ + public static final String DEFAULT_PARAM = "templateName"; + + /** instance name of struts2-action */ + public static final String ACTION_VARIABLE_NAME = "action"; + + /** field errors */ + public static final String FIELD_ERRORS_NAME ="field"; + + /** struts2 convertion errors fields and value */ + public static final String OVERRIDES_NAME = "overrides"; + + public ThymeleafSpringResult() { + } + + public ThymeleafSpringResult(String templateName) { + this.templateName = templateName; + } + + @Override + public void execute(ActionInvocation actionInvocation) throws Exception { + TemplateEngine templateEngine = templateEngineProvider.get(); + + HttpServletRequest request = ServletActionContext.getRequest(); + HttpServletResponse response = ServletActionContext.getResponse(); + ServletContext servletContext = ServletActionContext + .getServletContext(); + + Object action = actionInvocation.getAction(); + + // Action instance put to Thymeleaf context. + Map variables = bindStrutsContest(action); + + // Locale by Struts2-Action. + Locale locale = ((LocaleProvider) action).getLocale(); + + // Spring-ApplicationContext. + //ApplicationContext appctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); + ApplicationContext appctx = + (ApplicationContext)servletContext.getAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + + // Use SpringWebContext( by Thymeleaf-spring plugin. ) + SpringWebContext context = new SpringWebContext(request, response, + servletContext, locale, variables, appctx); + + // response to TemplateEngine. + response.setContentType("text/html"); + response.setCharacterEncoding(defaultEncoding); + templateEngine.process(templateName, context, response.getWriter()); + } + + @Inject(StrutsConstants.STRUTS_I18N_ENCODING) + public void setDefaultEncoding(String defaultEncoding) { + this.defaultEncoding = defaultEncoding; + } + + @Inject + public void setTemplateEngineProvider( + TemplateEngineProvider templateEngineProvider) { + this.templateEngineProvider = templateEngineProvider; + } + + public void setTemplateName(String templateName) { + this.templateName = templateName; + } + + /** + * Binding Struts2 action and context, and field-errors list binding "field". + * @param action Action instance + * @return ContextMap + */ + Map bindStrutsContest(Object action) { + Map variables = new HashMap(); + variables.put(ACTION_VARIABLE_NAME, action); + + if ( action instanceof ActionSupport) { + ActionSupport actSupport = (ActionSupport)action; + + // Struts2 field errors.( Map) + Map> fieldErrors = actSupport.getFieldErrors(); + variables.put(FIELD_ERRORS_NAME, fieldErrors); + } + + return variables; + } +} diff --git a/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/FieldAttrProcessor.java b/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/FieldAttrProcessor.java new file mode 100644 index 0000000..ea72d24 --- /dev/null +++ b/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/FieldAttrProcessor.java @@ -0,0 +1,88 @@ +/** + * + */ +package org.codework.struts.plugins.thymeleaf.diarect; + +import java.util.Map; + +import org.apache.commons.lang3.StringEscapeUtils; +import org.thymeleaf.Arguments; +import org.thymeleaf.dom.Element; +import org.thymeleaf.processor.attr.AbstractAttributeModifierAttrProcessor; +import org.thymeleaf.standard.processor.attr.AbstractStandardSingleAttributeModifierAttrProcessor; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.util.ValueStack; + +/** + * Thymeleaf extensions,field. + * @author A-pZ + * + */ +public class FieldAttrProcessor extends AbstractStandardSingleAttributeModifierAttrProcessor { + public static final int ATTR_PRECEDENCE = 1010; + public static final String ATTR_NAME = "value"; + + public FieldAttrProcessor() { + super(ATTR_NAME); + } + + protected String getTargetAttributeValue(Arguments arguments, Element element, String attributeName) + { + String attributeValue = super.getTargetAttributeValue(arguments, element, attributeName); + + String name = element.getAttributeValueFromNormalizedName("name"); + String type = element.getAttributeValueFromNormalizedName("type"); + return processOverridesValue(name,attributeValue); + } + + /** + * If Type-Convertion Error found at Struts2, overwrite request-parameter same name. + * + * @param name parameter-name + * @param value thymeleaf parameter-value + * @return request-parameter-value(if convertion error occurs,return from struts2 , not else thymeleaf.) + */ + protected String processOverridesValue(String name , String value) { + ActionContext ctx = ActionContext.getContext(); + ValueStack stack = ctx.getValueStack(); + Map overrideMap = stack.getExprOverrides(); + + if ( overrideMap == null || overrideMap.isEmpty()) { + return value; + } + + if (! overrideMap.containsKey(name)) { + return value; + } + + + String convertionValue = (String)overrideMap.get(name); + + // Struts2-Conponent is wrapped String quote, which erase for output value. + String altString = StringEscapeUtils.unescapeJava(convertionValue); + altString = altString.substring(1, altString.length() -1); + + return altString; + } + + @Override + protected String getTargetAttributeName(Arguments paramArguments, Element paramElement, String paramString) { + return ATTR_NAME; + } + + @Override + protected ModificationType getModificationType(Arguments paramArguments, Element paramElement, String paramString1, String paramString2) { + return AbstractAttributeModifierAttrProcessor.ModificationType.SUBSTITUTION; + } + + @Override + protected boolean removeAttributeIfEmpty(Arguments paramArguments, Element paramElement, String paramString1, String paramString2) { + return false; + } + + @Override + public int getPrecedence() { + return ATTR_PRECEDENCE; + } +} diff --git a/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/FieldDialect.java b/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/FieldDialect.java new file mode 100644 index 0000000..da27207 --- /dev/null +++ b/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/FieldDialect.java @@ -0,0 +1,31 @@ +/** + * + */ +package org.codework.struts.plugins.thymeleaf.diarect; + +import java.util.HashSet; +import java.util.Set; + +import org.thymeleaf.dialect.AbstractDialect; +import org.thymeleaf.processor.IProcessor; + +/** + * diarect:sth. + * @author A-pZ + * + */ +public class FieldDialect extends AbstractDialect { + + @Override + public String getPrefix() { + return "sth"; + } + + public Set getProcessors() { + final Set processors = new HashSet(); + processors.add(new FieldAttrProcessor()); + processors.add(new Struts2FieldErrorAttrProcessor()); + return processors; + } + +} diff --git a/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/Struts2FieldErrorAttrProcessor.java b/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/Struts2FieldErrorAttrProcessor.java new file mode 100644 index 0000000..9b52c93 --- /dev/null +++ b/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/Struts2FieldErrorAttrProcessor.java @@ -0,0 +1,119 @@ +/** + * + */ +package org.codework.struts.plugins.thymeleaf.diarect; + +import java.util.List; +import java.util.Map; + +import org.thymeleaf.Arguments; +import org.thymeleaf.dom.Element; +import org.thymeleaf.standard.processor.attr.AbstractStandardSingleAttributeModifierAttrProcessor; +import org.thymeleaf.util.StringUtils; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionSupport; + +/** + * IF Struts2-Fielderror raise, append css-class for field. + * + * @author A-pZ +*/ +public class Struts2FieldErrorAttrProcessor extends + AbstractStandardSingleAttributeModifierAttrProcessor { + + public static final int ATTR_PRECEDENCE = 1010; + public static final String ATTR_NAME = "errorclass"; + public static final String TARGET_ATTR_NAME = "class"; + + /** + * Default Constructor. + */ + public Struts2FieldErrorAttrProcessor() { + super(ATTR_NAME); + } + + /** + * Target attirbute name to append class. + * + * @see org.thymeleaf.processor.attr.AbstractSingleAttributeModifierAttrProcessor#getTargetAttributeName(org.thymeleaf.Arguments, + * org.thymeleaf.dom.Element, java.lang.String) + */ + @Override + protected String getTargetAttributeName(Arguments arguments, + Element element, String attributeName) { + return TARGET_ATTR_NAME; + } + + /** + * Get attribute value 'errorclass'. + * + * @return errorclass value + */ + protected String getTargetAttributeValue(final Arguments arguments, + final Element element, final String attributeName) { + + Object action = ActionContext.getContext().getActionInvocation() + .getAction(); + // check action instance 'ActionSupport'. + if (!(action instanceof ActionSupport)) { + return BLANK; + } + + ActionSupport asupport = (ActionSupport) action; + Map> fieldErrors = asupport.getFieldErrors(); + if (fieldErrors == null || fieldErrors.size() == 0) { + return BLANK; + } + + final String fieldName = element.getAttributeValue("name"); + if (StringUtils.isEmptyOrWhitespace(fieldName)) { + return BLANK; + } + + List fieldErrorList = fieldErrors.get(fieldName); + if ( fieldErrorList == null || fieldErrorList.size() == 0 ) { + return BLANK; + } + + return super.getTargetAttributeValue(arguments, element, attributeName); + } + + /** + * Attribute write type. APPEND_WITH_SPACE is append attirbute before white + * space. + * + * @see org.thymeleaf.processor.attr.AbstractAttributeModifierAttrProcessor#getModificationType(org.thymeleaf.Arguments, + * org.thymeleaf.dom.Element, java.lang.String, java.lang.String) + */ + @Override + protected ModificationType getModificationType(Arguments arguments, + Element element, String attributeName, String newAttributeName) { + return ModificationType.APPEND_WITH_SPACE; + } + + /** + * Empty attribute behavior. + * + * @see org.thymeleaf.processor.attr.AbstractAttributeModifierAttrProcessor#removeAttributeIfEmpty(org.thymeleaf.Arguments, + * org.thymeleaf.dom.Element, java.lang.String, java.lang.String) + */ + @Override + protected boolean removeAttributeIfEmpty(Arguments arguments, + Element element, String attributeName, String newAttributeName) { + return true; + } + + /** + * Return this processor precedence. + * + * @see org.thymeleaf.processor.AbstractProcessor#getPrecedence() + */ + @Override + public int getPrecedence() { + return ATTR_PRECEDENCE; + } + + private static final String BLANK = ""; + +} diff --git a/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/package-info.java b/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/package-info.java new file mode 100644 index 0000000..25d35f4 --- /dev/null +++ b/src/main/java/org/codework/struts/plugins/thymeleaf/diarect/package-info.java @@ -0,0 +1,6 @@ +/** + * Struts2-Spring-Thymeleaf diarect extension. + * @author A-pZ + * + */ +package org.codework.struts.plugins.thymeleaf.diarect; \ No newline at end of file diff --git a/src/main/java/org/codework/struts/plugins/thymeleaf/spi/DefaultTemplateEngineProvider.java b/src/main/java/org/codework/struts/plugins/thymeleaf/spi/DefaultTemplateEngineProvider.java index 10e2e88..06e37a6 100644 --- a/src/main/java/org/codework/struts/plugins/thymeleaf/spi/DefaultTemplateEngineProvider.java +++ b/src/main/java/org/codework/struts/plugins/thymeleaf/spi/DefaultTemplateEngineProvider.java @@ -15,86 +15,133 @@ */ package org.codework.struts.plugins.thymeleaf.spi; -import com.opensymphony.xwork2.inject.Inject; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.struts2.dispatcher.Dispatcher; import org.codework.struts.plugins.thymeleaf.StrutsMessageResolver; +import org.codework.struts.plugins.thymeleaf.diarect.FieldDialect; import org.thymeleaf.TemplateEngine; import org.thymeleaf.templateresolver.ServletContextTemplateResolver; +import com.opensymphony.xwork2.inject.Container; +import com.opensymphony.xwork2.inject.Inject; + /** * A default implementation of {@link TemplateEngineProvider}. * * @author Steven Benitez - * @since 2.3.15 */ public class DefaultTemplateEngineProvider implements TemplateEngineProvider { - // HTML5 is the future! - private String templateMode = "HTML5"; - private String characterEncoding = "UTF-8"; - // This will convert "home" to "/WEB-INF/templates/home.html" - private String prefix = "/WEB-INF/templates/"; - private String suffix = ".html"; - private boolean cacheable = true; - - // Default template cache TTL to 1 hour. If not set, entries would live in - // cache until expelled by LRU. - private Long cacheTtlMillis = 3600000L; - - private TemplateEngine templateEngine; - - /** - * Configure settings from the struts.xml or struts.properties, using sensible - * defaults if values are not provided. - */ - public void configure() { - ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(); - templateResolver.setTemplateMode(templateMode); - templateResolver.setCharacterEncoding(characterEncoding); - templateResolver.setPrefix(prefix); - templateResolver.setSuffix(suffix); - templateResolver.setCacheable(cacheable); - templateResolver.setCacheTTLMs(cacheTtlMillis); - - templateEngine = new TemplateEngine(); - templateEngine.setTemplateResolver(templateResolver); - templateEngine.setMessageResolver(new StrutsMessageResolver()); - } - - @Override - public TemplateEngine get() { - if (templateEngine == null) { - configure(); - } - - return templateEngine; - } - - @Inject(value = "struts.thymeleaf.templateMode", required = false) - public void setTemplateMode(String templateMode) { - this.templateMode = templateMode; - } - - @Inject(value = "struts.thymeleaf.encoding", required = false) - public void setCharacterEncoding(String characterEncoding) { - this.characterEncoding = characterEncoding; - } - - @Inject(value = "struts.thymeleaf.prefix", required = false) - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - @Inject(value = "struts.thymeleaf.suffix", required = false) - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - @Inject(value = "struts.thymeleaf.cacheable", required = false) - public void setCacheable(String cacheable) { - this.cacheable = Boolean.parseBoolean(cacheable); - } - - @Inject(value = "struts.thymeleaf.cacheTtlMillis", required = false) - public void setCacheTtlMillis(String cacheTtlMillis) { - this.cacheTtlMillis = Long.parseLong(cacheTtlMillis); - } + // HTML5 is the future! + private String templateMode = "HTML5"; + private String characterEncoding = "UTF-8"; + // This will convert "home" to "/WEB-INF/templates/home.html" + private String prefix = "/WEB-INF/templates/"; + private String suffix = ".html"; + private boolean cacheable = true; + + // Default template cache TTL to 1 hour. If not set, entries would live in + // cache until expelled by LRU. + private Long cacheTtlMillis = 3600000L; + + protected TemplateEngine templateEngine; + + private String templateEngineName = "default"; + private Container container; + private Map templateEngines = new HashMap(); + + /** + * Configure settings from the struts.xml or struts.properties, using + * sensible defaults if values are not provided. + */ + public void configure() { + ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(); + templateResolver.setTemplateMode(templateMode); + templateResolver.setCharacterEncoding(characterEncoding); + templateResolver.setPrefix(prefix); + templateResolver.setSuffix(suffix); + templateResolver.setCacheable(cacheable); + templateResolver.setCacheTTLMs(cacheTtlMillis); + + templateEngine.setTemplateResolver(templateResolver); + templateEngine.setMessageResolver(new StrutsMessageResolver()); + + // extension diarects. + FieldDialect fieldDialect = new FieldDialect(); + templateEngine.addDialect(fieldDialect); + } + + @Override + public TemplateEngine get() { + if ( templateEngine == null ) { + Container container = Dispatcher.getInstance().getContainer(); + setContainer(container); + + // loading template engine from struts2 di container. + this.templateEngine = templateEngines.get(templateEngineName); + configure(); + } + + return templateEngine; + } + + @Inject(value = "struts.thymeleaf.templateMode", required = false) + public void setTemplateMode(String templateMode) { + this.templateMode = templateMode; + } + + @Inject(value = "struts.thymeleaf.encoding", required = false) + public void setCharacterEncoding(String characterEncoding) { + this.characterEncoding = characterEncoding; + } + + @Inject(value = "struts.thymeleaf.prefix", required = false) + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + @Inject(value = "struts.thymeleaf.suffix", required = false) + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + @Inject(value = "struts.thymeleaf.cacheable", required = false) + public void setCacheable(String cacheable) { + this.cacheable = Boolean.parseBoolean(cacheable); + } + + @Inject(value = "struts.thymeleaf.cacheTtlMillis", required = false) + public void setCacheTtlMillis(String cacheTtlMillis) { + this.cacheTtlMillis = Long.parseLong(cacheTtlMillis); + } + + /** + * loading di container configulation from struts-plugin.xml , choise thymeleaf template engine. + * @param container Struts2Container + */ + public void setContainer(Container container) { + this.container = container; + + Map map = new HashMap(); + + // loading TemplateEngine class from DI Container. + Set prefixes = container.getInstanceNames(TemplateEngine.class); + for (String prefix : prefixes) { + TemplateEngine engine = (TemplateEngine) container.getInstance(TemplateEngine.class, prefix); + map.put(prefix, engine); + } + this.templateEngines = Collections.unmodifiableMap(map); + } + + /** + * Thymeleaf template type loading from struts.properties. + * @param templateEngineName ( default | spring ) + */ + @Inject(value = "struts.thymeleaf.templateEngineName") + public void setTemplateEngineName(String templateEngineName) { + this.templateEngineName = templateEngineName; + } } diff --git a/src/main/resources/struts-plugin.xml b/src/main/resources/struts-plugin.xml index f21e252..644ea54 100644 --- a/src/main/resources/struts-plugin.xml +++ b/src/main/resources/struts-plugin.xml @@ -1,15 +1,18 @@ - + "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" + "http://struts.apache.org/dtds/struts-2.3.dtd"> - + + + + + \ No newline at end of file