SpringMVC请求参数的绑定

一、什么是 SpringMVC 请求参数绑定?

在 Web 开发中,表单提交、URL 传参等请求数据都是 k=v 格式(例如 username=haha&password=123)。SpringMVC 的参数绑定 就是将这些请求数据自动映射到控制器方法的参数中,无需手动解析 Request 对象,极大简化了数据获取流程。

核心绑定规则
  • 表单 / 请求参数的 name 属性必须与控制器方法参数名、JavaBean 属性名一致(区分大小写)。
  • 支持自动类型转换(如字符串转基本数据类型),复杂场景可自定义转换器。

二、支持的绑定数据类型

SpringMVC 支持 3 大类数据绑定,覆盖绝大多数开发场景:

  1. 基本数据类型 + 字符串类型(int、String、Double 等)
  1. 实体类型(JavaBean)及嵌套引用类型
  1. 集合类型(List、Map 等)

下面通过「代码实例 + 场景说明」逐一拆解:

1. 环境准备(通用配置)

首先需要完成 SpringMVC 基础配置,确保注解生效:

  • web.xml:配置前端控制器、中文乱码过滤器(后续详细说明)
2. 基本数据类型 + 字符串绑定

场景:简单表单提交,直接获取单个参数(如用户名、年龄)。

步骤 1:编写 JSP 表单
html 复制代码
<!-- webapp/paramBinding.jsp -->

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>

<head>

<title>基本类型参数绑定</title>

</head>

<body>

<h3>基本数据类型 + 字符串绑定</h3>

<form action="/user/save1.do" method="post">

姓名:<input type="text" name="username" placeholder="请输入用户名"/><br/>

年龄:<input type="text" name="age" placeholder="请输入年龄"/><br/>

邮箱:<input type="text" name="email" placeholder="请输入邮箱"/><br/>

<input type="submit" value="提交" />

</form>

</body>

</html>
步骤 2:编写控制器方法
java 复制代码
// cn.tx.demo2.UserController

@Controller

@RequestMapping("/user") // 一级访问路径

public class UserController {

/**

* 基本类型+字符串绑定:参数名与表单name一致

* 注意:基本类型(如int)不能接收null值,建议用包装类(Integer)

*/

@RequestMapping("/save1.do")

public String save1(String username, Integer age, String email) {

System.out.println("用户名:" + username);

System.out.println("年龄:" + age);

System.out.println("邮箱:" + email);

return "suc"; // 跳转至WEB-INF/pages/suc.jsp

}

}
关键注意点
  • 表单 name 必须与方法参数名完全一致(如 username 对应 String username)。
  • 基本类型(int、double)无法接收 null,若表单可能漏填,建议用包装类(Integer、Double)。
  • 字符串类型可接收任意文本(包括中文,需解决乱码,后续说明)。
3. 实体类型(JavaBean)绑定

场景:表单字段较多时,将参数封装到 JavaBean 对象中(如用户信息、订单信息)。

步骤 1:定义 JavaBean(含嵌套引用类型)
java 复制代码
// 主实体类:User

package cn.tx.demo2;

import java.io.Serializable;

import java.util.List;

public class User implements Serializable {

private String username; // 用户名

private Integer age; // 年龄

private Address address; // 嵌套引用类型(地址信息)

private List<Address> addressList; // 集合类型(多个地址)

// 全参构造、无参构造(可选,建议保留)

// Getter + Setter(必须!SpringMVC通过Setter注入值)

// toString()(方便打印调试)

@Override

public String toString() {

return "User{" +

"username='" + username + '\'' +

", age=" + age +

", address=" + address +

", addressList=" + addressList +

'}';

}

// Getter和Setter省略,IDE自动生成即可

}

// 嵌套实体类:Address

package cn.tx.demo2;

import java.io.Serializable;

public class Address implements Serializable {

private String province; // 省份

private String city; // 城市

private Double money; // 金额

// Getter + Setter + toString()

@Override

public String toString() {

return "Address{" +

"province='" + province + '\'' +

", city='" + city + '\'' +

", money=" + money +

'}';

}

}
步骤 2:JSP 表单(支持嵌套和集合)
html 复制代码
<!-- 实体类+嵌套引用+集合绑定 -->

<h3>实体类绑定(含嵌套和集合)</h3>

<form action="/user/save2.do" method="post">

姓名:<input type="text" name="username" /><br/>

年龄:<input type="text" name="age" /><br/>

<!-- 嵌套引用类型:对象.属性名 -->

收货省份:<input type="text" name="address.province" /><br/>

收货城市:<input type="text" name="address.city" /><br/>

<!-- 集合类型:list[索引].属性名 -->

地址1金额:<input type="text" name="addressList[0].money" /><br/>

地址2金额:<input type="text" name="addressList[1].money" /><br/>

<input type="submit" value="提交" />

</form>
步骤 3:控制器方法(直接接收 JavaBean)
java 复制代码
/**

* 实体类绑定:直接接收User对象

* SpringMVC自动将表单参数注入到User的属性中(含嵌套对象和集合)

*/

@RequestMapping("/save2.do")

public String save2(User user) {

System.out.println("封装后的User对象:" + user);

return "suc";

}
打印结果示例
java 复制代码
封装后的User对象:User{

username='张三',

age=25,

address=Address{province='广东省', city='深圳市'},

addressList=[

Address{province='null', city='null', money=100.0},

Address{province='null', city='null', money=200.0}

]

}
核心规则
  • 普通属性:表单 name = JavaBean 属性名(如 username)。
  • 嵌套引用:表单 name = 引用对象名。属性名(如 address.province)。
  • List 集合:表单 name = 集合名 [索引]. 属性名(如 addressList[0].money)。
  • JavaBean 必须提供 无参构造Setter 方法(SpringMVC 通过反射注入)。
4. Map 集合绑定(拓展)

场景:不确定参数名时,用 Map 接收动态参数。

步骤 1:JSP 表单
html 复制代码
<h3>Map集合绑定</h3>

<form action="/user/save3.do" method="post">

键1:<input type="text" name="map['key1']" value="value1"/><br/>

键2:<input type="text" name="map['key2']" value="value2"/><br/>

用户姓名:<input type="text" name="username" value="李四"/><br/>

<input type="submit" value="提交" />

</form>
步骤 2:定义含 Map 的 JavaBean
java 复制代码
public class User implements Serializable {

private String username;

private Map<String, String> map; // Map集合属性

// Getter + Setter + toString()

}
步骤 3:控制器方法
java 复制代码
@RequestMapping("/save3.do")

public String save3(User user) {

System.out.println("Map集合数据:" + user.getMap());

System.out.println("用户名:" + user.getUsername());

return "suc";

}
打印结果
java 复制代码
Map集合数据:{key1=value1, key2=value2}

用户名:李四

三、请求参数中文乱码解决

表单提交中文时,默认会出现乱码(Tomcat 默认编码为 ISO-8859-1),SpringMVC 提供了现成的过滤器解决方案:

配置步骤(web.xml 中添加)
java 复制代码
<!-- 中文乱码过滤器:必须放在所有过滤器之前 -->

<filter>

<filter-name>characterEncodingFilter</filter-name>

<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

<!-- 设置请求编码 -->

<init-param>

<param-name>encoding</param-name>

<param-value>UTF-8</param-value>

</init-param>

<!-- 强制响应编码(可选) -->

<init-param>

<param-name>forceEncoding</param-name>

<param-value>true</param-value>

</init-param>

</filter>

<!-- 过滤所有请求 -->

<filter-mapping>

<filter-name>characterEncodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>
注意事项
  • 过滤器顺序:必须放在最前面(尤其是在 Shiro、Security 等过滤器之前)。
  • 仅对 POST 请求生效:GET 请求乱码需修改 Tomcat 的 server.xml(添加 URIEncoding="UTF-8")。

四、自定义类型转换器

SpringMVC 默认支持基本类型转换(如 String→int),但复杂类型(如 String→Date)需要自定义转换器。

两种实现方式
方式 1:@DateTimeFormat 注解(简单场景)

直接在 JavaBean 的 Date 属性上添加注解,指定日期格式:

java 复制代码
public class User implements Serializable {

// 其他属性...

// 日期格式:yyyy-MM-dd(如2024-05-20)

@DateTimeFormat(pattern = "yyyy-MM-dd")

private Date birthday;

// Getter + Setter

}

JSP 表单:

html 复制代码
生日:<input type="text" name="birthday" placeholder="格式:2024-05-20"/><br/>
方式 2:实现 Converter 接口(通用场景)

当需要全局复用转换器(如多种日期格式、自定义对象转换)时,推荐这种方式。

步骤 1:自定义转换器类
java 复制代码
package cn.tx.demo2;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Date;

/**

* 自定义转换器:String → Date

* 实现Converter<S, T>接口:S=源类型,T=目标类型

*/

public class StringToDateConverter implements Converter<String, Date> {

@Override

public Date convert(String source) {

// 1. 校验参数

if (source == null || source.trim().isEmpty()) {

throw new RuntimeException("日期参数不能为空!");

}

// 2. 定义日期格式(支持多种格式可扩展)

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

try {

// 3. 转换并返回

return sdf.parse(source);

} catch (ParseException e) {

throw new RuntimeException("日期格式错误!请输入yyyy-MM-dd格式");

}

}

}
步骤 2:注册转换器(springmvc.xml)
java 复制代码
<!-- 1. 配置转换器工厂,注入自定义转换器 -->

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">

<property name="converters">

<set>

<!-- 注入自定义的日期转换器 -->

<bean class="cn.tx.demo2.StringToDateConverter" />

</set>

</property>

</bean>

<!-- 2. 让MVC注解驱动使用自定义转换器 -->

<mvc:annotation-driven conversion-service="conversionService" />
步骤 3:测试使用

JSP 表单与方式 1 一致,控制器直接接收 Date 类型参数:

java 复制代码
@RequestMapping("/save4.do")

public String save4(User user) {

System.out.println("生日:" + user.getBirthday()); // 打印:Fri May 20 00:00:00 CST 2024

return "suc";

}

五、使用原生 Servlet API

SpringMVC 支持在控制器方法中直接获取原生 Servlet 对象(如 HttpServletRequest、HttpServletResponse),无需手动创建。

代码示例
java 复制代码
import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

/**

* 直接接收原生Servlet API:参数列表中直接声明即可

*/

@RequestMapping("/save5.do")

public String save5(

HttpServletRequest request,

HttpServletResponse response,

HttpSession session // 也可直接声明HttpSession

) {

// 1. 获取请求参数

String username = request.getParameter("username");

String age = request.getParameter("age");

System.out.println("原生API获取参数:" + username + "," + age);

// 2. 操作Session

session.setAttribute("user", username);

String sessionUser = (String) session.getAttribute("user");

System.out.println("Session中的用户:" + sessionUser);

// 3. 操作响应(如设置响应头)

response.setContentType("text/html;charset=UTF-8");

return "suc";

}
支持的原生对象
  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • java.security.Principal
  • Locale(国际化相关)
  • InputStream/OutputStream
  • Reader/Writer

六、常见问题与避坑指南

1.参数绑定失败(报 400 错误)

  • 原因:表单 name 与参数名 / JavaBean 属性名不一致;基本类型接收了 null 值。
  • 解决:检查 name 属性拼写;用包装类(Integer)替代基本类型(int)。

2.中文乱码

  • 原因:未配置中文过滤器;过滤器顺序错误。
  • 解决:按步骤配置 CharacterEncodingFilter;确保过滤器在最前面。

3.日期转换失败

  • 原因:未配置自定义转换器;日期格式与注解指定格式不一致。
  • 解决:使用 @DateTimeFormat 或自定义 Converter;确保表单日期格式匹配。

4.JavaBean 属性无法注入

  • 原因:未提供 Setter 方法;属性名与表单 name 不一致;无参构造缺失。
  • 解决:生成完整的 Setter 方法;检查 name 属性;保留无参构造。
相关推荐
952362 小时前
数据结构-二叉树
java·数据结构·学习
普通网友2 小时前
高性能TCP服务器设计
开发语言·c++·算法
普通网友2 小时前
C++与硬件交互编程
开发语言·c++·算法
一 乐2 小时前
宠物猫店管理|宠物店管理|基于Java+vue的宠物猫店管理管理系统(源码+数据库+文档)
java·前端·数据库·vue.js·后端·宠物管理
r***99822 小时前
在2023idea中如何创建SpringBoot
java·spring boot·后端
熊猫比分管理员2 小时前
【全栈源码解决方案】Vue+Java四端齐全,一周交付可运行项目!
java·前端·vue.js
chen_note2 小时前
K8s的配置存储与实战
java·容器·kubernetes·volume·k8s存储
i***39582 小时前
ShardingSphere-jdbc 5.5.0 + spring boot 基础配置 - 实战篇
java·spring boot·后端
Elias不吃糖2 小时前
整合了c++里面常用的STL及其常用API
开发语言·c++·学习·stl