05-处理器方法的四种参数

处理器方法参数类型
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";
    }
}

访问URLhttp://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;
    }
}

访问URLhttp://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会自动创建该对象的实例并填充数据(这个过程称为数据绑定)。

示例

  1. 创建自定义类(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; }
    }
    
  2. 在控制器中使用

    @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();
        }
    }
    

访问URLhttp://localhost:8080/your-app/user/create?name=LiSi&age=25&email=lisi@example.com

工作原理
Spring MVC 看到 User user 这个参数后,会:

  1. 调用 User 类的无参构造函数创建对象。
  2. 遍历请求中的所有参数名(如 name, age, email)。
  3. User 类中查找与之对应的 setName(), setAge(), setEmail() 方法。
  4. 调用这些setter方法,将请求参数的值注入进去。

总结与要点

参数类型 关键点 适用场景
HttpServletRequest 获取原始请求对象 需要直接、底层地操作请求时
HttpServletResponse 获取原始响应对象 需要直接操作响应(如文件下载、流输出)时
HttpSession 获取会话对象 需要在多次请求间存储用户状态(如登录信息、购物车)时
基本类型参数 形参名=请求参数名 处理少量、简单的参数
引用类型参数 对象属性名=请求参数名 处理一组逻辑相关的参数,表单提交

强烈建议

  • 对于简单的参数,优先使用基本类型或搭配 @RequestParam
  • 对于复杂的、相关联的表单数据,优先使用对象引用类型,代码更清晰、更面向对象。
  • 除非必要,否则尽量避免直接使用 HttpServletRequestHttpServletResponse,因为这样会使得代码与 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 属性。

posted on 2025-09-14 19:35  笨忠  阅读(12)  评论(0)    收藏  举报