业务数据绑定到域对象

1.绑定到request对象和session域对象区别

Spring MVC 的视图层解析过程中,业务数据通常需要绑定到某个域对象中,以便在视图(例如 JSP、Thymeleaf、Freemarker)中能够访问和显示这些数据。Spring MVC 提供了不同的 域对象(Scope Object),例如 requestsession,它们的生命周期和作用范围不同,因此绑定数据的目的和使用场景也有所区别。

具体来说,把业务数据绑定到 request 对象 把业务数据绑定到 session 域对象 是两种不同的绑定数据的方式,它们的作用范围和使用场景不同。下面我详细解释两者的含义以及它们的区别。

1.1 把业务数据绑定到 request 对象

当你将数据绑定到 request 对象 时,数据的作用范围仅限于一次请求的生命周期。也就是说,这些数据会在一次请求完成后被销毁。

生命周期

  • 数据只在当前请求有效。当请求结束或跳转到另一个页面时,数据就会消失。

适用场景

  • 单次请求内的数据传递:当业务数据只需要在当前请求中使用(例如传递给视图来显示),而在后续请求中不再需要时,使用 request 范围绑定数据最为合适。
  • 页面转发:当控制器通过 forward 转发请求时,可以通过 request 对象在多个组件(例如控制器和视图)之间共享数据。

1.1.1 业务数据的绑定过程

在Spring MVC中,业务数据的绑定过程通常如下:

  1. 控制器接收请求:当客户端发送一个HTTP请求时,Spring MVC的控制器会接收到这个请求。

  2. 处理请求并生成业务数据:控制器调用服务层或其他业务逻辑来处理请求,并生成相应的业务数据。

  3. 将业务数据绑定到特定的域对象

    • 通过ModelModelAndView将生成的业务数据添加到模型中。
    • 这些数据会被Spring MVC自动传递给视图层,用于在页面上展示。
  4. 返回视图名称:控制器方法会返回一个视图名称,Spring MVC会将模型数据与视图名称一起交给ViewResolver

  5. 视图解析与渲染ViewResolver根据视图名称找到对应的视图模板(如JSP、Thymeleaf等),并将模型数据传递给视图进行渲染,最终生成HTML内容返回给客户端。

1.1.2 示例

以下是一个典型的Spring MVC控制器方法示例:

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

    @GetMapping("/greeting")
    public String greeting(Model model) {
        // 业务数据
        String message = "Hello, Spring MVC!";
        
        // 将业务数据绑定到Model对象
        model.addAttribute("message", message);
        
        // 返回视图名称
        return "greeting";
    }
}

解释

  1. 业务数据的生成:在这个例子中,message是生成的业务数据,内容为 "Hello, Spring MVC!"

  2. 将业务数据绑定到Model对象model.addAttribute("message", message)message这个业务数据添加到Model对象中,键为"message"

  3. 返回视图名称:方法返回的视图名称是"greeting",Spring MVC会根据这个名称找到对应的视图模板。

  4. 视图渲染:在视图模板(如JSP或Thymeleaf)中,你可以通过 ${message} 来访问这个数据。

 JSP示例

<!-- greeting.jsp -->
<html>
<body>
    <h1>${message}</h1>
</body>
</html>

 无论使用哪种方式将业务数据添加到模型中,最终这些数据都会被绑定到视图层(如JSP页面),并通过ViewResolver解析。


1.2 把业务数据绑定到 session 域对象

将数据绑定到 session 对象 时,数据的作用范围扩展到整个会话期间。也就是说,只要用户的会话(Session)仍然有效,数据将会被保留,多个请求之间可以共享这些数据。

生命周期:数据的作用范围是用户的整个会话期,直到会话失效或手动移除数据为止。

  • 数据的作用范围是用户的整个会话期,直到会话失效或手动移除数据为止。

适用场景

  • 多次请求间的数据共享:当数据需要在用户的多次请求之间共享时(例如用户登录状态、购物车数据),绑定到 session 域是非常适合的选择。
  • 用户会话期数据存储:通常用来保存用户的会话信息,如用户认证信息、个性化设置、用户行为记录等。

1.2.1 示例

在Spring MVC中,你可以通过 @SessionAttributes 注解或 HttpSession 对象将数据绑定到 session 域对象中。

方法一:使用 @SessionAttributes 注解
@Controller
@SessionAttributes("user")
public class UserController {

    @RequestMapping("/login")
    public String loginUser(Model model) {
        // 将业务数据(例如用户信息)绑定到 session 对象
        User user = new User("john_doe", "John Doe");
        model.addAttribute("user", user); // "user" 被绑定到 session

        return "dashboard";
    }
}

在这个示例中,@SessionAttributes("user") 注解表示将名为 "user" 的属性放入 session 域对象中。这个数据可以在当前会话中的多个请求之间共享。

方法二:使用 HttpSession 对象
@RequestMapping("/addToCart")
public String addToCart(HttpSession session, @RequestParam("product") String product) {
    // 获取 session 中的购物车数据
    List<String> cart = (List<String>) session.getAttribute("cart");

    if (cart == null) {
        cart = new ArrayList<>();
        session.setAttribute("cart", cart);
    }

    cart.add(product); // 将产品添加到购物车

    return "cartPage";
}

在这个示例中,使用 HttpSession 对象手动操作 session 域,存储或读取业务数据。购物车信息会存储在用户的 session 中,可以跨多次请求进行共享。

详细使用可以参考Session在 Spring MVC中的操作与应用


1.3 requestsession 域对象的区别

特性request 域对象session 域对象
生命周期只在当前请求有效在整个用户会话期间有效
数据共享数据只在当前请求内共享数据在多个请求之间共享
使用场景页面转发时在控制器和视图之间传递数据多次请求中保存和共享数据,如用户登录状态
数据存储位置服务器的 HttpServletRequest 对象中服务器的 HttpSession 对象中
典型用例页面渲染时显示临时数据(如表单数据、结果)登录用户信息、购物车、长期的用户状态
数据生存时间请求结束时自动销毁用户会话结束时才销毁
数据量适合处理较小、短期的数据适合处理较大或长期的数据

1.3.1 具体的使用场景

  • request 域适用场景
    1. 当你需要在页面跳转时传递临时信息,如表单提交结果、一次性提示信息(例如“提交成功”)。
    2. 页面间的短期数据共享。例如,控制器处理表单数据后将处理结果通过 request 传递到 JSP 显示。
  • session 域适用场景
    1. 当你需要保存用户的长期状态信息,如用户登录状态、偏好设置等。
    2. 购物车功能,用户在不同页面添加商品,直到结账时数据都需要保持。

1.3.2 总结

  • request:适合用于 短期 数据的传递,数据在 单个请求 内有效。典型的场景是控制器处理请求后将数据传递给视图层进行展示,或者在控制器和视图之间通过页面转发传递数据。
  • session:适合用于 长期 数据的共享,数据在用户的 会话期间 有效。典型的应用场景是保存用户的登录信息、购物车数据等,可以跨多个请求共享。

在实际开发中,选择将数据绑定到 request 还是 session 取决于数据的生命周期需求。如果只是一次性展示或页面跳转后就不再需要的数据,绑定到 request 是合适的;而如果数据需要在多次请求中持续有效,则应该绑定到 session

2.将业务数据绑定到request对象的具体方法 

2.1 使用Model添加业务数据

Model是Spring MVC中最常用的方式之一,用于将业务数据传递给视图。在控制器方法中,你可以通过Model对象来添加数据。

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

    @GetMapping("/greeting")
    public String greeting(Model model) {
        model.addAttribute("message", "Hello, Spring MVC!");
        return "greeting"; // 返回视图名称
    }
}

解释

  • Model对象Model对象用于在控制器方法中添加业务数据。addAttribute方法将数据添加到模型中,键是"message",值是"Hello, Spring MVC!"
  • 返回视图名称:控制器方法返回视图名称 "greeting",Spring MVC会将模型中的数据绑定到视图,并交给ViewResolver解析和渲染。

2.2 使用ModelAndView添加业务数据

ModelAndView对象结合了视图名称和模型数据,它允许你同时指定视图名称并添加业务数据。

示例

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MyController {

    @GetMapping("/welcome")
    public ModelAndView welcome() {
        ModelAndView mav = new ModelAndView("welcome"); // 设置视图名称
        mav.addObject("message", "Welcome to Spring MVC!");
        return mav;
    }
}

解释

  • ModelAndView对象ModelAndView既包含视图名称,也包含模型数据。你可以使用addObject方法向模型中添加数据。
  • 返回ModelAndView对象:控制器方法返回ModelAndView,Spring MVC将自动处理视图名称和模型数据的绑定。

2.3 使用@ModelAttribute注解添加业务数据

2.3.1 使用@ModelAttribute在方法参数上绑定数据

当你在控制器方法的参数上使用@ModelAttribute注解时,Spring会自动将请求参数与方法参数中的Java对象进行绑定。这通常用于表单提交或请求中传递复杂的数据对象。

示例:绑定请求参数到Java对象

假设你有一个简单的用户表单,提交数据时通过URL或POST请求传递参数。

User类

public class User {
    private String name;
    private int age;

    // Getter and Setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

控制器方法

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class UserController {

    @PostMapping("/addUser")
    public String addUser(@ModelAttribute User user) {
        // 此时user对象已经绑定了请求中的name和age参数
        System.out.println("User Name: " + user.getName());
        System.out.println("User Age: " + user.getAge());
        
        // 返回视图名称
        return "userDetails";
    }
}

表单示例

<form action="/addUser" method="post">
    Name: <input type="text" name="name"/><br/>
    Age: <input type="text" name="age"/><br/>
    <input type="submit" value="Submit"/>
</form>

解释

  1. 请求参数绑定:当表单提交后,Spring会自动将请求参数nameage绑定到User对象的nameage属性上。
  2. @ModelAttribute作用@ModelAttribute注解告诉Spring要将请求参数绑定到控制器方法参数User对象上,然后将User对象作为方法参数传入控制器方法。

2.3.2 使用@ModelAttribute在方法上添加业务数据

@ModelAttribute还可以用于控制器方法上,在每次请求之前自动向模型中添加数据。这个方法通常用于在视图层中需要共享一些通用的数据,比如导航菜单、用户信息等。

示例:在方法上使用@ModelAttribute添加共享数据

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    // 每次请求之前,向模型中添加默认消息
    @ModelAttribute
    public void addDefaultMessage(Model model) {
        model.addAttribute("welcomeMessage", "Welcome to our website!");
    }

    @GetMapping("/home")
    public String homePage() {
        // 返回视图名称
        return "home";
    }

    @GetMapping("/about")
    public String aboutPage() {
        // 返回视图名称
        return "about";
    }
}

解释

  1. @ModelAttribute方法addDefaultMessage方法被@ModelAttribute注解标记,这意味着在每个请求处理之前,Spring会调用该方法并将返回的数据添加到模型中。在本例中,"welcomeMessage"会被添加到模型中,并可在所有视图中使用。(意思就是welcomeMessage这个变量已经被model传入了视图层,你在任何一个JSP页面当中都可以调用welcomeMessage这个变量,这个变量的值为“Welcome to our website!”。

  2. 在多个视图中共享数据:无论是访问/home还是/about路径,模型中都会包含"welcomeMessage",这使得在多个页面中共享某些数据非常简单。

2.3.3 使用@ModelAttribute在类级别添加数据

你还可以在控制器的类级别使用@ModelAttribute,以便将数据共享到该类中所有的请求处理方法。这与方法级别的@ModelAttribute相似,但它适用于整个控制器。

示例:在类级别使用@ModelAttribute

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;

@Controller
@ModelAttribute("projectName")
public class ProjectController {

    public String getProjectName() {
        return "Spring MVC Learning Project";
    }

    @GetMapping("/project")
    public String projectDetails() {
        return "projectDetails";
    }
}

解释

  • 类级别@ModelAttribute:在类级别声明的@ModelAttribute会使得"projectName"这个业务数据在控制器的所有处理方法中都可用。在本例中,getProjectName()方法返回的字符串将被添加到模型中,并在所有请求中可用。

这里为什么选择将getProjectName()方法的返回值作为projectName这个变量的值返回模型,是因为当@ModelAttribute("projectName")注解在类级别,就会从类的无注解方法中让找到的第一个无注解方法的返回值作为projectName的值返回模型。

示例代码中,首先projectDetails()方法前有注解@GetMapping("/project"),所以这个方法的返回值是作为视图名称来传递,其次它是在第二个,所以综合上述两个条件,将getProjectName()方法的返回值定义为projectName的值返回模型。

如果方法中有很多无注解的方法,并且你要让某个特定方法的返回值作为projectName的值,这个时候就可以将@ModelAttribute("projectName")注解只放在特定方法之前,控制器类中所有方法被调用之前都会先将这个特定方法的返回值传入projectName并传入模型传回视图层,再被调用。

2.3.4  @ModelAttribute结合ModelAndView使用

除了将@ModelAttribute直接用于模型数据绑定外,它还可以结合ModelAndView来实现模型和视图的组合。

示例:结合ModelAndView使用@ModelAttribute

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class ProductController {

    @GetMapping("/product")
    public ModelAndView getProductDetails(@ModelAttribute Product product) {
        ModelAndView mav = new ModelAndView("productDetails");
        mav.addObject("product", product);
        return mav;
    }
}

解释

@GetMapping("/product") 注解标识该方法用于处理 HTTP GET 请求,且请求路径为 /product。当客户端发送一个 GET 请求到 /product,Spring MVC 会将请求路由到这个方法。

public ModelAndView getProductDetails(@ModelAttribute Product product) {

@ModelAttribute 注解告诉 Spring MVC 将请求中的参数(比如 URL 中的 ?id=1&name=Product1)自动绑定到 Product 对象的属性上。Spring 会根据请求参数中的名称自动匹配 Product 对象的字段。

Product product:这个参数接收绑定好的 Product 对象,然后被传递到方法体内,供后续操作。

ModelAndView mav = new ModelAndView("productDetails");
  • ModelAndView 是 Spring MVC 提供的一个类,用于封装视图名称和模型数据。它包含两个核心部分:

    • 视图名称:即返回给前端的页面名称,Spring 会通过视图解析器找到该视图对应的页面进行渲染。
    • 模型数据:要传递给视图层的数据,通常以键值对形式存在。
    • new ModelAndView("productDetails")
      • 这里创建了一个 ModelAndView 对象,并指定视图名称为 "productDetails",表示该请求将渲染 productDetails 视图。
      • Spring MVC 会使用视图解析器根据 "productDetails" 名称来找到具体的页面文件(例如 JSP、Thymeleaf 模板等),并渲染该页面。
mav.addObject("product", product);

addObject("product", product) 方法用于将 product 对象添加到模型中,模型是传递给视图的数据。

  • 这里,"product" 是模型的属性名,product 是方法参数中传递的 Product 对象。
  • 这样,视图层可以通过访问 ${product} 来获取并展示 product 对象的属性。
return mav;
  • 最后,方法返回 ModelAndView 对象,这个对象包含了视图名称("productDetails")和模型数据(product 对象)。
  • Spring MVC 会将模型中的数据传递到指定的视图(productDetails),然后视图引擎(如 JSP、Thymeleaf 等)会根据模型数据渲染页面。

  • 用于方法参数时@ModelAttribute会将请求中的数据绑定到方法参数中的Java对象,这通常用于表单提交或复杂对象的传递。
  • 用于方法时@ModelAttribute可以在每个请求处理之前向模型中添加通用的业务数据,如共享的消息或菜单等信息。
  • 类级别使用,可以向所有控制器方法添加通用的模型数据,适用于需要在多个页面中共享的全局数据。

3. @ModelAttribute@RequestBody 的主要区别

特性@ModelAttribute@RequestBody
处理的数据来源URL参数和表单字段(即 application/x-www-form-urlencoded纯请求体中的数据(例如 JSON、XML 等)
数据格式处理表单字段(键值对,application/x-www-form-urlencoded处理 JSON 或 XML 格式的数据
适用场景适用于传统的表单提交、GET 参数、POST 的表单字段适用于 RESTful API,客户端以 JSON 或 XML 格式传递数据
数据绑定Spring自动从表单字段或URL参数解析,并绑定到对象属性上Spring 将请求体的JSON/XML 数据反序列化为Java对象
典型用法表单提交,用户登录、注册表单等场景RESTful API,传递复杂的对象或嵌套结构

3.1 @ModelAttribute:处理表单字段和URL参数

  • 表单字段绑定:当使用 POST 请求并提交表单时,表单数据以 application/x-www-form-urlencoded 格式包含在请求体中。@ModelAttribute 可以从请求体中的表单字段中解析数据,并将这些数据绑定到 Java 对象中。

    示例

    <form action="/submitUser" method="POST">
        <input type="text" name="name" value="Alice">
        <input type="text" name="age" value="30">
        <button type="submit">Submit</button>
    </form>
    

    控制器

    @PostMapping("/submitUser")
    public String submitUser(@ModelAttribute User user) {
        // Spring 从请求体中的表单字段解析数据并绑定到 User 对象
        System.out.println(user.getName()); // 输出 Alice
        return "userDetails";
    }
    

    请求体POST 请求中):

    name=Alice&age=30
    
    • 适用场景@ModelAttribute 主要用于处理传统的表单提交场景,表单字段数据会自动映射到对象的属性上。

3.2 @RequestBody:处理请求体中的 JSON 或 XML 数据

  • 请求体绑定@RequestBody 专门用于处理请求体中的数据,比如 JSON 或 XML 格式的数据。它不会处理表单字段,而是直接将请求体中的 JSON 或 XML 解析成 Java 对象。

    示例

    客户端传递 JSON 数据

    {
      "name": "Alice",
      "age": 30
    }
    

    控制器

    @PostMapping("/addUser")
    public String addUser(@RequestBody User user) {
        // Spring 将请求体中的 JSON 数据反序列化为 User 对象
        System.out.println(user.getName()); // 输出 Alice
        return "userDetails";
    }
    
    • 适用场景@RequestBody 主要用于处理 RESTful API 中的请求,在这些场景中,客户端通常通过 JSON 或 XML 格式向服务端发送数据。它更适合传递复杂的对象结构。

3.3 @ModelAttribute vs @RequestBody 处理数据的区别

  • @ModelAttribute 处理

    • 主要用于表单提交的场景(application/x-www-form-urlencoded)。
    • 它会从 URL 参数或请求体中的表单字段提取数据,自动绑定到 Java 对象。
    • 适合用于处理简单的键值对数据,如登录表单、注册表单等。
  • @RequestBody 处理

    • 专门用于处理请求体中的数据,特别是 JSON 或 XML 格式的数据。
    • 它通过消息转换器(如 Jackson 或 JAXB)将请求体中的数据反序列化为 Java 对象。
    • 适合用于处理复杂的对象结构,如嵌套的 JSON 或 XML。

3.4 实际场景中的区别

场景1:表单提交

如果你提交的是一个传统的表单,表单的字段以 application/x-www-form-urlencoded 格式发送,@ModelAttribute 会更合适:

<form action="/submitUser" method="POST">
    <input type="text" name="name" value="Alice">
    <input type="number" name="age" value="30">
    <button type="submit">Submit</button>
</form>

在这种情况下,@ModelAttribute 会解析这些表单字段,并将其映射到对象的属性上。

场景2:RESTful API 的 JSON 请求

如果你发送的是一个 REST API 请求,客户端以 JSON 格式发送数据,例如:

{
  "name": "Alice",
  "age": 30
}

在这种情况下,@RequestBody 是最佳选择,因为它可以处理请求体中的 JSON 数据,并将其反序列化为 Java 对象。

3.5 总结

  • @ModelAttribute:处理的是表单字段或URL参数,在POST请求时,虽然表单数据位于请求体中,但它仍然以键值对(application/x-www-form-urlencoded)的形式传递,适用于传统表单提交。

  • @RequestBody:处理的是请求体中的数据,特别是JSON、XML等复杂格式数据,适用于RESTful API中的数据传递。

所以,在POST请求的情况下,尽管表单字段和JSON数据都位于请求体中,但它们的格式不同:@ModelAttribute 适合处理 表单字段的键值对 格式(application/x-www-form-urlencoded),而 @RequestBody 适合处理 复杂格式的数据(如JSON或XML)。两者在数据来源、适用场景和处理机制上是有区别的。

4.  总结

方法

用法逻辑

适用场景

生命周期

Model 对象

将数据绑定到 request,用于单次请求传递给视图

单次请求中传递数据(如表单提交后显示结果)

当前请求有效

ModelAndView 对象

同时处理数据和视图,允许在一个对象中管理数据和视图

需要同时设置数据和视图的复杂场景(如根据不同情况返回不同视图)

当前请求有效

@ModelAttribute 注解

表单数据绑定到对象或提供全局共享数据

表单处理,或者在每次请求中都提供共享数据(如全局的配置或变量)

当前请求有效,或者与 session 结合使用

@SessionAttributes 注解

将数据存储在 session 中,允许跨多个请求共享数据

跨请求共享数据(如用户登录信息、购物车)用户会话期间有效

具体的选择逻辑

  1. 单次请求内数据传递:使用 ModelModelAndView 对象。Model 适用于简单的场景,只传递数据;ModelAndView 更灵活,适合需要控制视图和数据的场景。
  2. 表单处理:使用 @ModelAttribute 注解,简化表单数据与对象的绑定。
  3. 全局数据:在所有请求中提供通用数据时,使用 @ModelAttribute
  4. 跨请求共享数据:使用 @SessionAttributes 注解,将数据存储到会话中,适合需要在多个请求中共享的场景(如用户会话)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值