spring+thymeleaf实现表单验证数据双向绑定
前言
这个教程介绍了Thymeleaf与Spring框架的集成,特别是SpringMvc框架。
注意Thymeleaf支持同Spring框架的3.和4.版本的集成,但是这两个版本的支持是封装在thymeleaf-spring3和thymeleaf-spring4这两个独立的库中,项目中需要根据实际情况分别引用。
样例代码针对的是spring4.,但一般情况下,spring3.也可以无缝使用,所需要的仅仅是改变一下引用库。
1 Thymeleaf同Spring的整合
Thymeleaf与Spring进行整合后,可以在SpringMVC应用中完全替代JSP文件。
集成后你将:
*就像控制JSP一样,使用SpringMvc的@Controller注解来映射Thymeleaf的模板文件。
*在模板中使用SpringEL表达式来替换OGNL
*在模板中创建的表单,完全支持Beans和结果的绑定,包括使用PropertyEditor,转换,和验证等。
*可以通过Spring来管理国际化文件显示国际化信息。
*注意,在使用本教程之前,您应该充分了解Thymeleaf的标准方言。
2 Spring标准方言
为了更加方便,更快捷的集成,Thymeleaf提供了一套能够与Spring正确工作的特有方言。
这套方言基于Thymeleaf标准方言实现,它在类 org.thymeleaf.spring.dialect.SpringStandardDialect 中,事实上,他继承于 org.thymeleaf.standard.StandardDialect 中。
除了已经出现在标准方言中的所有功能,Spring中还有以下特点:
*不适用OGNL,而是SpringEL做完变量表达式,因此,所有的${...}和*{...}表达式将用Spring的表达式引擎进行处理。
*访问应用context中的beans可以使用SpringEL语法:${@myBean.doSomething()}
*基于表格处理的新属性:th:field,th:errors和th:errorclass,除此还有一个th:object的新实现,允许它使用表单命令选择器(??)。
*一个新的表达式:#themes.code(...),相当于jsp自定义标签中的spring:theme。
*在spring4.0集成中的一个新的表达式:#mvc.uri(...),相当于jsp自定义标签中的spring:mvcUrl(...)
注意,上述这些方言特性是不能再普通的TemplateEngine对象中使用的,应该配置一个org.thymeleaf.spring4.SpringTemplateEngine来执行。
其他thymeleaf基础使用方法部分不在叙述。
创建表单
处理命令对象
SpringMVC的表单支持bean就是命令对象,这个对象通过对象领域模型的方式提供get和set方法,在浏览器建立获取用户输入值的输入框架。
Thymeleaf需要你显示的在form标签内通过th:object属性指定命令对象:
<form action="#" th:action="@{/seedstartermng}" th:object="${seedStarter}" method="post">
...
</form>
这个th:object与其他的的地方用途是一直的,但是事实上在这种特定情况下,为了与SpringMVC框架的正确整合增加了一些特定的限制:
1.在form标签中的th:object的值必须是变量表达式(...),只能指定属性模型属性的名字,而不能使用属性导航,这意味着,表达式...),只能指定属性模型属性的名字,而不能使用属性导航,
这意味着,表达式 {seedStarter}是正确的,而${seedStarter.data}则不是。
2.一个form标签内只能指定一个th:object属性,这与html中form标签不能嵌套的特性相一致。
input
下面是如何将一个input插入到表单中
<input type="text" th:field="*{datePlanted}" />
正象上边的代码所示,新增了一个 th:field 的属性,这是SpringMVC集成的一个重要特征,它帮你完成了表单bean和输入框之间的繁重的绑定工作。可以看出他在from中的路径属性和SpringMVC的jsp标签库一样。
th:field 属性的不同行为取决于它所附加的不同标签,包括 <input> , <select> 或 <textarea> (还包括标签的不同type属性类型),在这种情况下,时间上上面哪行代码会是这样的:
<input type="text" id="datePlanted" name="datePlanted" th:value="*{datePlanted}" />
事实上,可能比上边的代码还要多一些东西,因为 th:field 还可能会注册一个Spring的转换服务,包括之前我们看到的 DateFormatter (甚至这个表达式中没使用双大括号),因此,这个日期也将被正确的格式化。
th:field 的值必须使用选择表达式,这样将在这个环境中使用表单bean,而不是上下文变量或SpringMVC的模型属性。
相反对于 th:object 这类,它的表达式可以使用属性导航(事实上在JSP的 <form:input 标签中,可以使用任何的路径属性表达式)
注意th:field属性也可以在HTML5的的新增类型中使用,如 <input type="datetime"> , <input type="color"> 等,有效的增加了对SpringMVC对HTML5支持的完整性。
复选框
th:field 也可以用在 checkbox 中,比如如下代码:
<div>
<label th:for="${#ids.next('covered')}" th:text="#{seedstarter.covered}">已种植</label>
<input type="checkbox" th:field="*{covered}" />
</div>
注意这里有一些除了复选框之外的好东西,比如外部label和它使用的 #ids.next("covered") 方法,用于当该id的复选框执行的时候获取它的id值。
那么为什么我们需要这个字段的id属性动态生成呢?因为复选框可能是多值的,因此它会给id值添加一个序列号后缀(内部使用 #ids.seq(...) 函数)来保证同一属性的复选框有不同的id值。
我们可以看看多值的复选框:
<ul>
<li th:each="feat : ${allFeatures}">
<input type="checkbox" th:field="*{features}" th:value="${feat}" />
<label th:for="${#ids.prev('features')}"
th:text="#{${'seedstarter.feature.' + feat}}">Heating</label>
</li>
</ul>
注意这次我们增加了一个 th:value 属性,因为这次的特征属性不是一个布尔值,而是一个数组。
一般情况下,它的输出为:
<ul>
<li>
<input id="features1" name="features" type="checkbox"
value="SEEDSTARTER_SPECIFIC_SUBSTRATE" />
<input name="_features" type="hidden" value="on" />
<label for="features1">Seed starter-specific substrate</label>
</li>
<li>
<input id="features2" name="features" type="checkbox"
value="FERTILIZER" />
<input name="_features" type="hidden" value="on" />
<label for="features2">Fertilizer used</label>
</li>
<li>
<input id="features3" name="features" type="checkbox"
value="PH_CORRECTOR" />
<input name="_features" type="hidden" value="on" />
<label for="features3">PH Corrector used</label>
</li>
</ul>
我们可以看到一个序列后缀增加在每一个id的属性中, #ids.prev(....) 函数允许我们把检索最后一个序列值,生成的一个特定的id。
用不着担心那些隐藏域的名称为"_features":这是为了避免浏览器将未选中的复选框的值在表单提交是没有自动发送而故意添加的。
还应注意到,如果我们的表单bean中的feature属性已经包含了一些特定的值,那么th:field还将会自动在相应的标签中增加checked="checked"属性。
单选框
单选框的用法和一个非布尔值的多选框使用方式类似,只是他不是多选:
<ul>
<li th:each="ty : ${allTypes}">
<input type="radio" th:field="*{type}" th:value="${ty}" />
<label th:for="${#ids.prev('type')}" th:text="#{${'seedstarter.type.' + ty}}">Wireframe</label>
</li>
</ul>
下拉列表
下拉列表包含两个部分:<select>标签和它包含的<option>标签。在创建这种表单域的时候,只有<select>标签需要导入th:field属性,但 th:value 属性却在 <option> 标签中非常重要,因为他们提供了目前选选择框的选项(使用和非布尔复选框和单选框类似的手段)
使用类型作为下拉列表:
<select th:field="*{type}">
<option th:each="type : ${allTypes}"
th:value="${type}"
th:text="#{${'seedstarter.type.' + type}}">Wireframe</option>
</select>
这段代码理解起来很容易,只是注意属性优先级让我们可以在option标签内使用th:each属性。
动态域
由于SpringMVC的高级表单绑定功能,使得我们可以使用复杂的SpringEL表达式来绑定动态表单域到表单bean中。这将允许我们在 SeedStarter bean 中创建一个新的Row对象,并将这个row的域添加到用户请求的form中。
为了做到这一点,我们需要在控制器中提供一些新的映射方法,它将根据我们的特定请求的参数来决定添加或删除一行我们定义的.
@RequestMapping(value="/seedstartermng", params={"addRow"})
public String addRow(final SeedStarter seedStarter, final BindingResult bindingResult) {
seedStarter.getRows().add(new Row());
return "seedstartermng";
} @RequestMapping(value="/seedstartermng", params={"removeRow"})
public String removeRow(
final SeedStarter seedStarter, final BindingResult bindingResult,
final HttpServletRequest req) {
final Integer rowId = Integer.valueOf(req.getParameter("removeRow"));
seedStarter.getRows().remove(rowId.intValue());
return "seedstartermng";
}
现在给form添加一个动态table
<table>
<thead>
<tr>
<th th:text="#{seedstarter.rows.head.rownum}">Row</th>
<th th:text="#{seedstarter.rows.head.variety}">Variety</th>
<th th:text="#{seedstarter.rows.head.seedsPerCell}">Seeds per cell</th>
<th>
<button type="submit" name="addRow" th:text="#{seedstarter.row.add}">Add row</button>
</th>
</tr>
</thead>
<tbody>
<tr th:each="row,rowStat : *{rows}">
<td th:text="${rowStat.count}">1</td>
<td>
<select th:field="*{rows[__${rowStat.index}__].variety}">
<option th:each="var : ${allVarieties}"
th:value="${var.id}"
th:text="${var.name}">Thymus Thymi</option>
</select>
</td>
<td>
<input type="text" th:field="*{rows[__${rowStat.index}__].seedsPerCell}" />
</td>
<td>
<button type="submit" name="removeRow"
th:value="${rowStat.index}" th:text="#{seedstarter.row.remove}">Remove row</button>
</td>
</tr>
</tbody>
</table>
这里出现了很多东西,但都不难理解,除了这一句:
<select th:field="*{rows[__${rowStat.index}__].variety}">
...
</select>
如果你记得Thymeleaf教程,那么应该明白 __${...}__ 是一种预处理表达式的语法。这是一个在处理整个表达式之前的内部表达式,但为什么用这种方式指定行的索引呢,下面这种方式不行么:
<select th:field="*{rows[rowStat.index].variety}">
...
</select>
嗯事实上,是不行的,他的问题是SpringEL表达式不执行数值中括号里边的表达式变量,索引执行上边的语句时,会得到一个错误的结果,就是字面形式的 row[rowStat.index] (而不是 row[0],row[1] )而不是行集合中的正确位置,这就是为什么在这里需要预处理。
让我们看看产生的html后按"添加行"按钮几次:
<tbody>
<tr>
<td>1</td>
<td>
<select id="rows0.variety" name="rows[0].variety">
<option selected="selected" value="1">Thymus vulgaris</option>
<option value="2">Thymus x citriodorus</option>
<option value="3">Thymus herba-barona</option>
<option value="4">Thymus pseudolaginosus</option>
<option value="5">Thymus serpyllum</option>
</select>
</td>
<td>
<input id="rows0.seedsPerCell" name="rows[0].seedsPerCell" type="text" value="" />
</td>
<td>
<button name="removeRow" type="submit" value="0">Remove row</button>
</td>
</tr>
<tr>
<td>2</td>
<td>
<select id="rows1.variety" name="rows[1].variety">
<option selected="selected" value="1">Thymus vulgaris</option>
<option value="2">Thymus x citriodorus</option>
<option value="3">Thymus herba-barona</option>
<option value="4">Thymus pseudolaginosus</option>
<option value="5">Thymus serpyllum</option>
</select>
</td>
<td>
<input id="rows1.seedsPerCell" name="rows[1].seedsPerCell" type="text" value="" />
</td>
<td>
<button name="removeRow" type="submit" value="1">Remove row</button>
</td>
</tr>
</tbody>
验证和错误信息
让我们看看当有错误的时候如何给一个表单域一个CSS类:
<input type="text" th:field="*{datePlanted}"
th:class="${#fields.hasErrors('datePlanted')}? fieldError" />
可以看到, #fields.hasErrors(...) 函数接受一个表达式参数(datePlanted),返回一个布尔值告诉field该字段是否有验证错误。
我们可以根据他们各自的field获取所有的错误:
<ul>
<li th:each="err : ${#fields.errors('datePlanted')}" th:text="${err}" />
</ul>
通过迭代,我们可以使用 th:errors ,一个专门用于创建一个通过制定选择器筛选的错误列表的属性,通过 分隔。
<input type="text" th:field="*{datePlanted}" />
<p th:if="${#fields.hasErrors('datePlanted')}" th:errors="*{datePlanted}">Incorrect date</p>
简单错误基础css样式,th:errorclass
在上边的例子中,如果字段有错误,将为表单的input域设置一个css类,因为这种方式很常见,Thymeleaf提供了一个特定的属性为 th:errorclass
应用于form域的标签(input,select,textarea等),它将从现有的name属性或th:field属性字段的名词相同的属性,如果发生错误,则将制定的css类追加到标签中。
<input type="text" th:field="*{datePlanted}" class="small" th:errorclass="fieldError" />
如果datePlanted发生错误,则:
<input type="text" id="datePlanted" name="datePlanted" value="2013-01-01" class="small fieldError" />
全部错误
如果我们想要在form中显示所有的错误呢?我们只需要通过'*'或'all'(等价)来查询 #field.hasErrors(...) 方法和 #field.errors(...) 方法:
<ul th:if="${#fields.hasErrors('*')}">
<li th:each="err : ${#fields.errors('*')}" th:text="${err}">Input is incorrect</li>
</ul>
在上边的例子中,我们得到所有的错误并迭代他们:
<ul>
<li th:each="err : ${#fields.errors('*')}" th:text="${err}" />
</ul>
建立一个以<Enter>分隔的列表:
<p th:if="${#fields.hasErrors('all')}" th:errors="*{all}">Incorrect date</p>
最后,注意 #field.hasErrors("") 等效的属性 #fields.hasAnyErrors() 和 #fields.errors() 的等效的 #fields.allErrors() ,可以使用喜欢的任何语法。
<div th:if="${#fields.hasAnyErrors()}">
<p th:each="err : ${#fields.allErrors()}" th:text="${err}">...</p>
</div>
全局错误
Spring表单还有一种错误,全局错误,都是些不与窗体的任何特定字段关联的错误。
Thymeleaf提供了一个global的常量来访问这些错误。
<ul th:if="${#fields.hasErrors('global')}">
<li th:each="err : ${#fields.errors('global')}" th:text="${err}">Input is incorrect</li>
</ul>
Incorrect date以及等效的 #field.hasGlobalErrors() 和 #field.globalErrors() 方法。
<div th:if="${#fields.hasGlobalErrors()}">
<p th:each="err : ${#fields.globalErrors()}" th:text="${err}">...</p>
</div>
在表单外部显示错误
表单验证错误也可以在表单外部显示,方法是通过变量(即${...})的内部选择变量(*{...})增加表单bean的名字作为前缀的方式。
<form>
<div th:errors="${myForm}">...</div>
<div th:errors="${myForm.date}">...</div>
<div th:errors="${myForm.*}">...</div>
<div th:if="${#fields.hasErrors('${myForm}')}">...</div>
<div th:if="${#fields.hasErrors('${myForm.date}')}">...</div>
<div th:if="${#fields.hasErrors('${myForm.*}')}">...</div>
<form th:object="${myForm}">
...
</form>
富错误对象
Thymeleaf提供了以bean的形式(代替单纯的String)提供错误信息的能力,包括fieldName(String),message(String),和global(String)属性的错误。这些错误可以通过工具方法#fields.datailedErrors()来实现:
<ul>
<li th:each="e : ${#fields.detailedErrors()}" th:class="${e.global}? globalerr : fielderr">
<span th:text="${e.global}? '*' : ${e.fieldName}">The field name</span> |
<span th:text="${e.message}">The error message</span>
</li>
</ul>
转换服务
配置
就像前文所说,Thymeleaf可以在上下文中注册一个转换服务,再次看一下他的配置信息
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
...
<mvc:annotation-driven conversion-service="conversionService" />
...
<!-- **************************************************************** -->
<!-- CONVERSION SERVICE -->
<!-- Standard Spring formatting-enabled implementation -->
<!-- **************************************************************** -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="thymeleafexamples.stsm.web.conversion.VarietyFormatter" />
<bean class="thymeleafexamples.stsm.web.conversion.DateFormatter" />
</set>
</property>
</bean>
...
</beans>
${{...}}语法
转换服务可以通过 ${{...}} 语法很轻松的实现对象到字符串的转换或格式化:
变量语法 ${{...}}
选择变量语法 *{{...}}
例如,将一个Integer型转换为字符串类型,并通过逗号来分隔:
<p th:text="${val}">...</p>
<p th:text="${{val}}">...</p>
返回结果为:
<p>1234567890</p>
<p>1,234,567,890</p>
表单中使用
我们之前看到的每一个th:field属性都将始终使用转换服务:
<input type="text" th:field="*{datePlanted}" />
等效于:
<input type="text" th:field="*{{datePlanted}}" />
注意这是唯一一种在表达式中使用单大括号的转换服务。
#conversions工具对象
conversions工具对象表达式允许手动执行转换服务:
<p th:text="${'Val: ' + #conversions.convert(val,'String')}">...</p>
工具对象表达式的语法为:
conversions.convert(Object,Class) :将对象转换为指定的类
conversions.convert(Object,String) :和上边相同,但是指定的目标为String类(java.lang包名可以省略)
渲染片段模板
Thymeleaf提供了将一个模板只渲染一部分,并作为一个片段返回的能力。
这是一个非常有用的组件化工具,比如,它可以用于执行AJAX的Controller的调用,用于在已经加载的浏览器中返回一个片段标签(如用于更新选择,启用禁用按钮等)。
片段渲染可以使用Thymeleaf的片段规范:一个实现了 org.thymeleaf.fragment.IFragmentSpec 接口的对象。
最常用的一个实现是 org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec 类,它允许一个片段规范包括之前说过的th:insert,th:replace使用DOM选择器。
在视图bean中指定片段
视图bean是在应用程序上下文中声明的 org.thymeleaf.spring4.view.ThymeleafView 的bean,它允许这样定义一个片段:
<bean name="content-part" class="org.thymeleaf.spring4.view.ThymeleafView">
<property name="templateName" value="index" />
<property name="fragmentSpec">
<bean
class="org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec"
c:selectorExpression="content" />
</property>
</bean>
通过上边的bean的定义,如果controller返回一个content-part(bean的名字),
@RequestMapping("/showContentPart")
public String showContentPart() {
...
return "content-part";
}
Thymeleaf将只返回index模板的content片段。一旦前缀后缀都设置并匹配,那么它可能为/WEB-INF/templates/index.html,
<!DOCTYPE html>
<html>
...
<body>
...
<div th:fragment="content">
只有这里渲染!!
</div>
...
</body>
</html>
另外应该注意到,因为Thymeleaf可以使用DOM选择器,所有我们可以不用任何 th:fragment 属性,而只用id属性来选择一个片段,如:
<bean name="content-part" class="org.thymeleaf.spring4.view.ThymeleafView">
<property name="fragmentSpec">
<bean class="org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec"
c:selectorExpression="#content" />
</property>
<property name="templateName" value="index" />
</bean>
同样完美的适用:
<!DOCTYPE html>
<html>
...
<body>
...
<div id="content">
只有这里渲染!!
</div>
...
</body>
</html>
通过控制权的返回值指定片段
不声明一个视图bean,可以从控制器自己就可以使用与片段相同的语法,类似于th:insert,th:rplace属性等,如:
@RequestMapping("/showContentPart")
public String showContentPart() {
...
return "index :: content";
}
当然,同样可以使用基于DOM选择器的功能,所有我们也可以是选择使用基于标准的HTML属性,如id="content"
@RequestMapping("/showContentPart")
public String showContentPart() {
...
return "index :: #content";
}
也可以使用参数:
@RequestMapping("/showContentPart")
public String showContentPart() {
...
return "index :: #content ('myvalue')";
}
与RequestDataValueProcessor集成
现在Thymeleaf无缝的与Spring的RequestDataValueProcessor接口集成,这个接口允许拦截链接URLS,表达URLS和表达域的值,以及为了启用安全,如抵御CSRF而自动透明的添加一些隐藏域。
在应用的上下文中可以简单的配置RequestDataValueProcessor:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> ... <bean name="requestDataValueProcessor"
class="net.example.requestdata.processor.MyRequestDataValueProcessor" /> </beans>
Thymeleaf将通过这种方式使用它:
在渲染URL之前,th:href和th:src将会调用 RequestDataValueProcessor.processUrl(...)
在渲染表单的action属性之前,th:action会调用 RequestDataValueProcessor.processAction(...) ,另外他会检查标签,因为一般来说这是使用action的唯一一个地方,并且在的关闭标签之前执行 RequstDataValueProcessor.getExtraHiddenFields(...) 用来新增返回的hidden域。
在渲染value属性之前,th:value会调用 RequestDataProcessor.processFormFieldValue(...) ,除非在这个标签中存在了th:field(这时候th:field属性起作用)
当存在th:field的时候,在渲染value属性之前会调用 RequestDataValueProcessor.processFormFieldValue(...) 处理这个属性值(<textarea>处理内容值)
此功能只有Spring3.x以后使用
绑定地址到Controller
在Spring4.1之后的版本中,Spring允许通过注解直接从从视图链接到控制器,而不需要知道这些控制器映射的URI.
在Thymeleaf中可以通过 #mvc.url(...) 表达式方法调用Controller中符合驼峰命名规则的方法(get,set),调用的方式为方法的名字,即相当于jsp的spring:mvcUrl(...)自定义方法。
比如
public class ExampleController {
@RequestMapping("/data")
public String getData(Model model) { ... return "template" }
@RequestMapping("/data")
public String getDataParam(@RequestParam String type) {
...
return "template" }
}
下边是一个链接到它的方法:
<a th:href="${(#mvc.url('EC#getData')).build()}">获取Data参数</a>
<a th:href="${(#mvc.url('EC#getDataParam').arg(0,'internal')).build()}">获取Data参数</a>
Spring WebFlow的集成
基础配置
Thymeleaf-spring4集成包包括与Spring WebFlow 2.3.x的集成
WebFlow包括当特定的事件(过渡)被触发时渲染页面片段的一些Ajax的功能,未来让Thymeleaf参加这些Ajax请求,我们将使用一个不通过的视图解析器的实现,它这样配置:
<bean id="thymeleafViewResolver" class="org.thymeleaf.spring4.view.AjaxThymeleafViewResolver">
<property name="viewClass" value="org.thymeleaf.spring4.view.FlowAjaxThymeleafView" />
<property name="templateEngine" ref="templateEngine" />
</bean>
然后在ViewResolver中配置WebFlow的 ViewFactoryCreator .
<bean id="mvcViewFactoryCreator"
class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="thymeleafViewResolver"/>
</bean>
在这里可以指定模板的视图状态
<view-state id="detail" view="bookingDetail">
...
</view-state>
在上边的实例中,bookingDetail是Thymeleaf模板通常使用的一个方式,是模板引擎内任何模板解析器都可以懂的
Ajax片段
WebFlow的片段规范允许片段通过标签呈现,就像这样:
<view-state id="detail" view="bookingDetail">
<transition on="updateData">
<render fragments="hoteldata"/>
</transition>
</view-state>
这些片段(即hoteldata)可以是逗号分隔的列表标记在th:fragment标签中。
<div id="data" th:fragment="hoteldata">
这里内容替换</div>
永远记住,指定的片段必须有一个id属性,这样浏览器运行的SpringJavaScript库才能对标签进行替换。
标签,也可以通过DOM选择器设定:
<view-state id="detail" view="bookingDetail">
<transition on="updateData">
<render fragments="[//div[@id='data']]"/>
</transition>
</view-state>
这将意味着th:fragment不在需要:
<div id="data">
This is a content to be changed
</div>
而出发updateData后转换的代码:
<script type="text/javascript" th:src="@{/resources/dojo/dojo.js}"></script>
<script type="text/javascript" th:src="@{/resources/spring/Spring.js}"></script>
<script type="text/javascript" th:src="@{/resources/spring/Spring-Dojo.js}"></script> ... <form id="triggerform" method="post" action="">
<input type="submit" id="doUpdate" name="_eventId_updateData" value="Update now!" />
</form> <script type="text/javascript">
Spring.addDecoration(
new Spring.AjaxEventDecoration({
formId:'triggerform',
elementId:'doUpdate',
event:'onclick'
}));
</script>
转载:
spring+thymeleaf实现表单验证数据双向绑定的更多相关文章
- jdbc工具类的封装,以及表单验证数据提交后台
在之前已经写过了jdbc的工具类,不过最近学习了新的方法,所以在这里重新写一遍,为后面的javaEE做铺垫: 首先我们要了解javaEE项目中,文件构成,新建一个javaEE项目,在项目中,有一个we ...
- Spring Boot学习——表单验证
我觉得表单验证主要是用来防范小白搞乱网站和一些低级的黑客技术.Spring Boot可以使用注解 @Valid 进行表单验证.下面是一个例子. 例子说明:数据库增加一条Student记录,要求学生年龄 ...
- python_way day17 jQuery表单验证,事件绑定,插件,文本框架,正则表达式
python_way day17 1.jQuery表单验证 dom事件绑定 jquery事件绑定 $.each return值的判断 jquery扩展方法 2.前段插件 3.jDango文本框架 4. ...
- 走进AngularJs 表单及表单验证
年底了越来越懒散,AngularJs的学习落了一段时间,博客最近也没更新.惭愧~前段时间有试了一下用yeoman构建Angular项目,感觉学的差不多了想做个项目练练手,谁知遇到了一系列问题.yeom ...
- 走进AngularJs(九)表单及表单验证
年底了越来越懒散,AngularJs的学习落了一段时间,博客最近也没更新.惭愧~前段时间有试了一下用yeoman构建Angular项目,感觉学的差不多了想做个项目练练手,谁知遇到了一系列问题.yeom ...
- AngularJs 入门系列-2 表单验证
对于日常的开发来说,最常见的开发场景就是通过表单编辑数据,这里涉及的问题就是验证问题. angularjs 内置已经支持了常见的验证方式,可以轻松实现表单验证. 1. 绑定 为了方便,我们在 $sco ...
- Django学习笔记之表单验证
表单概述 HTML中的表单 单纯从前端的html来说,表单是用来提交数据给服务器的,不管后台的服务器用的是Django还是PHP语言还是其他语言.只要把input标签放在form标签中,然后再添加一个 ...
- bootstrap-table之通用方法( 时间控件,导出,动态下拉框, 表单验证 ,选中与获取信息)
1.bootstrap-table 单击单行选中 $('#gzrwTable').on('click-row.bs.table', function(e, row, $element) { $('.s ...
- atittit.表单验证的实现方式以及原理本质以及选型以及自定义兼容easyui dsl规则的表单验证
atittit.表单验证的实现方式以及原理本质以及选型以及自定义兼容easyui dsl规则的表单验证 1. 需求,表单验证需要弹框式,但目前easyui ms绑定死了tooltip式样 1 2. 表 ...
随机推荐
- Kubernetes - 配置Nginx-Ingress 作为服务发现
添加 Kubernetes ConfigMap配置来自定义端口与服务的映射关系 配置文件, 有二个在默认空间下web服务和api服务分别映射到自定义端口 9001, 9002 apiVersion: ...
- 雷锋沙龙 ppt 演讲内容分享(xss,流量劫持的利用)
http://www.pkav.net/XSS.png?from=timeline&isappinstalled=0
- NYOJ-277-车牌号
车牌号 时间限制:3000 ms | 内存限制:65535 KB 难度:1 描写叙述 茵茵非常喜欢研究车牌号码,从车牌号码上能够看出号码注冊的早晚,据研究发现,车牌号码是按字典序发放的,如今她收集 ...
- Excel2007制作直方图和正态分布曲线图
对同一维度的数据分析数据分布范围及分布趋势,要通过制作直方图和正态分布曲线图体现. 例如:已知所有员工的日收入,分析员工收入分布情况(51.7,50.6,57.9,56.9,56.7,56.7,55. ...
- 【C语言疯狂讲义】(三)C语言运算符
1.运算符: 连接两个操作数(常量.变量)的符号 用运算符依照一定的规则连接的式子称为表达式 运算符的分类: 1)操作数的个数: 单目运算(++ sizeof !) 双目运算符:... ...
- [j2ee]java中的xml操作
一.XML简单介绍 xml是可扩展标记语言,主要用来标记数据.定义数据类型,很适合万维网传输. xml特点: xml是一种标记语言.非常类似HTML xml的设计宗旨是数据传输,而不是显示数 ...
- css 温故而知新 select-option 文字方向居右
对select-option使用text-align:right;是无效的. 正确的姿势是:direction: ltr; 另外值得一提的是,通常还需要配合一点padding来美化.
- 使用Vitamio开发iOS平台上的万能播放器
迅速了解 Vitamio是干什么的?看官方怎么说: "Vitamio SDK for iOS是Yixia Ltd官方推出的 iOS 平台上使用的软件开发工具包(SDK),为iOS开发人员提供 ...
- Android实现夜间模式小结
随着APP实现的功能越来越丰富, 看小说看视频上网等等, 如今不少人花在手机平板等移动终端上的时间越来越长了. 但手机和平板的屏幕并不像Kindle那类电纸书的水墨屏那么耐看, 因为自发光的屏幕特性, ...
- php正則表達式中的非贪婪模式匹配的使用
php正則表達式中的非贪婪模式匹配的使用 通常我们会这么写: $str = "http://www.baidu/.com? url=www.sina.com/"; preg_mat ...