Spring MVC 绑定表单数据

1. 前言

在 WEB 应用程序中,经常会以表单的方式提交数据。使用 Spring MVC 或其它 WEB MVC 框架开发时,框架本身会提供以对象为单位自动封装表单中数据的功能。

本节课通过一个用户注册的小例子,和大家聊聊 Spring MVC 是如何优雅的以对象的方式封装表单中的数据。

本节课程的重点就是请你一定要跟着课程案例练习一遍。

2. 对象 / 表单

以表单的方式提交数据有一个优点,可以把逻辑上具有内在联系的多个数据同时发送给服务器。原生 Servlet 开发时,服务器端的响应组件(Servlet)中,需要开发者编写代码从请求包一个一个解析出提交过来的数据。

如果数据量不多,倒还好,如果数据量较多,一个一个解析,枯燥乏味的工作除了让人厌烦,且会耽误开发效率。

来!通过一个案例,体会 Spring MVC 是如何一步到位解析大量数据的。

案例需求描述: 实现用户注册功能。

流程分析: 通过注册页面,用户输入个人信息。表单中的数据以 POST 的请求方式提交至服务器,服务器端的控制器对提交过来的数据进行处理。

实现流程:

2.1 编写页面

编写注册页面,表单的提交方法设置为 POST

Tips: 无论数据是以 GET 或 POST 提交,本质没多大区别,仅表现在语义上的差异性。也就是说,此处使用 GET 方式提交并不影响结果。

<form action="user/register" method="post">
	用户名:<input type="text" value="" name="userName" /> 
    <br />
    密码:<inpu type="password" value="" name="userName" />
    <br />
    <input type="submit" value="注册" name="btnRegister" />
    <input type="reset"  value="重置" name="btnReset" />
</form>

2.2 分析控制器中的逻辑流程

注册页面中提交的用户数据最终会交给服务器端的用户控制器完成,控制器中的处理流程应该分 3 步走:

  1. 从请求包中解析出客户端提交过来的注册数据;
  2. 处理注册数据。核心业务逻辑就是添加数据到数据库中;
  3. 根据处理结果进行页面跳转。

Tips: 本节课程主要讲解数据绑定,会淡化后面的两个逻辑。

2.3 绑定数据

使用 @RequestParam 注解

Spring MVC 提供有 @RequestParam 注解,通过给定参数名,可以自动绑定请求包中的同名参数的数据。

代码如下:

@Controller
@RequestMapping("/user")
public class UserAction {
	@RequestMapping("/register")
	public String register(@RequestParam("userName") String userNmae,
			@RequestParam("userPassword") String userPassword) {
		System.out.println(userNmae);
		System.out.println(userPassword);
		return null;
	}
}

此处,使用 @RequestParam 注解绑定请求包中的数据,有 2 个弊端:

  • 如果请求包中传过来的数据较多,控制器中响应方法的参数也会增多,代码臃肿不好维护;

  • Java 语言最大的特色是面向对象编程(OOP)。很显然,userNameuserPassword 都是用户的信息,以一种拆离的方式分别注入数据没有体现出 OOP 的优点。

那么,有没有一种更好的替代方案或者说有一种很 OOP 的方案呢?

以 OOP 方式绑定数据

OOP 的角度分析,在应用程序中必然会存在一个描述用户的类。

public class User {
	private String userName;
   	private String userPassword;
    //……
}

能不能直接把请求包中提交的数据绑定到 User 类型中?

答案是肯定的,而且实现起来非常简单,只需要把控制器方法的参数修改成对象类型便可。

@RequestMapping("/register",method = RequestMethod.POST)
public String register(User user) {
	System.out.println(user);
	return null;
}

不需要使用额外的任何注解,就可以直接绑定表单中的数据。

为什么表单中的数据能自动绑定到对象上?

原理很简单,表单中数据以 key=value&key=value 的方式提交,此处的 key 实质是表单控件的名称。前面的注册表单中的数据在请求包中的格式形式如下:

userNname=abc&userPassword=123456

图片描述

如上图所示,Spring MVC 能自动解析这个数据,然后自动注入到对象的同名属性中。所以一定要保证对象的属性名与表单中提交数据时使用的参数名(key)一致。

数据解析成功后,理论上讲应该要把数据送到数据库中,本章节暂不涉及到数据库操作。只做业务逻辑模拟。

@RequestMapping(value="/register",method = RequestMethod.POST)
public String register(User user) {
	if("abc".equals(user.getUserName()) && "123456".equals(user.getUserPassword()) ) {
		return "success";
	}else {
		return "fail";
	}	
}

3. 对象级联

OOP 代码中经常会出现类似于 A 对象引用 B 对象,B 对象引用 C 对象的现象。 类似于现实生活中的小王有一辆汽车,汽车有一把钥匙……

如果每一个用户都有一辆汽车,用 OOP 描述,意味着 User 类中有一个对 Car 的引用类型属性。

public class User {
	private String userName;
	private String userPassword;
	private Car car;
    //……
}

假设 Car 类结构如下:

public class Car {
private String carType;
private String carColor;
//……
}

在注册时,除了要输入用户信息之外,还需要指定用户所拥有的汽车类型、颜色。那么,控制器是否能自动绑定用户以及汽车数据?

Tips: 为什么注册时要输入汽车信息,不要纠结,只是一个用来说明问题的例子。

答案是肯定的。

只需要在表单页面中添加如下代码,控制器端不做任何修改。如此,除了能接收用户数据外,还能接收汽车的信息。

<form action="user/register" method="post">
	用户名:<input type="text" value="" name="userName" /> 
	<br />
	密码:<input type="password" value="" name="userPassword" /> <br />
	汽车类型:<input type="text" value="" name="car.carType" /> <br />
	汽车颜色:<input  type="text" value="" name="car.carColor" /> <br />
	<input  type="submit" value="注册" name="btnRegister" />
	<input type="reset"  value="重置" name="btnReset" />
</form>

也就是说,Spring MVC 支持对象级联自动数据绑定。

图片描述

Spring MVC 支持多层级的对象级联。

4. 小结

本节课程主要是和大家讲解如何绑定表单中的数据。有 2 种方式,一是使用 @RequestParam 注解,另一个就是通过一个对象参数直接绑定数据。

Spring MVC 的自动绑定功能非常强大。在使用的时候可根据自己的需要自行选择。

当然,以 OOP 的形式绑定数据定当是最佳、快速的选择。