Spring MVC 表单入门

1.概述

在本文中,我们将讨论Spring表单和与控制器的数据绑定。

我们还将简单的看一下Spring MVC中的@ModelAttribute

2.模型

首先, 让我们定义一个简单的实体类,用来显示和绑定表单:

public class Employee {
    private String name;
    private long id;
    private String contactNumber;
 
    // getters and setters
}

3. 视图

然后我们定义包含的表单的HTML文件。

使用一个页面来创建/注册新员工:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
</head>
<body>
<h3>请输入社员的信息</h3>
<form:form method="POST"
           action="/form/employee/add" modelAttribute="employee">
    <table>
        <tr>
            <td><form:label path="name">Name</form:label></td>
            <td><form:input path="name"/></td>
        </tr>
        <tr>
            <td><form:label path="id">Id</form:label></td>
            <td><form:input path="id"/></td>
        </tr>
        <tr>
            <td><form:label path="contactNumber">
                Contact Number</form:label></td>
            <td><form:input path="contactNumber"/></td>
        </tr>
        <tr>
            <td><input type="submit" value="Submit"/></td>
        </tr>
    </table>
</form:form>
</body>
</html>

我们在JSP页面中包含了一个标记库,即form,来帮助我们定义表单。

JSP中最重要的部分就是<form:form>,它与HTLM <form>标记非常相似,但是,我们可以通过modelAttribute属性是来指定支持此表单的模型对象的名称:

<form:form method="POST"
           action="/form/employee/add" modelAttribute="employee">

一会我们在控制器中使用@ModelAttribute与它对应。

然后,我们为表单的每个输入字段都使用Spring Form taglib中的另一个的标签– form:prefix

这些字段中的每个字段都需要指定一个路径属性,必须对应于模型属性的getter/setter。加载页面时,Spring会自动帮我们填充字段,Spring将调用绑定到输入字段的每个字段的getter。提交表单后,将调用setter以将表单的值保存到模型对象。

最后,在提交表单的时候,调用控制器中的处理方法,并将表单自动绑定到我们传入的参数中。

4.控制器

下面,来看一下处理表单请求的Controller:

@Controller
@RequestMapping("/form/employee")
public class EmployeeController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView showForm() {
        return new ModelAndView("formDemo", "employee", new Employee());
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String submit(@Validated @ModelAttribute("employee") Employee employee,
                         BindingResult result, ModelMap model) {
        if (result.hasErrors()) {
            return "error";
        }
        model.addAttribute("name", employee.getName());
        model.addAttribute("contactNumber", employee.getContactNumber());
        model.addAttribute("id", employee.getId());
        return "formData";
    }
}

控制器定义了两个简单的操作:

  • 显示社员信息
  • 创建社员信息

要访问表单支持对象,我们可以通过*@ModelAttribute*注解注入它。不过,没有注解也可以自动的帮我们绑定模型对象属性。

@ModelAttribute指示从模型(model,不是Employee)中检索。如果模型中不存在该参数,则将首先实例化该参数,然后将其添加到模型中。

5. 处理绑定错误

默认情况下,当请求绑定期间发生错误时,Spring MVC会引发异常。

通常这不是我们想要的,相反,我们可能需要向用户显示这些错误。

我们这里只是为了检查是否有绑定错误,关于验证数据,请关注我们之后的更新。

可以通过在控制器方法中添加一个作为参数来使用BindingResult:

@RequestMapping(value = "/add", method = RequestMethod.POST)
public String submit(@Validated @ModelAttribute("employee") Employee employee,
                     BindingResult result, ModelMap model) {

不过需要注意的是BindingResult参数的位置,一定要在我们表单模型参数的后面。

如果在前面的话,会发生如下的异常:

 @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String submit(BindingResult result,@Validated @ModelAttribute("employee") Employee employee,
                          ModelMap model) {

异常信息

javax.servlet.ServletException: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply: public java.lang.String com.ripjava.spring.mvc.form.controller.EmployeeController.submit(org.springframework.validation.BindingResult,com.ripjava.spring.mvc.form.bean.Employee,org.springframework.ui.ModelMap)

我们可以在代码中检测绑定错误,并将页面跳转到错误处理页面。

@RequestMapping(value = "/add", method = RequestMethod.POST)
public String submit(BindingResult result,@Validated @ModelAttribute("employee") Employee employee,
                     ModelMap model) {
  if (result.hasErrors()) {
    return "error";
  }
  // ....
  return "formData";
}

最后,我们简单的创建一个error.jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
          integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h3>请重提交社员信息</h3>
    <table class="table">
        <tr>
            <td><a href="/form/employee/">Retry</a></td>
        </tr>
    </table>
</div>
</body>
</html>

6. 社员信息页面

最后,我们在简单的创建一个显示社员信息的页面。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
          integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2>提交的社员信息</h2>
    <table class="table">
        <tr>
            <td>Name :</td>
            <td>${name}</td>
        </tr>
        <tr>
            <td>ID :</td>
            <td>${id}</td>
        </tr>
        <tr>
            <td>Contact Number :</td>
            <td>${contactNumber}</td>
        </tr>
    </table>
</div>
</body>

7. 测试一下

下面我们简单的来测试一下:

这里我们通过Maven Jetty插件启动一个服务器:

mvn jetty:run

然后我们访问表单页面

http://localhost:8080/form/employee/

image-20200109210510235

提交表单。

image-20200109210745503

8. 总结

在本文中,我们简单的介绍了Spring MVC表单处理。在本文涉及的东西,以后逐一向大家介绍。

与往常一样,可以在GitHub上获得代码示例。