原文: https://howtodoinjava.com/spring-mvc/spring-mvc-populate-and-validate-dropdown-example/

如果您正在使用 Spring MVC 开发的任何面向客户的 Web 应用程序,那么您可能还需要在应用程序 UI 中的某个位置使用下拉框。 本教程将帮助您显示预填充的下拉列表,然后验证用户在提交表单时是否选择了任何值。

这篇文章是我以前关于 spring mvc 验证(使用 JSR-303 注解 )的继续。 我将修改相同的源代码。

在此示例中,我将显示一个用于向系统中添加新员工的表单。 该表格将有一个下拉列表,列出所有部门。 应用程序用户必须在提交表单之前从下拉列表中选择一个值。

Spring MVC 填充和验证下拉列表示例 - 图1

Spring MVC 下拉菜单示例 – 空白表单

下载源码

  1. Table of Contents
  2. Model Classes
  3. Adding PropertyEditorSupport
  4. View layer changes for displaying Dropdown box
  5. Dropdown validation changes
  6. Test The Application

模型类

DepartmentVO.java

  1. package com.howtodoinjava.demo.model;
  2. public class DepartmentVO
  3. {
  4. public DepartmentVO(Integer id, String name) {
  5. super();
  6. this.id = id;
  7. this.name = name;
  8. }
  9. private Integer id;
  10. private String name;
  11. //Setters and Getters
  12. @Override
  13. public String toString() {
  14. return "DepartmentVO [id=" + id + ", name=" + name + "]";
  15. }
  16. }

EmployeeVO.java

此类具有DepartmentVO的关联属性。

  1. package com.howtodoinjava.demo.model;
  2. import java.io.Serializable;
  3. import javax.validation.constraints.NotNull;
  4. import org.hibernate.validator.constraints.NotEmpty;
  5. public class EmployeeVO implements Serializable
  6. {
  7. private static final long serialVersionUID = 1L;
  8. private Integer id;
  9. @NotEmpty
  10. private String firstName;
  11. private String lastName;
  12. private String email;
  13. @NotNull
  14. private DepartmentVO department;
  15. //Setters and Getters
  16. @Override
  17. public String toString() {
  18. return "EmployeeVO [id=" + id + ", firstName=" + firstName
  19. + ", lastName=" + lastName + ", email=" + email
  20. + ", department=" + department + "]";
  21. }
  22. }

添加PropertyEditorSupport

我们不会在 UI 中将DepartmentVO显示为 java 对象,而是当用户提交绑定到Department字段的属性时,HTTP POST 中只会出现一个字符串值。 我们需要某种机制将字符串值转换回DepartmentVO实例并注入EmployeeVO实例。

Spring 为此提供了PropertyEditorSupport类。

DepartmentEditor.java

  1. package com.howtodoinjava.demo.convertor;
  2. import java.beans.PropertyEditorSupport;
  3. import com.howtodoinjava.demo.model.DepartmentVO;
  4. public class DepartmentEditor extends PropertyEditorSupport
  5. {
  6. //This will be called when user HTTP Post to server a field bound to DepartmentVO
  7. @Override
  8. public void setAsText(String id)
  9. {
  10. DepartmentVO d;
  11. switch(Integer.parseInt(id))
  12. {
  13. case 1: d = new DepartmentVO(1, "Human Resource"); break;
  14. case 2: d = new DepartmentVO(2, "Finance"); break;
  15. case 3: d = new DepartmentVO(3, "Information Technology"); break;
  16. default: d = null;
  17. }
  18. this.setValue(d);
  19. }
  20. }

可以,但是 spring 怎么会知道我们有此类用于转换目的。 为此,我们必须告诉 Spring。 我们可以通过以下方式在控制器类中进行操作。

  1. @InitBinder
  2. public void initBinder(WebDataBinder binder) {
  3. binder.registerCustomEditor(DepartmentVO.class, new DepartmentEditor());
  4. }

现在,每次将表单提交到EmployeeController且字段绑定到department的字段时,DepartmentEditor都会用于将字符串值转换为DepartmentVO实例。

EmployeeController的完整代码如下。

EmployeeController.java

  1. package com.howtodoinjava.demo.controller;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.Set;
  5. import javax.validation.ConstraintViolation;
  6. import javax.validation.Validation;
  7. import javax.validation.Validator;
  8. import javax.validation.ValidatorFactory;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.stereotype.Controller;
  11. import org.springframework.ui.Model;
  12. import org.springframework.validation.BindingResult;
  13. import org.springframework.validation.FieldError;
  14. import org.springframework.web.bind.WebDataBinder;
  15. import org.springframework.web.bind.annotation.InitBinder;
  16. import org.springframework.web.bind.annotation.ModelAttribute;
  17. import org.springframework.web.bind.annotation.RequestMapping;
  18. import org.springframework.web.bind.annotation.RequestMethod;
  19. import org.springframework.web.bind.annotation.SessionAttributes;
  20. import org.springframework.web.bind.support.SessionStatus;
  21. import com.howtodoinjava.demo.convertor.DepartmentEditor;
  22. import com.howtodoinjava.demo.model.DepartmentVO;
  23. import com.howtodoinjava.demo.model.EmployeeVO;
  24. import com.howtodoinjava.demo.service.EmployeeManager;
  25. @Controller
  26. @RequestMapping("/employee-module/addNew")
  27. @SessionAttributes("employee")
  28. public class EmployeeController
  29. {
  30. @Autowired
  31. EmployeeManager manager;
  32. private Validator validator;
  33. public EmployeeController()
  34. {
  35. ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
  36. validator = validatorFactory.getValidator();
  37. }
  38. @InitBinder
  39. public void initBinder(WebDataBinder binder) {
  40. binder.registerCustomEditor(DepartmentVO.class, new DepartmentEditor());
  41. }
  42. @ModelAttribute("allDepartments")
  43. public List<DepartmentVO> populateDepartments()
  44. {
  45. ArrayList<DepartmentVO> departments = new ArrayList<DepartmentVO>();
  46. departments.add(new DepartmentVO(-1, "Select Department"));
  47. departments.add(new DepartmentVO(1, "Human Resource"));
  48. departments.add(new DepartmentVO(2, "Finance"));
  49. departments.add(new DepartmentVO(3, "Information Technology"));
  50. return departments;
  51. }
  52. @RequestMapping(method = RequestMethod.GET)
  53. public String setupForm(Model model) {
  54. EmployeeVO employeeVO = new EmployeeVO();
  55. model.addAttribute("employee", employeeVO);
  56. return "addEmployee";
  57. }
  58. @RequestMapping(method = RequestMethod.POST)
  59. public String submitForm(@ModelAttribute("employee") EmployeeVO employeeVO,
  60. BindingResult result, SessionStatus status) {
  61. Set<ConstraintViolation<EmployeeVO>> violations = validator.validate(employeeVO);
  62. for (ConstraintViolation<EmployeeVO> violation : violations)
  63. {
  64. String propertyPath = violation.getPropertyPath().toString();
  65. String message = violation.getMessage();
  66. // Add JSR-303 errors to BindingResult
  67. // This allows Spring to display them in view via a FieldError
  68. result.addError(new FieldError("employee", propertyPath, "Invalid "+ propertyPath + "(" + message + ")"));
  69. }
  70. if (result.hasErrors()) {
  71. return "addEmployee";
  72. }
  73. // Store the employee information in database
  74. // manager.createNewRecord(employeeVO);
  75. System.out.println(employeeVO);
  76. // Mark Session Complete
  77. status.setComplete();
  78. return "redirect:addNew/success";
  79. }
  80. @RequestMapping(value = "/success", method = RequestMethod.GET)
  81. public String success(Model model) {
  82. return "addSuccess";
  83. }
  84. }

要了解有关此控制器中更多代码段的更多信息,请参考本 spring mvc 显示形式教程

查看更改以显示下拉框

要显示下拉列表,您必须将部门的集合提供给 jsp 文件。 这是从控制器完成的。 请注意,在此示例中,我对集合进行了硬编码。 在生产类应用程序中,您将需要动态构建此集合。

  1. @ModelAttribute("allDepartments")
  2. public List<DepartmentVO> populateDepartments()
  3. {
  4. ArrayList<DepartmentVO> departments = new ArrayList<DepartmentVO>();
  5. departments.add(new DepartmentVO(-1, "Select Department"));
  6. departments.add(new DepartmentVO(1, "Human Resource"));
  7. departments.add(new DepartmentVO(2, "Finance"));
  8. departments.add(new DepartmentVO(3, "Information Technology"));
  9. return departments;
  10. }

可以在form:select标记的 JSP 文件内部访问此allDepartments属性。

  1. <%@ page contentType="text/html;charset=UTF-8"%>
  2. <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
  3. <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
  4. <html>
  5. <head>
  6. <title>Add Employee Form</title>
  7. <style>
  8. .error
  9. {
  10. color: #ff0000;
  11. font-weight: bold;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <h2><spring:message code="lbl.page" text="Add New Employee" /></h2>
  17. <br/>
  18. <form:form method="post" modelAttribute="employee">
  19. <%-- <form:errors path="*" cssClass="error" /> --%>
  20. <table>
  21. <tr>
  22. <td><spring:message code="lbl.firstName" text="First Name" /></td>
  23. <td><form:input path="firstName" /></td>
  24. <td><form:errors path="firstName" cssClass="error" /></td>
  25. </tr>
  26. <tr>
  27. <td><spring:message code="lbl.lastName" text="Last Name" /></td>
  28. <td><form:input path="lastName" /></td>
  29. <td><form:errors path="lastName" cssClass="error" /></td>
  30. </tr>
  31. <tr>
  32. <td><spring:message code="lbl.email" text="Email Id" /></td>
  33. <td><form:input path="email" /></td>
  34. <td><form:errors path="email" cssClass="error" /></td>
  35. </tr>
  36. <!-- DROPDOWN code -->
  37. <tr>
  38. <td><spring:message code="lbl.department" text="Department" /></td>
  39. <td><form:select path="department" items="${allDepartments}" itemValue="id" itemLabel="name" /></td>
  40. <td><form:errors path="department" cssClass="error" /></td>
  41. </tr>
  42. <tr>
  43. <td colspan="3"><input type="submit" value="Add Employee"/></td>
  44. </tr>
  45. </table>
  46. </form:form>
  47. </body>
  48. </html>

下拉验证

为了验证下拉框,我们使用了以下内容。

1)我们在EmployeeVO内的部门字段中使用了@NotNull注解。 如果字段为null,使用 JSR-303 的 spring 验证将自动引发错误。

  1. @NotNull
  2. private DepartmentVO department;

2)由于具有@NotNull注解,因此我们要做的就是在department字段中为所有意外值设置null。 这是在DepartmentEditor内部完成的,因为在进入控制器代码之前,会调用DepartmentEditor.setAsText()来设置部门的正确值。

  1. public void setAsText(String id)
  2. {
  3. DepartmentVO d;
  4. switch(Integer.parseInt(id))
  5. {
  6. case 1: d = new DepartmentVO(1, "Human Resource"); break;
  7. case 2: d = new DepartmentVO(2, "Finance"); break;
  8. case 3: d = new DepartmentVO(3, "Information Technology"); break;
  9. default: d = null;
  10. }
  11. this.setValue(d);
  12. }

在上面的代码中,仅当下拉选择值是 1,2 或 3 时; 那么只会设置部门的有效实例。 否则,部门将设置为null。 此null将引发错误。

测试下拉菜单

1)部署应用程序并输入 URL:http://localhost:8080/springmvcexample/employee-module/addNew

Spring MVC 填充和验证下拉列表示例 - 图2

Spring MVC 下拉菜单示例 – 空白表达

2)填写名字并提交表格。 您将验证消息。

Spring MVC 填充和验证下拉列表示例 - 图3

Spring MVC 下拉菜单示例 – 下拉菜单验证

3)从列表中选择一个部门并提交表格。 您将成功页面。

Spring MVC 填充和验证下拉列表示例 - 图4

Spring MVC 表单示例 – 成功消息

下载源码

将我的问题放在评论框中。

祝您学习愉快!