处理器方法参数类型
1.HttpServletRequest
2.HttpServletResponse
3.HttpSession
4. 自定义参数类型
A. 基本类型参数:形参名称必须与请求包中请求参数名称相同
B. 引用类型参数:形参是一个对象,对象中属性名必须与请求参数名称相同
1. HttpServletRequest
用途:直接获取原始的 HttpServletRequest 对象,用于读取请求信息(如参数、头信息、属性等)。
示例:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/info")
public String getUserInfo(HttpServletRequest request, Model model) {
// 直接从 request 中获取请求参数
String name = request.getParameter("name");
Integer age = Integer.parseInt(request.getParameter("age"));
model.addAttribute("name", name);
model.addAttribute("age", age);
return "userInfo";
}
}
访问URL:http://localhost:8080/your-app/user/info?name=ZhangSan&age=20
2. HttpServletResponse
用途:直接获取原始的 HttpServletResponse 对象,用于操作响应(如设置头信息、写入输出流、设置Cookie等)。
示例:
@Controller
@RequestMapping("/download")
public class DownloadController {
@RequestMapping("/pdf")
public void downloadPdf(HttpServletResponse response) throws IOException {
// 1. 设置响应内容类型和头信息
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"demo.pdf\"");
// 2. 获取输出流并写入数据(这里简化了,实际应从文件或数据库读取)
OutputStream out = response.getOutputStream();
// ... 写入 PDF 数据的逻辑 ...
out.write(...);
out.close();
}
}
3. HttpSession
用途:获取当前请求的会话(Session)对象,用于在多次请求间存储和读取用户特定的数据。
示例:
@Controller
@RequestMapping("/cart")
public class ShoppingCartController {
// 将商品添加到购物车(Session)
@RequestMapping("/add")
public String addToCart(@RequestParam String itemId, HttpSession session) {
// 从 Session 中获取购物车对象,如果没有则创建一个新的
Map<String, Integer> cart = (Map<String, Integer>) session.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
session.setAttribute("cart", cart);
}
// 将商品添加到购物车
cart.put(itemId, cart.getOrDefault(itemId, 0) + 1);
return "redirect:/cart/view";
}
// 查看购物车
@RequestMapping("/view")
public String viewCart() {
return "cartPage";
}
}
4. 自定义参数类型
A. 基本类型参数
规则:方法形参的名称必须与HTTP请求中发送的参数名称完全相同。Spring会自动进行类型转换(如将String "20" 转换为 int 20)。
示例:
@Controller
@RequestMapping("/math")
public class MathController {
// 参数名 num1, num2 必须和请求中的参数名一致
@RequestMapping("/add")
@ResponseBody // 直接返回字符串到响应体,不找视图
public String add(int num1, int num2) {
int result = num1 + num2;
return "Result: " + result;
}
}
访问URL:http://localhost:8080/your-app/math/add?num1=10&num2=5
注意:如果参数名不一致,可以使用
@RequestParam注解进行映射。public String add(@RequestParam("firstNum") int num1, @RequestParam("secondNum") int num2)访问URL需变为:
...?firstNum=10&secondNum=5
B. 引用类型参数(对象绑定)
规则:将一个对象作为形参,该对象中的属性名必须与请求参数名称相同。Spring会自动创建该对象的实例并填充数据(这个过程称为数据绑定)。
示例:
-
创建自定义类(JavaBean):
// User.java public class User { private String name; private Integer age; private String email; // 必须提供 Getter 和 Setter 方法!!! public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } -
在控制器中使用:
@Controller @RequestMapping("/user") public class UserController { // Spring 会自动创建 User 对象,并根据请求参数名匹配并调用 setXxx() 方法 @RequestMapping("/create") @ResponseBody public String createUser(User user) { System.out.println("Creating user: " + user.getName() + ", " + user.getAge()); // 通常这里会调用 Service 层方法将 user 保存到数据库 return "User created successfully: " + user.getName(); } }
访问URL:http://localhost:8080/your-app/user/create?name=LiSi&age=25&email=lisi@example.com
工作原理:
Spring MVC 看到 User user 这个参数后,会:
- 调用
User类的无参构造函数创建对象。 - 遍历请求中的所有参数名(如
name,age,email)。 - 在
User类中查找与之对应的setName(),setAge(),setEmail()方法。 - 调用这些setter方法,将请求参数的值注入进去。
总结与要点
| 参数类型 | 关键点 | 适用场景 |
|---|---|---|
| HttpServletRequest | 获取原始请求对象 | 需要直接、底层地操作请求时 |
| HttpServletResponse | 获取原始响应对象 | 需要直接操作响应(如文件下载、流输出)时 |
| HttpSession | 获取会话对象 | 需要在多次请求间存储用户状态(如登录信息、购物车)时 |
| 基本类型参数 | 形参名=请求参数名 | 处理少量、简单的参数 |
| 引用类型参数 | 对象属性名=请求参数名 | 处理一组逻辑相关的参数,表单提交 |
强烈建议:
- 对于简单的参数,优先使用基本类型或搭配
@RequestParam。 - 对于复杂的、相关联的表单数据,优先使用对象引用类型,代码更清晰、更面向对象。
- 除非必要,否则尽量避免直接使用
HttpServletRequest和HttpServletResponse,因为这样会使得代码与 Servlet API 耦合,不如使用Spring提供的更高级的参数注解(如@RequestParam,@RequestBody等)简洁。
为什么属性名和请求参数名必须一致呢
想象一下,你是一个叫 Spring小助手 的机器人。你的任务是把用户提交的表单数据(一堆零散的 key=value),自动填充到一个Java对象(比如 User 对象)里。
用户传来的数据是这样的:userName=Tom&age=25。
User 对象看起来是这样的:
java
public class User {
private String userName;
private int age;
// 设置userName的方法
public void setUserName(String userName) {
this.userName = userName;
}
// 设置age的方法
public void setAge(int age) {
this.age = age;
}
}
你的工作就是执行 user.setUserName("Tom") 和 user.setAge(25)。
但问题是:你怎么知道要调用 setUserName 这个方法?
Spring小助手的“工作手册”(算法步骤)
你不会思考,只能严格按照以下步骤执行:
第1步:收集信息
你拿到了一串数据,并把它整理成一个清单(Map):
参数名 (Key) 参数值 (Value)
userName "Tom"
age "25"
第2步:分析目标对象
你面前有一个空的 User 对象。你拿出一个“方法探测器”(反射),扫描这个对象,找出所有“设置属性”的方法(setter方法)。你找到了两个:
setUserName(String name)
setAge(int age)
第3步:建立连接(最关键的匹配环节)
现在,你必须把 数据清单 和 方法列表 对应起来。你怎么做?
规则非常简单粗暴:看名字!
对于数据清单里的每一项,你都执行以下操作:
拿到数据项的Key:比如第一项的Key是 "userName"。
根据Key,推测方法名:你的工作手册告诉你,一个叫 xxx 的数据,对应的设置方法名叫 setXxx。
所以,你把 "userName" 变成 "setUserName"。
怎么变? 把首字母大写,然后在前面加上 "set"。
"userName" -> "set" + "U" + "serName" = "setUserName"。
在你的方法列表里寻找这个方法:你拿着 "setUserName" 这个名字,去方法列表里找。哎!发现列表里正好有一个方法叫 setUserName!
太好了,匹配成功!
于是,你通过“方法调用器”(反射的 invoke 方法),执行了 user.setUserName("Tom")。
继续下一个:你拿到下一个Key "age"。
推测出方法名:"set" + "A" + "ge" = "setAge"。
去方法列表里找,找到了 setAge 方法。
但是,你发现这个方法要的是 int 类型,而你手里的值是字符串 "25"。于是你调用“类型转换部”,把字符串 "25" 转换成数字 25。
最后,执行 user.setAge(25)。
整个过程圆满成功!
如果名字不一致会发生什么?
现在,我们搞点破坏。用户传来的数据变成了:name=Tom&age=25。(Key 从 userName 变成了 name)。
User 对象还是老样子,它的 setter 方法叫 setUserName,不是 setName。
Spring小助手再次开始工作:
数据清单:
Key Value
name "Tom"
age "25"
方法列表还是:setUserName, setAge。
匹配环节:
拿到Key "name"。
推测出方法名:"set" + "N" + "ame" = "setName"。
去方法列表里寻找 setName 方法...
找不到! 列表里只有 setUserName 和 setAge,根本没有 setName 这个方法。
这时Spring小助手会怎么办?
它的工作手册上写着:“如果找不到对应的方法,就跳过这个数据项,什么都不做。”
所以,它默默地跳过了 name=Tom 这个数据,继续去处理 age=25。最终,userName 属性因为没有得到赋值,保持了默认值 null。而 age 属性被成功设置为 25。
这就是为什么名字必须一致的根本原因!
SpringMVC(Spring小助手)通过请求参数的Key(name),来拼凑出一个它认为应该存在的setter方法名(setName)。然后它用反射去调用这个方法。如果这个方法在类里根本不存在,反射调用就会失败,数据自然就设置不进去。它无法智能地猜到 name 其实对应的是 userName 属性。
浙公网安备 33010602011771号