1. 概述

在本系列的第一篇文章中,我们介绍了 Spring MVC 表单标签库的基本用法,以及如何将表单数据绑定到 Controller。

本文将深入探讨 Spring MVC 提供的各种表单标签,帮助我们更高效地构建和校验表单

2. input 标签

我们先从最常用的 input 标签开始。该标签默认会渲染一个 HTML <input type="text"> 元素,并绑定指定字段的值:

<form:input path="name" />

从 Spring 3.1 开始,支持 HTML5 中的多种 type 类型,如 emaildate 等。例如,创建一个邮箱输入框:

<form:input type="email" path="email" />

同样地,创建一个日期输入框(HTML5 浏览器会自动显示日期选择器):

<form:input type="date" path="dateOfBirth" />

3. password 标签

这个标签用于渲染一个密码输入框(<input type="password">),绑定的值不会明文显示:

<form:password path="password" />

4. textarea 标签

用于渲染 HTML <textarea> 多行文本输入框:

<form:textarea path="notes" rows="3" cols="20"/>

与原生 HTML 一样,可以设置 rowscols 属性来控制显示区域大小。

5. checkboxcheckboxes 标签

checkbox 标签用于渲染 <input type="checkbox"> 复选框。

✅ 单个复选框通常用于布尔值绑定:

<form:checkbox path="receiveNewsletter" />

如果绑定的值为 true,则默认选中。

✅ 多个复选框绑定同一个字段,字段类型为数组或 java.util.Collection

Bird watching: <form:checkbox path="hobbies" value="Bird watching"/>
Astronomy: <form:checkbox path="hobbies" value="Astronomy"/>
Snowboarding: <form:checkbox path="hobbies" value="Snowboarding"/>

对应 Java 字段:

String[] hobbies;

checkboxes 标签用于动态生成多个复选框选项:

<form:checkboxes items="${favouriteLanguageItem}" path="favouriteLanguage" />

其中 items 可以是 ArrayListMap,通常在 Controller 中初始化:

List<String> favouriteLanguageItem = new ArrayList<String>();
favouriteLanguageItem.add("Java");
favouriteLanguageItem.add("C++");
favouriteLanguageItem.add("Perl");

对应的 Java 字段:

List<String> favouriteLanguage;

6. radiobuttonradiobuttons 标签

用于渲染 <input type="radio"> 单选按钮。

✅ 多个 radiobutton 绑定同一个字段,每个按钮对应一个值:

Male: <form:radiobutton path="sex" value="M"/>
Female: <form:radiobutton path="sex" value="F"/>

对应 Java 字段:

private String sex;

radiobuttons 动态生成单选按钮选项:

<form:radiobuttons items="${jobItem}" path="job" />

Controller 中初始化选项:

List<String> jobItem = new ArrayList<String>();
jobItem.add("Full time");
jobItem.add("Part time");

7. select 标签

用于渲染 HTML <select> 下拉选择框:

<form:select path="country" items="${countryItems}" />

选项可以是 ArrayListMap,Controller 中示例:

Map<String, String> countryItems = new LinkedHashMap<String, String>();
countryItems.put("US", "United States");
countryItems.put("IT", "Italy");
countryItems.put("UK", "United Kingdom");
countryItems.put("FR", "France");

✅ 支持嵌套 optionoptions 标签:

<form:select path="book">
    <form:option value="-" label="--Please Select--"/>
    <form:options items="${books}" />
</form:select>

✅ 多选下拉框(列表框):

<form:select path="fruit" items="${fruit}" multiple="true"/>

对应 Java 字段为数组或 Collection

List<String> fruit;

8. hidden 标签

用于渲染隐藏域(<input type="hidden">):

<form:hidden path="id" value="12345" />

9. errors 标签

用于展示字段校验失败时的错误信息。错误信息由 Controller 关联的 Validator 生成:

<form:errors path="name" cssClass="error" />

默认渲染为 <span> 标签,ID 为 字段名.errors,并可指定 CSS 类:

<span id="name.errors" class="error">Name is required!</span>

✅ 可通过 element 属性更换包装标签:

<form:errors path="name" cssClass="error" element="div" />

输出:

<div id="name.errors" class="error">Name is required!</div>

✅ 显示所有字段的错误信息(使用通配符):

<form:errors path="*" />

9.1. 自定义 Validator

要展示字段错误,需要定义一个 Validator:

public class PersonValidator implements Validator {

    @Override
    public boolean supports(Class clazz) {
        return Person.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object obj, Errors errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required.name");
    }
}

错误信息定义在 messages.properties 中:

required.name = Name is required!

在 Spring 配置文件中注册资源文件:

<bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource">
     <property name="basename" value="messages" />
</bean>

或使用 Java 配置:

@Bean
public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasenames("messages");
    return messageSource;
}

在 Controller 中使用 Validator:

@RequestMapping(value = "/addPerson", method = RequestMethod.POST)
public String submit(
  @ModelAttribute("person") Person person, 
  BindingResult result, 
  ModelMap modelMap) {

    validator.validate(person, result);

    if (result.hasErrors()) {
        return "personForm";
    }
    
    modelMap.addAttribute("person", person);
    return "personView";
}

9.2. JSR 303 Bean 校验

从 Spring 3 开始,支持使用 @Valid 注解进行 JSR 303 校验。需要引入 Hibernate Validator:

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>8.0.1.Final</version>
</dependency>

启用注解驱动支持:

<mvc:annotation-driven/>

或 Java 配置:

@EnableWebMvc
@Configuration
public class ClientWebConfigJava implements WebMvcConfigurer {
    // All web configuration will go here
}

在 Controller 方法中使用 @Valid

@RequestMapping(value = "/addPerson", method = RequestMethod.POST)
public String submit(
  @Valid @ModelAttribute("person") Person person, 
  BindingResult result, 
  ModelMap modelMap) {
 
    if(result.hasErrors()) {
        return "personForm";
    }
     
    modelMap.addAttribute("person", person);
    return "personView";
}

实体字段上使用注解校验:

@NotEmpty
private String password;

默认错误信息是 “may not be empty”,可通过资源文件覆盖:

NotEmpty.person.password = Password is required!

10. 总结

本文详细介绍了 Spring MVC 表单标签库中各个标签的使用方式,以及如何结合 Validator 和 JSR 303 实现表单校验与错误提示。

所有示例代码可从 GitHub 项目 获取,导入 Eclipse 即可运行。

启动项目后访问地址:

http://localhost:8080/spring-mvc-xml/person


原始标题:Exploring Spring MVC's Form Tag Library