8.Spring MVC域对象共享数据

在 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 域对象中,示例代码如下。

  1. @RequestMapping("/testServletAPI")
  2. public String testServletAPI(HttpServletRequest request) {
  3. request.setAttribute("testScope", "hello,Servet API");
  4. return "success";
  5. }


由于这种方式是通过原生 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)时,前端控制器解析才会去解析它,示例代码如下。

  1. @RequestMapping("/testModelAndView")
  2. public ModelAndView testModelAndView() {
  3. /**
  4. * ModelAndView有Model和View的功能
  5. * Model主要用于向请求域共享数据
  6. * View主要用于设置视图,实现页面跳转
  7. */
  8. ModelAndView mav = new ModelAndView();
  9. //向请求域共享数据
  10. mav.addObject("testScope", "hello,ModelAndView");
  11. //设置视图,实现页面跳转
  12. mav.setViewName("success");
  13. return mav;
  14. }

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

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

  1. @RequestMapping("/testModel")
  2. public String testModel(Model model) {
  3. model.addAttribute("testScope", "hello,Model");
  4. return "success";
  5. }

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

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

  1. @RequestMapping("/testMap")
  2. public String testMap(Map<String, Object> map) {
  3. map.put("testScope", "hello,Map");
  4. return "success";
  5. }

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

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

  1. @RequestMapping("/testModelMap")
  2. public String testModelMap(ModelMap modelMap) {
  3. modelMap.addAttribute("testScope", "hello,ModelMap");
  4. return "success";
  5. }

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

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

  1. @RequestMapping("/testSession")
  2. public String testSession(HttpSession session) {
  3. session.setAttribute("testSessionScope", "hello,session");
  4. return "success";
  5. }

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

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

  1. @RequestMapping("/testApplication")
  2. public String testApplication(HttpSession session) {
  3. ServletContext application = session.getServletContext();
  4. application.setAttribute("testApplicationScope", "hello,application");
  5. return "success";
  6. }

示例

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

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

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  4. id="WebApp_ID" version="4.0">
  5. <display-name>first-springmvc-demo</display-name>
  6.  
  7. <!--请求和响应的字符串过滤器-->
  8. <filter>
  9. <filter-name>CharacterEncodingFilter</filter-name>
  10. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  11. <!--设置请求的编码-->
  12. <init-param>
  13. <param-name>encoding</param-name>
  14. <param-value>UTF-8</param-value>
  15. </init-param>
  16. <!--设置响应的编码,这里我们可以省略-->
  17. <init-param>
  18. <param-name>forceResponseEncoding</param-name>
  19. <param-value>true</param-value>
  20. </init-param>
  21. </filter>
  22. <filter-mapping>
  23. <filter-name>CharacterEncodingFilter</filter-name>
  24. <url-pattern>/*</url-pattern>
  25. </filter-mapping>
  26.  
  27.  
  28. <!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
  29. <servlet>
  30. <servlet-name>dispatcherServlet</servlet-name>
  31. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  32. <!--配置 DispatcherServlet 的一个初始化参数:spring mvc 配置文件按的位置和名称-->
  33. <init-param>
  34. <param-name>contextConfigLocation</param-name>
  35. <param-value>classpath:springMVC.xml</param-value>
  36. </init-param>
  37. <load-on-startup>1</load-on-startup>
  38. </servlet>
  39.  
  40. <servlet-mapping>
  41. <servlet-name>dispatcherServlet</servlet-name>
  42. <!--设置springMVC的核心控制器所能处理的请求的请求路径/所匹配的请求可以是/login或.html或.js或.css方式的请求路径但是/不能匹配.jsp请求路径的请求-->
  43. <url-pattern>/</url-pattern>
  44. </servlet-mapping>
  45. </web-app>


2.  在 src 下(类路径下)创建一个名为 springMVC.xml 的 Spring MVC 配置文件,配置内容如下。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:mvc="http://www.springframework.org/schema/mvc"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
  10.  
  11. <!--开启组件扫描-->
  12. <context:component-scan base-package="net.biancheng.c"></context:component-scan>
  13.  
  14. <!-- 配置 Thymeleaf 视图解析器 -->
  15. <bean id="viewResolver"
  16. class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
  17. <property name="order" value="1"/>
  18. <property name="characterEncoding" value="UTF-8"/>
  19. <property name="templateEngine">
  20. <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
  21. <property name="templateResolver">
  22. <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
  23. <!-- 视图前缀 -->
  24. <property name="prefix" value="/WEB-INF/templates/"/>
  25. <!-- 视图后缀 -->
  26. <property name="suffix" value=".html"/>
  27. <property name="templateMode" value="HTML5"/>
  28. <property name="characterEncoding" value="UTF-8"/>
  29. </bean>
  30. </property>
  31. </bean>
  32. </property>
  33. </bean>
  34. </beans>


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

  1. package net.biancheng.c.entity;
  2.  
  3. public class User {
  4. private String userId;
  5. private String userName;
  6. private String password;
  7.  
  8. public String getUserId() {
  9. return userId;
  10. }
  11.  
  12. public void setUserId(String userId) {
  13. this.userId = userId;
  14. }
  15.  
  16. public String getUserName() {
  17. return userName;
  18. }
  19.  
  20. public void setUserName(String userName) {
  21. this.userName = userName;
  22. }
  23.  
  24. public String getPassword() {
  25. return password;
  26. }
  27.  
  28. public void setPassword(String password) {
  29. this.password = password;
  30. }
  31.  
  32. @Override
  33. public String toString() {
  34. return "User{" +
  35. "userId='" + userId + '\'' +
  36. ", userName='" + userName + '\'' +
  37. ", password='" + password + '\'' +
  38. '}';
  39. }
  40. }


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

  1. package net.biancheng.c.entity;
  2.  
  3. import java.math.BigDecimal;
  4.  
  5. public class Product {
  6. private Integer productId;
  7. private String productName;
  8. private BigDecimal price;
  9. private Integer storage;
  10.  
  11. public Integer getProductId() {
  12. return productId;
  13. }
  14.  
  15. public void setProductId(Integer productId) {
  16. this.productId = productId;
  17. }
  18.  
  19. public String getProductName() {
  20. return productName;
  21. }
  22.  
  23. public void setProductName(String productName) {
  24. this.productName = productName;
  25. }
  26.  
  27. public BigDecimal getPrice() {
  28. return price;
  29. }
  30.  
  31. public void setPrice(BigDecimal price) {
  32. this.price = price;
  33. }
  34.  
  35. public Integer getStorage() {
  36. return storage;
  37. }
  38.  
  39. public void setStorage(Integer storage) {
  40. this.storage = storage;
  41. }
  42.  
  43. @Override
  44. public String toString() {
  45. return "Product{" +
  46. "productId=" + productId +
  47. ", productName='" + productName + '\'' +
  48. ", price=" + price +
  49. ", storage=" + storage +
  50. '}';
  51. }
  52. }


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

  1. package net.biancheng.c.controller;
  2.  
  3. import net.biancheng.c.entity.User;
  4. import net.biancheng.c.service.UserService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Controller;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8.  
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpSession;
  11.  
  12. @Controller
  13. public class LoginController {
  14. @Autowired
  15. private UserService userService;
  16.  
  17. @RequestMapping("/user")
  18. public String sayHello() {
  19. return "user";
  20. }
  21.  
  22. @RequestMapping("/login")
  23. public String login(User user, HttpServletRequest request) {
  24. User user2 = userService.getUserByUserName(user.getUserName());
  25. if (user2 != null && user2.getPassword().equals(user.getPassword())) {
  26. HttpSession session = request.getSession();
  27. session.setAttribute("loginUser", user2);
  28. return "redirect:/getProductList";
  29. }
  30. request.setAttribute("msg", "账号或密码错误!");
  31. return "user";
  32. }
  33. }


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

  1. package net.biancheng.c.controller;
  2.  
  3. import net.biancheng.c.entity.Product;
  4. import net.biancheng.c.service.ProductService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Controller;
  7. import org.springframework.ui.Model;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.servlet.ModelAndView;
  10.  
  11. import java.util.List;
  12.  
  13. @Controller
  14. public class ProductController {
  15. @Autowired
  16. private ProductService productService;
  17.  
  18. @RequestMapping("/getProductList")
  19. public ModelAndView getProductList() {
  20. ModelAndView modelAndView = new ModelAndView();
  21. modelAndView.setViewName("productList");
  22. List<Product> productList = productService.getProductList();
  23.  
  24. modelAndView.addObject(productList);
  25. return modelAndView;
  26.  
  27. }
  28.  
  29. @RequestMapping("/getProduct")
  30. public String getProduct(Integer productId, Model model) {
  31. Product productById = productService.getProductById(productId);
  32. model.addAttribute("product", productById);
  33. return "product";
  34. }
  35. }


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

  1. package net.biancheng.c.service;
  2.  
  3. import net.biancheng.c.entity.User;
  4.  
  5. public interface UserService {
  6.  
  7. User getUserByUserName(String userName);
  8.  
  9. }


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

  1. package net.biancheng.c.service.impl;
  2.  
  3. import net.biancheng.c.dao.UserDao;
  4. import net.biancheng.c.entity.User;
  5. import net.biancheng.c.service.UserService;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.stereotype.Service;
  8.  
  9. @Service("userService")
  10. public class UserServiceImpl implements UserService {
  11. @Autowired
  12. private UserDao userDao;
  13.  
  14. @Override
  15. public User getUserByUserName(String userName) {
  16. return userDao.getUserByUserName(userName);
  17. }
  18. }


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

  1. package net.biancheng.c.service;
  2.  
  3. import net.biancheng.c.entity.Product;
  4.  
  5. import java.util.List;
  6.  
  7. public interface ProductService {
  8.  
  9. List<Product> getProductList();
  10.  
  11. Product getProductById(Integer productId);
  12. }


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

  1. package net.biancheng.c.service.impl;
  2.  
  3. import net.biancheng.c.dao.ProductDao;
  4. import net.biancheng.c.entity.Product;
  5. import net.biancheng.c.service.ProductService;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.stereotype.Service;
  8.  
  9. import java.util.List;
  10.  
  11. @Service("productService")
  12. public class ProductServiceImpl implements ProductService {
  13. @Autowired
  14. private ProductDao productDao;
  15.  
  16. @Override
  17. public List<Product> getProductList() {
  18. return productDao.getProductList();
  19. }
  20.  
  21. @Override
  22. public Product getProductById(Integer productId) {
  23. return productDao.getProductById(productId);
  24. }
  25. }


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

  1. package net.biancheng.c.dao;
  2.  
  3. import net.biancheng.c.entity.User;
  4. import org.springframework.stereotype.Repository;
  5.  
  6. import java.util.*;
  7.  
  8. @Repository
  9. public class UserDao {
  10. private static Map<String, User> users = null;
  11.  
  12. static {
  13. users = new HashMap<String, User>();
  14. User user = new User();
  15. user.setUserId("1001");
  16. user.setUserName("C语言中文网默认用户");
  17. user.setPassword("123456789");
  18.  
  19. User user1 = new User();
  20. user1.setUserId("1002");
  21. user1.setUserName("南忘");
  22. user1.setPassword("qwertyuiop");
  23.  
  24. User user2 = new User();
  25. user2.setUserId("1003");
  26. user2.setUserName("Java用户");
  27. user2.setPassword("987654321");
  28.  
  29. User user3 = new User();
  30. user3.setUserId("1004");
  31. user3.setUserName("李小龙");
  32. user3.setPassword("1qazxsw2");
  33.  
  34. users.put(user.getUserName(), user);
  35. users.put(user1.getUserName(), user1);
  36. users.put(user2.getUserName(), user2);
  37. users.put(user3.getUserName(), user3);
  38. }
  39.  
  40.  
  41. public List getUserList() {
  42. List userList = new ArrayList();
  43. Set<String> keys = users.keySet();
  44. for (String key : keys) {
  45. User user = users.get(key);
  46. userList.add(user);
  47. }
  48. return userList;
  49. }
  50.  
  51. public User getUserByUserName(String userName) {
  52. User user = users.get(userName);
  53. return user;
  54. }
  55.  
  56. public void addUser(User user) {
  57. users.put(user.getUserId(), user);
  58. }
  59.  
  60. public void update(User user) {
  61. users.put(user.getUserId(), user);
  62. }
  63.  
  64. public void delete(String userId) {
  65. users.remove(userId);
  66. }
  67.  
  68. }


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

  1. package net.biancheng.c.dao;
  2.  
  3. import net.biancheng.c.entity.Product;
  4. import net.biancheng.c.entity.User;
  5. import org.springframework.stereotype.Repository;
  6.  
  7. import java.math.BigDecimal;
  8. import java.util.*;
  9.  
  10. @Repository
  11. public class ProductDao {
  12.  
  13. private static Map<Integer, Product> products = null;
  14.  
  15. static {
  16. products = new HashMap<Integer, Product>();
  17. Product product = new Product();
  18. product.setProductId(1);
  19. product.setProductName("茅台");
  20. product.setPrice(new BigDecimal(9999));
  21.  
  22. Product product1 = new Product();
  23. product1.setProductId(2);
  24. product1.setProductName("五粮液");
  25. product1.setPrice(new BigDecimal(8888));
  26.  
  27. Product product2 = new Product();
  28. product2.setProductId(3);
  29. product2.setProductName("信阳毛尖");
  30. product2.setPrice(new BigDecimal(7777));
  31.  
  32.  
  33. Product product3 = new Product();
  34. product3.setProductId(4);
  35. product3.setProductName("深州大蜜桃");
  36. product3.setPrice(new BigDecimal(6666));
  37.  
  38. products.put(product.getProductId(), product);
  39. products.put(product1.getProductId(), product1);
  40. products.put(product2.getProductId(), product2);
  41. products.put(product3.getProductId(), product3);
  42. }
  43.  
  44.  
  45. public List getProductList() {
  46. List productList = new ArrayList();
  47. Set<Integer> keys = products.keySet();
  48. for (Integer key : keys) {
  49. Product product = products.get(key);
  50. productList.add(product);
  51. }
  52. return productList;
  53. }
  54.  
  55. public Product getProductById(Integer productId) {
  56. return products.get(productId);
  57. }
  58. }


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

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>C语言中文网</title>
  6. </head>
  7. <body>
  8. <form th:action="@{/login}" method="post">
  9.  
  10. <table style="margin: auto">
  11. <tr>
  12. <td colspan="2" align="center">
  13. <p style="color: red;margin: auto" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
  14. </td>
  15. </tr>
  16. <tr>
  17. <td>用户名:</td>
  18. <td><input type="text" name="userName" required><br></td>
  19. </tr>
  20. <tr>
  21. <td>密码:</td>
  22. <td><input type="password" name="password" required><br></td>
  23. </tr>
  24. <tr>
  25. <td colspan="2" align="center"><input type="submit"></td>
  26. </tr>
  27. </table>
  28.  
  29. </form>
  30. </body>
  31. </html>


14. 在 webapp/WEB-INF/templates 目录下,新建一个 productList.html,代码如下。

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8.  
  9. <h1 th:text="'欢迎您:'+${session.loginUser.getUserName()}"></h1>
  10. <table th:border="1" th:cellspacing="0" th:cellpadding="10" style="text-align: center;">
  11. <thead>
  12. <th>商品id</th>
  13. <th>商品名</th>
  14. <th>商品价格</th>
  15. <th>操作</th>
  16. </thead>
  17. <tbody>
  18.  
  19. <tr th:each="m:${productList}">
  20. <td th:text="${m.getProductId()}"></td>
  21. <td th:text="${m.getProductName()}"></td>
  22. <td th:text="${m.getPrice()}"></td>
  23. <td>
  24. <a th:href="@{/getProduct(productId=${m.getProductId()})}">查看商品详细信息</a>
  25. </td>
  26. </tr>
  27. </tbody>
  28. </table>
  29. </body>
  30. </html>


15.  在 webapp/WEB-INF/templates 目录下,新建一个 product.html,代码如下。

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8.  
  9. <table>
  10. <tr>
  11. <td> 商品ID:</td>
  12. <td th:text="${product.getProductId()}"></td>
  13. </tr>
  14. <tr>
  15. <td>商品名:</td>
  16. <td th:text="${product.getProductName()}"></td>
  17. </tr>
  18. <tr>
  19. <td>商品价格:</td>
  20. <td th:text="${product.getPrice()}"></td>
  21. </tr>
  22. </table>
  23.  
  24. <a th:href="@{/getProductList}">返回首页</a>
  25. </body>
  26. </html>


16. 将 springmvc-response-demo 部署到 Tomcate 服务器中,启动 Tomcat 服务器。使用浏览器访问“http://localhost:8080/springmvc-response-demo/user”,结果如下。

登录页
图1:登陆页面


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


图2:登陆错误


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


图3:登陆正确

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

商品列表
图4:商品列表


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

商品详情
图5:商品详情
posted @ 2022-07-31 14:22  随遇而安==  阅读(91)  评论(0编辑  收藏  举报