# 5.4　处理表单

Web 应用的功能通常并不局限于为用户推送内容。大多数的应用允许用户填充表单并将数据提交回应用中，通过这种方式实现与用户的交互。像提供内容一样，Spring MVC 的控制器也为表单处理提供了良好的支持。

使用表单分为两个方面：展现表单以及处理用户通过表单提交的数据。在 Spittr 应用中，我们需要有个表单让新用户进行注册。SpitterController 是一个新的控制器，目前只有一个请求处理的方法来展现注册表单。

{% code title="程序清单 5.13　SpitterController：展现一个表单，允许用户注册该应用" %}

```java
package spittr.web;

import static org.springframework.web.bind.annotation.RequestMethod.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import spittr.Spitter;
import spittr.data.SpitterRepository;

@Controller
@RequestMapping("/spitter")
public class SpitterController {
  
  @RequestMapping(value="/register", method=GET)
  public String showRegistrationForm() {
    return "registerForm";
  }

}
```

{% endcode %}

showRegistrationForm() 方法的 @RequestMapping 注解以及类级别上的 @RequestMapping 注解组合起来，声明了这个方法要处理的是针对 `/spitter/register` 的 GET 请求。这是一个简单的方法，没有任何输入并且只是返回名为 registerForm 的逻辑视图。按照我们配置InternalResource-ViewResolver的方式，这意味着将会使用 `/WEB-INF/views/registerForm.jsp` 这个 JSP 来渲染注册表单。

尽管 showRegistrationForm() 方法非常简单，但测试依然需要覆盖到它。因为这个方法很简单，所以它的测试也比较简单。

{% code title="程序清单 5.14 测试展现表单的控制器方法" %}

```java
@Test
public void shouldShowRegistration() throws Exception {
  SpitterController controller = new SpitterController();
  MockMvc mockMvc = standaloneSetup(controller).build();
  
  mockMvc.perform(get("/spitter/register")).andExpect(view().name("registerForm"));
}
```

{% endcode %}

这个测试方法与首页控制器的测试非常类似。它对 `/spitter/register` 发送 GET 请求，然后断言结果的视图名为 registerForm。

现在，让我们回到视图上。因为视图的名称为 registerForm，所以 JSP 的名称需要是 registerForm.jsp。这个 JSP 必须要包含一个 HTML `<form>` 标签，在这个标签中用户输入注册应用的信息。如下就是我们现在所要使用的 JSP。

{% code title="程序清单 5.15　渲染注册表单的 JSP" %}

```markup
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
  <head>
    <title>Spitter</title>
    <link rel="stylesheet" type="text/css" 
          href="<c:url value="/resources/style.css" />" >
  </head>
  <body>
    <h1>Register</h1>

    <form method="POST">
      First Name: <input type="text" name="firstName" /><br/>
      Last Name: <input type="text" name="lastName" /><br/>
      Email: <input type="email" name="email" /><br/>
      Username: <input type="text" name="username" /><br/>
      Password: <input type="password" name="password" /><br/>
      <input type="submit" value="Register" />
    </form>
  </body>
</html>
```

{% endcode %}

可以看到，这个 JSP 非常基础。它的 HTML 表单域中记录用户的名字、姓氏、用户名以及密码，然后还包含一个提交表单的按钮。在浏览器渲染之后，它的样子大致如图 5.5 所示。

需要注意的是：这里的标签中并没有设置 action 属性。在这种情况下，当表单提交时，它会提交到与展现时相同的 URL 路径上。也就是说，它会提交到 `/spitter/register` 上。

这就意味着需要在服务器端处理该 HTTP POST 请求。现在，我们在 SpitterController 中再添加一个方法来处理这个表单提交。

![图 5.5　注册页提供了一个表单，这个表单会由 SpitterController 进行处理，完成为应用添加新用户的功能](/files/-LmruB2cHQMfLzIBgGR2)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://potoyang.gitbook.io/spring-in-action-v4/di-5-zhang-gou-jian-spring-web-ying-yong-cheng-xu/untitled-3.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
