第一部分:请求参数绑定
1.1 绑定机制与前提条件
⭐ 老师强调 :Spring MVC 底层依然基于 Servlet 的
request.getParameter(),但通过方法参数列表直接声明,框架会自动完成绑定赋值。
核心要求 :表单提交的 name 属性必须与控制器方法形参名/实体类属性名完全一致(区分大小写)。
支持的数据类型:
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List、Map等)
- 复杂嵌套类型(实体套实体、实体套集合等)
1.2 六大绑定形式
1. 基本数据类型与字符串(同名接收)
@RequestMapping("/save1.do")
public String save(String username, Integer age) {
// 前端 form 的 name="username" 和 name="age" 自动绑定到这里
return "suc";
}
2. 实体类(JavaBean)接收
⭐ 老师强调 :字段多(如10个)时挨个写参数太麻烦。用实体类接收,只要
name和实体类属性名一致,自动映射。必须有无参构造、有参构造、get/set、toString。
public class User implements Serializable {
private String username;
private Integer age;
// get/set...
}
@RequestMapping("/save2.do")
public String save2(User user) {
System.out.println(user);
return "suc";
}
3. 实体类嵌套实体类(点语法接收)
前端表单必须写成 对象.属性 的形式:
金额:<input type="text" name="address.money" />
@RequestMapping("/save3.do")
public String save3(User user) {
System.out.println(user);
return "suc";
}
4. 实体类嵌套集合(索引接收)
前端表单必须写成 集合[索引].属性 的形式:
集合1:<input type="text" name="list[0].money" />
集合2:<input type="text" name="list[1].money" />
@RequestMapping("/save4.do")
public String save4(User user) {
System.out.println(user);
return "suc";
}
5. 参数名不一致(使用 @RequestParam 绑定)
⭐ 老师强调 :当方法形参名与前端
name不一致时,用@RequestParam绑定。
@RequestMapping("/save1.do")
public String save(@RequestParam(value = "username", required = false, defaultValue = "abc") String name) {
// required=true 默认,不传报 400;defaultValue 不传时给默认值
return "suc";
}
6. 使用原生 Servlet API
⭐ 老师强调:框架虽然做了简化,但依然支持原生 API。只需要在方法参数中定义,框架会自动注入。
@RequestMapping("/save6.do")
public String save6(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
System.out.println(request.getParameter("username"));
return "suc";
}
第二部分:中文乱码与日期格式转换
2.1 乱码的根源
⭐ 老师强调:电脑底层只认 0 和 1。字符要进电脑,先按某种编码(如 UTF-8)转成字节流,再转二进制。若用 UTF-8 编码,却用 GBK 解码,就会乱码(就像 A 密码本加密,B 密码本解密)。
2.2 解决乱码的三种方式
⭐ 老师强调:第一种侵入代码、局部生效;第二种更灵活但麻烦;第三种过滤器才是最佳实践。
方式一:手动设置请求编码(局部) 在 Servlet 或 Controller 方法第一行设置:
request.setCharacterEncoding("UTF-8");
方式二:String 重构转码(针对单一参数)
String name = new String(request.getParameter("username").getBytes("ISO-8859-1"), "UTF-8");
方式三:配置 Spring 提供的过滤器(最佳实践) 在 web.xml 中配置,拦截所有请求,统一设置编码:
<!-- 配置过滤器,解决中文乱码的问题 -->
<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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
⭐ 老师强调 :如果配置了过滤器还是乱码,检查是否遗漏了
<init-param>指定编码,或者 IDEA/Tomcat 自身的编码配置不对。
2.3 日期格式转换
⭐ 老师强调 :前端表单传日期默认格式是
yyyy/MM/dd(斜杠)。如果用横杠yyyy-MM-dd,框架会默认转换失败报错。有两种解决方案:
方式一:@DateTimeFormat 注解(推荐,简单)
直接在实体类的日期属性上加注解:
import org.springframework.format.annotation.DateTimeFormat;
public class User implements Serializable {
// 规定前端传这个格式的日期
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
}
⭐ 老师强调 :加了注解后,前端必须按注解规定的格式传(如
2026-10-18),否则报 400 错误。若前端传斜杠,需把pattern改为yyyy/MM/dd。注解只约束前端传入格式,不影响后台控制台打印格式。
方式二:自定义类型转换器(适合复杂格式/额外处理)
-
编写转换器类,实现
Converter<S, T>接口:public class StringToDate implements Converter<String, Date> {
@Override
public Date convert(String s) {
if(s == null) throw new RuntimeException("请输入内容");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
return sdf.parse(s);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
} -
在
springmvc.xml中注册转换器:<mvc:annotation-driven conversion-service="conversionService" />
⭐ 老师强调 :自定义转换器后,框架遇到该类转换不走默认模式,完全接管。它相比注解的优势是能对传来的字符串做其他额外处理(如复杂格式、中文处理)。
第三部分:常用注解详解
3.1 @RequestParam
作用:把请求中指定名称的参数赋值给控制器方法的形参(解决名不一致问题)。
属性:
value:请求参数的名字。required:是否必须(默认true,不传报错 400)。defaultValue:默认值。
代码示例:
// 前端请求:/user/query?name=张三&age=20
@RequestMapping("/query")
public String query(
@RequestParam(value = "name", required = true) String username,
@RequestParam(value = "age", required = false, defaultValue = "18") Integer userAge) {
System.out.println("用户名:" + username); // 张三
System.out.println("年龄:" + userAge); // 20
return "suc";
}
// 前端请求:/user/query?age=25 (没有传 name)
// 因为 required=true,直接报 400 错误:Required String parameter 'name' is not present
// 前端请求:/user/query?name=李四 (没有传 age)
// 因为 required=false 且有 defaultValue,userAge = 18
老师强调 :当注解只有一个
value属性时可省略不写;设了多个属性必须写明。传空串或 null 都会触发defaultValue。
3.2 @RequestBody
作用 :获取请求体内容(注意:GET 请求没有请求体,不能用)。
属性 :required(默认 true)。
注意 :常用于接收前端异步请求(如 Ajax)传来的 JSON 数据。可以直接用 String 接收整体请求体,也可以接收并封装为对象。
代码示例一:String 接收请求体
// 前端 Ajax 发送 POST 请求,Content-Type: application/json
// 请求体内容:{"username":"张三","age":20,"email":"zhangsan@qq.com"}
@RequestMapping("/save")
public String save(@RequestBody String body) {
System.out.println(body);
// 输出:{"username":"张三","age":20,"email":"zhangsan@qq.com"}
return "suc";
}
代码示例二:封装为对象接收(需要 Jackson 依赖)
// 前端 Ajax 发送 POST 请求,Content-Type: application/json
// 请求体内容:{"username":"李四","age":25}
@RequestMapping("/saveUser")
public String saveUser(@RequestBody User user) {
System.out.println(user);
// 输出:User{username='李四', age=25}
return "suc";
}
// 错误示范:GET 请求不能用 @RequestBody
@RequestMapping(value = "/query", method = RequestMethod.GET)
public String query(@RequestBody User user) {
// 报错:Required request body is missing
return "suc";
}
老师强调 :
@RequestBody只能用于 POST、PUT 等有请求体的请求方式,GET 请求没有请求体,用了会报错。
3.3 @PathVariable
作用 :绑定 URL 中的占位符 。用于支持 RESTful 风格。
属性 :value(URL 中占位符的名字)。
RESTful 风格示例:
// 前端访问:GET /emp/1001
@RequestMapping(path = "/emp/{id}", method = RequestMethod.GET)
public String findById(@PathVariable(value = "id") Integer id) {
System.out.println("通过id查询员工..." + id);
// 输出:通过id查询员工...1001
return "suc";
}
// 前端访问:DELETE /emp/1002
@RequestMapping(path = "/emp/{id}", method = RequestMethod.DELETE)
public String deleteById(@PathVariable("id") Integer id) {
System.out.println("删除员工..." + id);
// 输出:删除员工...1002
return "suc";
}
// 前端访问:PUT /emp/1003 (路径一样,method 不同走不同方法)
@RequestMapping(path = "/emp/{id}", method = RequestMethod.PUT)
public String updateById(@PathVariable("id") Integer id) {
System.out.println("更新员工..." + id);
// 输出:更新员工...1003
return "suc";
}
老师强调 :RESTful 风格(请求路径一样,根据
method不同去执行不同后台方法)结构清晰,是行业标准。此时web.xml前端控制器的url-pattern要改为/,否则{id}会被当作扩展名截断。访问delete/5时,框架会把 5 解析成 id=5 并自动绑定。
3.4 @RequestHeader 和 @CookieValue
@RequestHeader:获取请求头的值(如Accept、User-Agent)。@CookieValue:获取指定 Cookie 的值(如JSESSIONID)。
代码示例:
// 前端任意请求(浏览器自动带上请求头和 Cookie)
@RequestMapping("/header")
public String getHeader(
@RequestHeader("Accept") String accept,
@RequestHeader("User-Agent") String userAgent,
@CookieValue("JSESSIONID") String sessionId) {
System.out.println("Accept:" + accept);
// 输出:Accept:text/html,application/xhtml+xml,...
System.out.println("User-Agent:" + userAgent);
// 输出:User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64)...
System.out.println("JSESSIONID:" + sessionId);
// 输出:JSESSIONID:A1B2C3D4E5F6...
return "suc";
}
老师强调 :以前用原生 Servlet 获取请求头需要遍历枚举(判断
hasMoreElements(),强转 String),现在用注解直接 K-V 匹配,非常方便。
3.5 综合对比示例
| 注解 | 数据来源 | 适用场景 | 代码示意 |
|---|---|---|---|
@RequestParam |
URL 查询参数 ?key=value |
普通表单/GET 请求 | /query?name=张三 |
@RequestBody |
HTTP 请求体(JSON) | Ajax 异步 POST | {"name":"张三"} |
@PathVariable |
URL 路径中的占位符 | RESTful 风格 | /emp/1001 |
@RequestHeader |
HTTP 请求头 | 获取浏览器/客户端信息 | Accept: text/html |
@CookieValue |
Cookie | 获取会话 ID 等 | JSESSIONID=xxx |
老师总结 :日常开发中
@RequestParam、@RequestBody、@PathVariable使用频率最高,建议结合 Ajax 异步请求和 RESTful 接口一起练习,理解各自的数据来源差异。