Spring MVC域对象共享数据

1年前 (2024-04-27)
在 Spring MVC 中,控制器在接收到 DispatcherServlet 分发过来的请求后,会继续调用 Model 层对请求进行处理。Model 层处理完请求后的结果被称为模型数据,会将模型数据返回给 Controller。Controller 在接收到 Model 层返回的模型数据后,下一步就是将模型数据通过域对象共享的方式传递给 View 视图进行渲染,最终返回给客户端展示。

域对象是服务器在内存上创建的一块存储空间,主要用不同动态资源之间的数据传递和数据共享。在 Spring MVC 中,常用的域对象有 request 域对象、session 域对象、application 域对象等。

Spring MVC 提供了多种域对象共享数据的方式,其中最常用的方式如下:

  • 使用 Servlet API 向 request 域对象中共享数据

  • 使用 ModelAndView 向 request 域对象中共享数据

  • 使用 Model 向 request 域对象中共享数据

  • 使用 Map 向 request 域对象中共享数据

  • 使用 ModelMap 向 request 域对象中共享数据

  • 使用 Servlet API 向 session 域中共享数据

  • 使用 Servlet API 向 application 域中共享数据


下面我们就一一对这几种域对象共享数据的方式进行介绍。

1. 使用 Servlet API 向 request 域对象中共享数据

我们可以在控制器方法中设置一个 HttpServletRequest 类型的形参。通过它,我们就可以将模型数据共享到 request 域对象中,示例代码如下。

@RequestMapping("/testServletAPI")

public String testServletAPI(HttpServletRequest request) {

request.setAttribute("testScope", "hello,Servet API");

return "success";

}


由于这种方式是通过原生 Servlet API 实现的,会导致控制器与 Servlet 容器耦度过高,因此通常情况下,我们不使用这种方式向 request 域对象中共享数据。

2. 使用 ModelAndView 向 request 域对象中共享数据

我们还可以通过 Spring 提供的 ModelAndView 向 reuqest 域对象中共享数据。ModelAndView 主要由 model(模型)和 view(视图)两部分组成。其中,model 负责数据共享,而 view 则主要用于设置视图,实现页面的跳转。

ModelAndView 为我们提供了多种方法,其中常用的方法如下表。

方法

说明

 ModelAndView addObject(String attributeName, @Nullable Object attributeValue)

添加模型数据

ModelAndView addObject(Object attributeValue)

ModelAndView addAllObjects(@Nullable Map<String, ?> modelMap)

void setViewName(@Nullable String viewName) 

设置视图

void setView(@Nullable View view) 


在 Controller 类中,ModelAndView 只有在作为控制器方法的返回值,返回给前端控制器(DispatcherServlet)时,前端控制器解析才会去解析它,示例代码如下。

@RequestMapping("/testModelAndView")

public ModelAndView testModelAndView() {

/**

* ModelAndView有Model和View的功能

* Model主要用于向请求域共享数据

* View主要用于设置视图,实现页面跳转

*/

ModelAndView mav = new ModelAndView();

//向请求域共享数据

mav.addObject("testScope", "hello,ModelAndView");

//设置视图,实现页面跳转

mav.setViewName("success");

return mav;

}

3. 使用 Model 向 request 域对象中共享数据

我们可以在 Controller 控制器方法中设置一个 Model 类型的形参。通过它,我们也可以向 request 域对象中共享数据,示例代码如下。

@RequestMapping("/testModel")

public String testModel(Model model) {

model.addAttribute("testScope", "hello,Model");

return "success";

}

4. 使用 Map 向 request 域对象中共享数据

我们可以在 Controller 控制器方法中设置一个 Map 类型的形参。通过它,我们也可以向 request 域对象中共享数据,示例代码如下。

@RequestMapping("/testMap")

public String testMap(Map<String, Object> map) {

map.put("testScope", "hello,Map");

return "success";

}

5. 使用 ModelMap 向 request 对象中共享数据

我们可以在 Controller 控制器方法中设置一个 ModelMap 类型的形参。通过它,我们也可以向 request 域对象中共享数据,示例代码如下。

@RequestMapping("/testModelMap")

public String testModelMap(ModelMap modelMap) {

modelMap.addAttribute("testScope", "hello,ModelMap");

return "success";

}

6. 使用 Servlet API 向 session 域对象中共享数据

我们可以在控制器方法中设置一个 HttpSession 类型的形参。通过它,我们就可以将数据共享到 session 域对象中,示例代码如下。

@RequestMapping("/testSession")

public String testSession(HttpSession session) {

session.setAttribute("testSessionScope", "hello,session");

return "success";

}

7. 使用 Servlet API 向 application 域对象中共享数据

我们可以在控制器方法中设置一个 HttpSession 类型的形参,并通过它获取到 application 域对象,最终我们就可以将数据共享到 application 域对象中,示例代码如下。

@RequestMapping("/testApplication")

public String testApplication(HttpSession session) {

ServletContext application = session.getServletContext();

application.setAttribute("testApplicationScope", "hello,application");

return "success";

}

示例

下面,我们就通过一个简单的案例,来演示下如何实现通过域对象中共享数据,将模型数据返回到 view 视图中。

1. 新建一个名为 springmvc-response-demo 的 Web 项目,并将 Spring MVC 相关的依赖引入到该项目中,web.xml 配置如下。

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3网站站点" rel="nofollow" />

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework网站站点" rel="nofollow" />

package net.biancheng.c.entity;

public class User {

private String userId;

private String userName;

private String password;

public String getUserId() {

return userId;

}

public void setUserId(String userId) {

this.userId = userId;

}

public String getUserName() {

return userName;

}

public void setUserName(String userName) {

this.userName = userName;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

@Override

public String toString() {

return "User{" +

"userId='" + userId + '\'' +

", userName='" + userName + '\'' +

", password='" + password + '\'' +

'}';

}

}


4. 在 net.biancheng.c.entity 包下,创建一个名为 Product 的实体类,代码如下。

package net.biancheng.c.entity;

import java.math.BigDecimal;

public class Product {

private Integer productId;

private String productName;

private BigDecimal price;

private Integer storage;

public Integer getProductId() {

return productId;

}

public void setProductId(Integer productId) {

this.productId = productId;

}

public String getProductName() {

return productName;

}

public void setProductName(String productName) {

this.productName = productName;

}

public BigDecimal getPrice() {

return price;

}

public void setPrice(BigDecimal price) {

this.price = price;

}

public Integer getStorage() {

return storage;

}

public void setStorage(Integer storage) {

this.storage = storage;

}

@Override

public String toString() {

return "Product{" +

"productId=" + productId +

", productName='" + productName + '\'' +

", price=" + price +

", storage=" + storage +

'}';

}

}


5. 在 net.biancheng.c.controller 包下,创建一个名为 LoginController 的 Controller 类,代码如下。

package net.biancheng.c.controller;

import net.biancheng.c.entity.User;

import net.biancheng.c.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

@Controller

public class LoginController {

@Autowired

private UserService userService;

@RequestMapping("/user")

public String sayHello() {

return "user";

}

@RequestMapping("/login")

public String login(User user, HttpServletRequest request) {

User user2 = userService.getUserByUserName(user.getUserName());

if (user2 != null && user2.getPassword().equals(user.getPassword())) {

HttpSession session = request.getSession();

session.setAttribute("loginUser", user2);

return "redirect:/getProductList";

}

request.setAttribute("msg", "账号或密码错误!");

return "user";

}

}


6. 在 net.biancheng.c.controller 包下,创建一个名为 ProductController 的 Controller 类,代码如下。

package net.biancheng.c.controller;

import net.biancheng.c.entity.Product;

import net.biancheng.c.service.ProductService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@Controller

public class ProductController {

@Autowired

private ProductService productService;

@RequestMapping("/getProductList")

public ModelAndView getProductList() {

ModelAndView modelAndView = new ModelAndView();

modelAndView.setViewName("productList");

List<Product> productList = productService.getProductList();

modelAndView.addObject(productList);

return modelAndView;

}

@RequestMapping("/getProduct")

public String getProduct(Integer productId, Model model) {

Product productById = productService.getProductById(productId);

model.addAttribute("product", productById);

return "product";

}

}


7. 在 net.biancheng.c.service 包下,创建一个名为 UserService 的接口,代码如下。

package net.biancheng.c.service;

import net.biancheng.c.entity.User;

public interface UserService {

User getUserByUserName(String userName);

}


8. 在 net.biancheng.service.impl 包下,创建 UserService 接口的实现类 UserServiceImpl,代码如下。

package net.biancheng.c.service.impl;

import net.biancheng.c.dao.UserDao;

import net.biancheng.c.entity.User;

import net.biancheng.c.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

@Service("userService")

public class UserServiceImpl implements UserService {

@Autowired

private UserDao userDao;

@Override

public User getUserByUserName(String userName) {

return userDao.getUserByUserName(userName);

}

}


9. 在 net.biancheng.c.service 包下,创建一个名为 ProductService 的接口,代码如下。

package net.biancheng.c.service;

import net.biancheng.c.entity.Product;

import java.util.List;

public interface ProductService {

List<Product> getProductList();

Product getProductById(Integer productId);

}


10. 在 net.biancheng.service.impl 包下,创建 ProductService 接口的实现类 ProductServiceImpl,代码如下。

package net.biancheng.c.service.impl;

import net.biancheng.c.dao.ProductDao;

import net.biancheng.c.entity.Product;

import net.biancheng.c.service.ProductService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.List;

@Service("productService")

public class ProductServiceImpl implements ProductService {

@Autowired

private ProductDao productDao;

@Override

public List<Product> getProductList() {

return productDao.getProductList();

}

@Override

public Product getProductById(Integer productId) {

return productDao.getProductById(productId);

}

}


11. 在 net.biancheng.c.dao 包下,创建一个名为 UserDao 的类,代码如下。

package net.biancheng.c.dao;

import net.biancheng.c.entity.User;

import org.springframework.stereotype.Repository;

import java.util.*;

@Repository

public class UserDao {

private static Map<String, User> users = null;

static {

users = new HashMap<String, User>();

User user = new User();

user.setUserId("1001");

user.setUserName("C语言中文网默认用户");

user.setPassword("123456789");

User user1 = new User();

user1.setUserId("1002");

user1.setUserName("南忘");

user1.setPassword("qwertyuiop");

User user2 = new User();

user2.setUserId("1003");

user2.setUserName("Java用户");

user2.setPassword("987654321");

User user3 = new User();

user3.setUserId("1004");

user3.setUserName("李小龙");

user3.setPassword("1qazxsw2");

users.put(user.getUserName(), user);

users.put(user1.getUserName(), user1);

users.put(user2.getUserName(), user2);

users.put(user3.getUserName(), user3);

}

public List getUserList() {

List userList = new ArrayList();

Set<String> keys = users.keySet();

for (String key : keys) {

User user = users.get(key);

userList.add(user);

}

return userList;

}

public User getUserByUserName(String userName) {

User user = users.get(userName);

return user;

}

public void addUser(User user) {

users.put(user.getUserId(), user);

}

public void update(User user) {

users.put(user.getUserId(), user);

}

public void delete(String userId) {

users.remove(userId);

}

}


12. 在 net.biancheng.c.dao 包下,创建一个名为 ProductDao 的类,代码如下。

package net.biancheng.c.dao;

import net.biancheng.c.entity.Product;

import net.biancheng.c.entity.User;

import org.springframework.stereotype.Repository;

import java.math.BigDecimal;

import java.util.*;

@Repository

public class ProductDao {

private static Map<Integer, Product> products = null;

static {

products = new HashMap<Integer, Product>();

Product product = new Product();

product.setProductId(1);

product.setProductName("茅台");

product.setPrice(new BigDecimal(9999));

Product product1 = new Product();

product1.setProductId(2);

product1.setProductName("五粮液");

product1.setPrice(new BigDecimal(8888));

Product product2 = new Product();

product2.setProductId(3);

product2.setProductName("信阳毛尖");

product2.setPrice(new BigDecimal(7777));

Product product3 = new Product();

product3.setProductId(4);

product3.setProductName("深州大蜜桃");

product3.setPrice(new BigDecimal(6666));

products.put(product.getProductId(), product);

products.put(product1.getProductId(), product1);

products.put(product2.getProductId(), product2);

products.put(product3.getProductId(), product3);

}

public List getProductList() {

List productList = new ArrayList();

Set<Integer> keys = products.keySet();

for (Integer key : keys) {

Product product = products.get(key);

productList.add(product);

}

return productList;

}

public Product getProductById(Integer productId) {

return products.get(productId);

}

}


13. 在 webapp/WEB-INF 下新建一个 templates 目录,并在该目录下创建 user.html,代码如下。

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf网站站点" rel="nofollow" />

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf网站站点" rel="nofollow" />

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf网站站点" rel="nofollow" /> 登录页

图1:登陆页面


17. 分别输入错误的用户名和密码,结果如下图。


图2:登陆错误


18. 在登录页中,分别输入用户名:C语言中文网默认用户,密码:123456789,如下图。


图3:登陆正确

19. 点击“提交”按钮,跳转到商品列表页,如下图。

商品列表

图4:商品列表


20. 点击“查看商品详细信息”,结果如下图。

商品详情

图5:商品详情