Add FreeMarker macro support in spring-webflux
Closes gh-23002
This commit is contained in:
committed by
Sam Brannen
parent
9b084bb3ea
commit
b58f34d802
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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
|
||||
*
|
||||
* https://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.reactive.result.view;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
/**
|
||||
* Dummy request context used for VTL and FTL macro tests.
|
||||
*
|
||||
* @author Darren Davison
|
||||
* @author Juergen Hoeller
|
||||
* @author Issam El-atif
|
||||
*
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext
|
||||
*/
|
||||
public class DummyMacroRequestContext {
|
||||
|
||||
private final ServerWebExchange exchange;
|
||||
|
||||
private final ModelMap model;
|
||||
|
||||
private final GenericApplicationContext context;
|
||||
|
||||
private Map<String, String> messageMap;
|
||||
|
||||
private String contextPath;
|
||||
|
||||
public DummyMacroRequestContext(ServerWebExchange exchange, ModelMap model, GenericApplicationContext context) {
|
||||
this.exchange = exchange;
|
||||
this.model = model;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void setMessageMap(Map<String, String> messageMap) {
|
||||
this.messageMap = messageMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getMessage(String)
|
||||
*/
|
||||
public String getMessage(String code) {
|
||||
return this.messageMap.get(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getMessage(String, String)
|
||||
*/
|
||||
public String getMessage(String code, String defaultMsg) {
|
||||
String msg = this.messageMap.get(code);
|
||||
return (msg != null ? msg : defaultMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getMessage(String, List)
|
||||
*/
|
||||
public String getMessage(String code, List<?> args) {
|
||||
return this.messageMap.get(code) + args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getMessage(String, List, String)
|
||||
*/
|
||||
public String getMessage(String code, List<?> args, String defaultMsg) {
|
||||
String msg = this.messageMap.get(code);
|
||||
return (msg != null ? msg + args : defaultMsg);
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getContextPath()
|
||||
*/
|
||||
public String getContextPath() {
|
||||
return this.contextPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getContextUrl(String)
|
||||
*/
|
||||
public String getContextUrl(String relativeUrl) {
|
||||
return getContextPath() + relativeUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getContextUrl(String, Map)
|
||||
*/
|
||||
public String getContextUrl(String relativeUrl, Map<String,String> params) {
|
||||
UriTemplate template = new UriTemplate(relativeUrl);
|
||||
return getContextPath() + template.expand(params).toASCIIString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getBindStatus(String)
|
||||
*/
|
||||
public BindStatus getBindStatus(String path) throws IllegalStateException {
|
||||
return new BindStatus(new RequestContext(this.exchange, this.model, this.context), path, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.reactive.result.view.RequestContext#getBindStatus(String, boolean)
|
||||
*/
|
||||
public BindStatus getBindStatus(String path, boolean htmlEscape) throws IllegalStateException {
|
||||
return new BindStatus(new RequestContext(this.exchange, this.model, this.context), path, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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
|
||||
*
|
||||
* https://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.reactive.result.view.freemarker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
|
||||
import freemarker.cache.ClassTemplateLoader;
|
||||
import freemarker.cache.MultiTemplateLoader;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
|
||||
import org.springframework.ui.freemarker.SpringTemplateLoader;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIOException;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Issam El-atif
|
||||
*/
|
||||
public class FreeMarkerConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void freeMarkerConfigurerDefaultEncoding() throws IOException, TemplateException {
|
||||
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
|
||||
configurer.afterPropertiesSet();
|
||||
Configuration cfg = configurer.getConfiguration();
|
||||
assertThat(cfg.getDefaultEncoding()).isEqualTo("UTF-8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freeMarkerConfigurerWithConfigLocation() {
|
||||
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
|
||||
configurer.setConfigLocation(new FileSystemResource("myprops.properties"));
|
||||
Properties props = new Properties();
|
||||
props.setProperty("myprop", "/mydir");
|
||||
configurer.setFreemarkerSettings(props);
|
||||
assertThatIOException().isThrownBy(
|
||||
configurer::afterPropertiesSet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freeMarkerConfigurerWithResourceLoaderPath() throws Exception {
|
||||
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
|
||||
configurer.setTemplateLoaderPath("file:/mydir");
|
||||
configurer.afterPropertiesSet();
|
||||
Configuration cfg = configurer.getConfiguration();
|
||||
assertThat(cfg.getTemplateLoader()).isInstanceOf(MultiTemplateLoader.class);
|
||||
MultiTemplateLoader multiTemplateLoader = (MultiTemplateLoader)cfg.getTemplateLoader();
|
||||
assertThat(multiTemplateLoader.getTemplateLoader(0)).isInstanceOf(SpringTemplateLoader.class);
|
||||
assertThat(multiTemplateLoader.getTemplateLoader(1)).isInstanceOf(ClassTemplateLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void freeMarkerConfigurerWithNonFileResourceLoaderPath() throws Exception {
|
||||
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
|
||||
configurer.setTemplateLoaderPath("file:/mydir");
|
||||
Properties settings = new Properties();
|
||||
settings.setProperty("localized_lookup", "false");
|
||||
configurer.setFreemarkerSettings(settings);
|
||||
configurer.setResourceLoader(new ResourceLoader() {
|
||||
@Override
|
||||
public Resource getResource(String location) {
|
||||
if (!("file:/mydir".equals(location) || "file:/mydir/test".equals(location))) {
|
||||
throw new IllegalArgumentException(location);
|
||||
}
|
||||
return new ByteArrayResource("test".getBytes(), "test");
|
||||
}
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return getClass().getClassLoader();
|
||||
}
|
||||
});
|
||||
configurer.afterPropertiesSet();
|
||||
assertThat(configurer.getConfiguration()).isInstanceOf(Configuration.class);
|
||||
Configuration fc = configurer.getConfiguration();
|
||||
Template ft = fc.getTemplate("test");
|
||||
assertThat(FreeMarkerTemplateUtils.processTemplateIntoString(ft, new HashMap())).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test // SPR-12448
|
||||
public void freeMarkerConfigurationAsBean() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition loaderDef = new RootBeanDefinition(SpringTemplateLoader.class);
|
||||
loaderDef.getConstructorArgumentValues().addGenericArgumentValue(new DefaultResourceLoader());
|
||||
loaderDef.getConstructorArgumentValues().addGenericArgumentValue("/freemarker");
|
||||
RootBeanDefinition configDef = new RootBeanDefinition(Configuration.class);
|
||||
configDef.getPropertyValues().add("templateLoader", loaderDef);
|
||||
beanFactory.registerBeanDefinition("freeMarkerConfig", configDef);
|
||||
beanFactory.getBean(Configuration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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
|
||||
*
|
||||
* https://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.reactive.result.view.freemarker;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import freemarker.template.Configuration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.test.server.MockServerWebExchange;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.result.view.DummyMacroRequestContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Darren Davison
|
||||
* @author Juergen Hoeller
|
||||
* @author Issam El-atif
|
||||
*/
|
||||
public class FreeMarkerMacroTests {
|
||||
|
||||
private MockServerWebExchange exchange;
|
||||
|
||||
private Configuration freeMarkerConfig;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path"));
|
||||
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
|
||||
configurer.setTemplateLoaderPaths("classpath:/", "file://" + System.getProperty("java.io.tmpdir"));
|
||||
this.freeMarkerConfig = configurer.createConfiguration();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testName() throws Exception {
|
||||
assertThat(getMacroOutput("NAME")).isEqualTo("Darren");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAge() throws Exception {
|
||||
assertThat(getMacroOutput("AGE")).isEqualTo("99");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessage() throws Exception {
|
||||
assertThat(getMacroOutput("MESSAGE")).isEqualTo("Howdy Mundo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultMessage() throws Exception {
|
||||
assertThat(getMacroOutput("DEFAULTMESSAGE")).isEqualTo("hi planet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageArgs() throws Exception {
|
||||
assertThat(getMacroOutput("MESSAGEARGS")).isEqualTo("Howdy[World]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageArgsWithDefaultMessage() throws Exception {
|
||||
assertThat(getMacroOutput("MESSAGEARGSWITHDEFAULTMESSAGE")).isEqualTo("Hi");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUrl() throws Exception {
|
||||
assertThat(getMacroOutput("URL")).isEqualTo("/springtest/aftercontext.html");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUrlParams() throws Exception {
|
||||
assertThat(getMacroOutput("URLPARAMS")).isEqualTo("/springtest/aftercontext/bar?spam=bucket");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm1() throws Exception {
|
||||
assertThat(getMacroOutput("FORM1")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" >");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm2() throws Exception {
|
||||
assertThat(getMacroOutput("FORM2")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" class=\"myCssClass\" >");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm3() throws Exception {
|
||||
assertThat(getMacroOutput("FORM3")).isEqualTo("<textarea id=\"name\" name=\"name\" >\nDarren</textarea>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm4() throws Exception {
|
||||
assertThat(getMacroOutput("FORM4")).isEqualTo("<textarea id=\"name\" name=\"name\" rows=10 cols=30>\nDarren</textarea>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm9() throws Exception {
|
||||
assertThat(getMacroOutput("FORM9")).isEqualTo("<input type=\"password\" id=\"name\" name=\"name\" value=\"\" >");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm10() throws Exception {
|
||||
assertThat(getMacroOutput("FORM10")).isEqualTo("<input type=\"hidden\" id=\"name\" name=\"name\" value=\"Darren\" >");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm11() throws Exception {
|
||||
assertThat(getMacroOutput("FORM11")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" >");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm12() throws Exception {
|
||||
assertThat(getMacroOutput("FORM12")).isEqualTo("<input type=\"hidden\" id=\"name\" name=\"name\" value=\"Darren\" >");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm13() throws Exception {
|
||||
assertThat(getMacroOutput("FORM13")).isEqualTo("<input type=\"password\" id=\"name\" name=\"name\" value=\"\" >");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm15() throws Exception {
|
||||
String output = getMacroOutput("FORM15");
|
||||
assertThat(output.startsWith("<input type=\"hidden\" name=\"_name\" value=\"on\"/>")).as("Wrong output: " + output).isTrue();
|
||||
assertThat(output.contains("<input type=\"checkbox\" id=\"name\" name=\"name\" />")).as("Wrong output: " + output).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm16() throws Exception {
|
||||
String output = getMacroOutput("FORM16");
|
||||
assertThat(output.startsWith(
|
||||
"<input type=\"hidden\" name=\"_jedi\" value=\"on\"/>")).as("Wrong output: " + output).isTrue();
|
||||
assertThat(output.contains(
|
||||
"<input type=\"checkbox\" id=\"jedi\" name=\"jedi\" checked=\"checked\" />")).as("Wrong output: " + output).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm17() throws Exception {
|
||||
assertThat(getMacroOutput("FORM17")).isEqualTo("<input type=\"text\" id=\"spouses0.name\" name=\"spouses[0].name\" value=\"Fred\" >");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForm18() throws Exception {
|
||||
String output = getMacroOutput("FORM18");
|
||||
assertThat(output.startsWith(
|
||||
"<input type=\"hidden\" name=\"_spouses[0].jedi\" value=\"on\"/>")).as("Wrong output: " + output).isTrue();
|
||||
assertThat(output.contains(
|
||||
"<input type=\"checkbox\" id=\"spouses0.jedi\" name=\"spouses[0].jedi\" checked=\"checked\" />")).as("Wrong output: " + output).isTrue();
|
||||
}
|
||||
|
||||
private String getMacroOutput(String name) throws Exception {
|
||||
String macro = fetchMacro(name);
|
||||
assertThat(macro).isNotNull();
|
||||
|
||||
FileSystemResource resource = new FileSystemResource(System.getProperty("java.io.tmpdir") + "/tmp.ftl");
|
||||
FileCopyUtils.copy("<#import \"spring.ftl\" as spring />\n" + macro, new FileWriter(resource.getPath()));
|
||||
|
||||
Map<String, String> msgMap = new HashMap<>();
|
||||
msgMap.put("hello", "Howdy");
|
||||
msgMap.put("world", "Mundo");
|
||||
|
||||
TestBean darren = new TestBean("Darren", 99);
|
||||
TestBean fred = new TestBean("Fred");
|
||||
fred.setJedi(true);
|
||||
darren.setSpouse(fred);
|
||||
darren.setJedi(true);
|
||||
darren.setStringArray(new String[] {"John", "Fred"});
|
||||
|
||||
Map<String, String> names = new HashMap<>();
|
||||
names.put("Darren", "Darren Davison");
|
||||
names.put("John", "John Doe");
|
||||
names.put("Fred", "Fred Bloggs");
|
||||
names.put("Rob&Harrop", "Rob Harrop");
|
||||
|
||||
ModelMap model = new ExtendedModelMap();
|
||||
DummyMacroRequestContext rc = new DummyMacroRequestContext(this.exchange, model, new GenericApplicationContext());
|
||||
rc.setMessageMap(msgMap);
|
||||
rc.setContextPath("/springtest");
|
||||
|
||||
model.put("command", darren);
|
||||
model.put("springMacroRequestContext", rc);
|
||||
model.put("msgArgs", new Object[] { "World" });
|
||||
model.put("nameOptionMap", names);
|
||||
model.put("options", names.values());
|
||||
|
||||
FreeMarkerView view = new FreeMarkerView();
|
||||
view.setBeanName("myView");
|
||||
view.setUrl("tmp.ftl");
|
||||
view.setConfiguration(freeMarkerConfig);
|
||||
|
||||
view.render(model, null, this.exchange).subscribe();
|
||||
|
||||
// tokenize output and ignore whitespace
|
||||
String output = this.exchange.getResponse().getBodyAsString().block();
|
||||
output = output.replace("\r\n", "\n");
|
||||
return output.trim();
|
||||
}
|
||||
|
||||
private String fetchMacro(String name) throws Exception {
|
||||
ClassPathResource resource = new ClassPathResource("test-macro.ftl", getClass());
|
||||
assertThat(resource.exists()).isTrue();
|
||||
String all = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
|
||||
all = all.replace("\r\n", "\n");
|
||||
String[] macros = StringUtils.delimitedListToStringArray(all, "\n\n");
|
||||
for (String macro : macros) {
|
||||
if (macro.startsWith(name)) {
|
||||
return macro.substring(macro.indexOf("\n")).trim();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<#--
|
||||
test template for FreeMarker macro test class
|
||||
-->
|
||||
<#import "spring.ftl" as spring />
|
||||
|
||||
NAME
|
||||
${command.name}
|
||||
|
||||
AGE
|
||||
${command.age}
|
||||
|
||||
MESSAGE
|
||||
<@spring.message "hello"/> <@spring.message "world"/>
|
||||
|
||||
DEFAULTMESSAGE
|
||||
<@spring.messageText "no.such.code", "hi"/> <@spring.messageText "no.such.code", "planet"/>
|
||||
|
||||
MESSAGEARGS
|
||||
<@spring.messageArgs "hello", msgArgs/>
|
||||
|
||||
MESSAGEARGSWITHDEFAULTMESSAGE
|
||||
<@spring.messageArgsText "no.such.code", msgArgs, "Hi"/>
|
||||
|
||||
URL
|
||||
<@spring.url "/aftercontext.html"/>
|
||||
|
||||
URLPARAMS
|
||||
<@spring.url relativeUrl="/aftercontext/{foo}?spam={spam}" foo="bar" spam="bucket"/>
|
||||
|
||||
FORM1
|
||||
<@spring.formInput "command.name", ""/>
|
||||
|
||||
FORM2
|
||||
<@spring.formInput "command.name", 'class="myCssClass"'/>
|
||||
|
||||
FORM3
|
||||
<@spring.formTextarea "command.name", ""/>
|
||||
|
||||
FORM4
|
||||
<@spring.formTextarea "command.name", "rows=10 cols=30"/>
|
||||
|
||||
FORM5
|
||||
<@spring.formSingleSelect "command.name", nameOptionMap, ""/>
|
||||
|
||||
FORM6
|
||||
<@spring.formMultiSelect "command.spouses", nameOptionMap, ""/>
|
||||
|
||||
FORM7
|
||||
<@spring.formRadioButtons "command.name", nameOptionMap, " ", ""/>
|
||||
|
||||
FORM8
|
||||
<@spring.formCheckboxes "command.stringArray", nameOptionMap, " ", ""/>
|
||||
|
||||
FORM9
|
||||
<@spring.formPasswordInput "command.name", ""/>
|
||||
|
||||
FORM10
|
||||
<@spring.formHiddenInput "command.name", ""/>
|
||||
|
||||
FORM11
|
||||
<@spring.formInput "command.name", "", "text"/>
|
||||
|
||||
FORM12
|
||||
<@spring.formInput "command.name", "", "hidden"/>
|
||||
|
||||
FORM13
|
||||
<@spring.formInput "command.name", "", "password"/>
|
||||
|
||||
FORM14
|
||||
<@spring.formSingleSelect "command.name", options, ""/>
|
||||
|
||||
FORM15
|
||||
<@spring.formCheckbox "command.name"/>
|
||||
|
||||
FORM16
|
||||
<@spring.formCheckbox "command.jedi"/>
|
||||
|
||||
FORM17
|
||||
<@spring.formInput "command.spouses[0].name", ""/>
|
||||
|
||||
FORM18
|
||||
<@spring.formCheckbox "command.spouses[0].jedi" />
|
||||
Reference in New Issue
Block a user