• SpringMVC Day 04 : 数据绑定


    前言

    SpringMVC是一个非常流行的Java Web框架,它提供了很多方便的功能和工具来帮助我们构建高效、灵活的Web应用程序。其中,数据绑定就是SpringMVC中非常重要的一部分,它可以帮助我们方便地将请求参数绑定到Java对象上,从而简化了我们的开发流程。

    在本篇博客中,我们将深入探讨SpringMVC中的数据绑定机制,包括如何定义绑定规则、如何处理绑定错误等内容。希望本文能够对您理解SpringMVC的数据绑定机制有所帮助。

    一、什么是数据绑定

    数据绑定是一种编程技术,用于将数据模型的值自动地与用户界面元素(如文本框、标签、下拉菜单等)进行同步。当数据模型中的值发生变化时,这些变化会自动地反映在用户界面元素中,反之亦然。数据绑定可以减少开发人员的工作量,提高应用程序的可维护性和可重用性。

    数据绑定可以分为单向绑定和双向绑定两种类型。单向绑定是指只有在数据模型中的值发生变化时,才会更新用户界面元素的值。而双向绑定则是指在数据模型中的值发生变化时,不仅会更新用户界面元素的值,同时也会将用户界面元素中的值更新到数据模型中。

    二、前期准备

    1、新建项目,结构如下

    2、添加依赖
    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframeworkgroupId>
    4. <artifactId>spring-webmvcartifactId>
    5. <version>5.3.23version>
    6. dependency>
    7. <dependency>
    8. <groupId>org.projectlombokgroupId>
    9. <artifactId>lombokartifactId>
    10. <version>1.18.30version>
    11. dependency>
    12. <dependency>
    13. <groupId>ch.qos.logbackgroupId>
    14. <artifactId>logback-classicartifactId>
    15. <version>1.4.5version>
    16. dependency>
    17. dependencies>
    3、配置 web.xml
    1. "1.0" encoding="UTF-8"?>
    2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    5. version="4.0">
    6. <servlet>
    7. <servlet-name>dispatcherservlet-name>
    8. <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    9. <load-on-startup>1load-on-startup>
    10. servlet>
    11. <servlet-mapping>
    12. <servlet-name>dispatcherservlet-name>
    13. <url-pattern>/url-pattern>
    14. servlet-mapping>
    15. web-app>

    用于配置 Servlet 的映射和加载。在 Spring MVC 中,它用于配置 DispatcherServlet 的初始化和请求映射。

    具体来说,这段配置的作用如下:

    1. 定义了一个名为 "dispatcher" 的 Servlet,并指定了 org.springframework.web.servlet.DispatcherServlet 作为其处理类。
    2. 设置了 load-on-startup 属性为 1,表示在应用启动时就加载该 Servlet。
    3. 使用 元素将 "dispatcher" Servlet 映射到所有的请求路径上(即 /),意味着所有的请求都会经过该 Servlet 进行处理。

     这段配置的作用是将所有的请求交给 DispatcherServlet 处理,并让它成为应用的核心控制器。DispatcherServlet 将根据请求的 URL 和其他配置信息,将请求分发给相应的处理器方法进行处理,然后返回响应结果。

    4、新建并配置 dispacther-servlet.xml 文件
    1. "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" xmlns:mcv="http://www.springframework.org/schema/mvc"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    7. <context:component-scan base-package="edu.nf.ch04"/>
    8. <mvc:annotation-driven/>
    9. <mcv:default-servlet-handler/>
    10. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    11. <property name="prefix" value="/WEB-INF/jsp/"/>
    12. <property name="suffix" value=".jsp"/>
    13. bean>
    14. beans>

    这段 XML 配置的作用如下:

    1. :用于扫描指定包下的组件,并将其注册为 Spring 容器中的 Bean。这样可以自动发现和管理这些组件,使它们可以在应用程序中被使用。
    2. :启用 MVC 注解驱动,使得 Spring MVC 可以处理注解相关的请求映射、参数绑定、数据转换等操作。通过这个配置,你可以使用注解来定义控制器、请求映射、请求参数等,简化了开发过程。
    3. :启用默认的静态资源处理器。当有静态资源请求时(如 CSS、JS 文件),Spring MVC 将不会处理这些请求,而是将其交给容器的默认 Servlet 处理。这样可以提高性能并减少不必要的开销。
    4. :将指定路径下的静态资源映射到指定的 URL 路径上。在这个例子中,mapping="page/**" 表示将以 /page/ 开头的 URL 路径映射到静态资源,location="/static/" 表示静态资源的存放路径为 /static/。这样配置后,当访问以 /page/ 开头的 URL 路径时,Spring MVC 会将对应的静态资源返回给客户端。
    5. :定义了一个内部资源视图解析器 InternalResourceViewResolver,用于将逻辑视图名称解析为具体的 JSP 视图路径。prefix 属性表示 JSP 文件的前缀路径,suffix 属性表示 JSP 文件的后缀名。通过这个配置,可以简化控制器中返回视图的处理过程。

    这段配置主要是为了实现 Spring MVC 的基本功能,包括组件扫描、注解驱动、静态资源处理和视图解析等。它们共同协作,使得开发者可以更方便地开发和管理 Spring MVC 应用程序。
     

     5、在 entity 包下新建三个实体类 User、Card、address

    User 

    1. /**
    2. * @Date 2023-10-20
    3. * @Author qiu
    4. * 映射到实体的时候,字段名与请求中的 name 保持一致
    5. *
    6. */
    7. @Data
    8. public class User {
    9. private String userName;
    10. private Integer age;
    11. private Date birth;
    12. private List tel;
    13. // 一对一关联
    14. private Card card;
    15. // 一对多关联
    16. private List
      addresses;
    17. }

     Card

    1. @Data
    2. public class Card {
    3. private String cardNum;
    4. }

    Address

    1. @Data
    2. public class Address {
    3. private String addr;
    4. }

    二、把数据保存到作用域中

    1、使用原生 servlet 
    1. @Controller
    2. @Slf4j
    3. public class UserController {
    4. @PostMapping("/add")
    5. public ModelAndView add(HttpServletRequest request){
    6. String userName = request.getParameter("username");
    7. String age = request.getParameter("age");
    8. log.info(userName + " "+ age);
    9. // 将参数当如请求作用域中
    10. request.setAttribute("username",userName);
    11. request.setAttribute("age",age);
    12. return new ModelAndView("index");
    13. }
    14. }

    是一个基于Spring MVC框架的UserController类,其中包含了一个add()方法,用于处理HTTP POST请求。在该方法中,使用HttpServletRequest对象获取了请求参数(即用户名和年龄),并将它们记录在日志中。

    接着,使用HttpServletRequest对象将这些参数放入请求作用域中,以便在返回视图时能够在页面上显示这些参数。最后,使用ModelAndView对象将逻辑视图名("index")返回给前端控制器DispatcherServlet,以便DispatcherServlet能够找到对应的视图并进行渲染。

    2、通过 modelAndView 将参数放入请求作用域
    1. @Controller
    2. @Slf4j
    3. public class UserController {
    4. @PostMapping("/add")
    5. public ModelAndView add(HttpServletRequest request){
    6. String userName = request.getParameter("username");
    7. String age = request.getParameter("age");
    8. log.info(userName + " "+ age);
    9. // 通过 modelAndView 将参数放入请求作用域
    10. ModelAndView index = new ModelAndView("index");
    11. index.addObject("username",userName);
    12. index.addObject("age",age);
    13. return index;
    14. }
    15. }

    创建了一个ModelAndView对象,将逻辑视图名("index")作为构造函数的参数传入。然后,使用ModelAndView的addObject()方法将用户名和年龄作为键值对添加到ModelAndView对象中,以便在返回视图时能够在页面上显示这些参数。

     3、运行效果
     1)、在 index.html  页面中完成一个提交表单
    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Titletitle>
    6. head>
    7. <body>
    8. <h1>添加用户h1>
    9. <form action="../add2" method="post">
    10. Name:<input type="text" name="username" value="user"><br>
    11. Age:<input type="text" name="age" value="2000"><br>
    12. <input type="submit" value="提交">
    13. form>
    14. body>
    15. html>

    注意:这个 name 定义了以后,在控制器中就是获取这个 name 来获取它的 value 的。 

    2)在 index.jsp 中获取 index.html 提交的数据
    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <html>
    3. <head>
    4. <title>Titletitle>
    5. head>
    6. <body>
    7. <h1>首页h1>
    8. 用户名:${requestScope.username}<br>
    9. 年龄:${requestScope.age}<br>
    10. body>
    11. html>
     3) 运行效果

     4)使用原生 servlet 保存数据到作用域和 modelAndView 将参数放入请求作用域有什么区别

    在使用原生 Servlet 时,可以通过不同的方式将数据保存到作用域中,包括请求作用域、会话作用域和应用程序作用域。对于保存数据到作用域的不同方式,以及将参数放入请求作用域和使用 modelAndView 的区别,可以进行如下解释:

    1. 请求作用域:

      • 使用 request.setAttribute(String name, Object value) 方法将数据保存到请求作用域中。
      • 请求作用域的生命周期仅限于一次请求,当请求完成后,作用域中的数据会被销毁。
      • 请求作用域适合在同一个请求中的多个 Servlet 或 JSP 页面之间共享数据。
    2. modelAndView:

      • modelAndView 是一种模式,通常与 MVC(Model-View-Controller)架构一起使用。
      • 在 modelAndView 中,数据被封装在一个特定的对象中,该对象包含模型数据和视图信息。
      • 模型数据是指需要传递给视图显示的数据,而视图信息则指定了要显示的视图的名称或路径。
      • modelAndView 可以通过方法参数或返回值来传递,并且可以在控制器中进行处理和操作。
      • modelAndView 适合在 MVC 架构中,将处理逻辑和数据展示分离,提供更好的代码组织和可维护性。

    区别:

    • 生命周期:请求作用域的生命周期仅限于一次请求,而 modelAndView 可以在多个请求之间传递数据。
    • 使用方式:请求作用域需要手动将数据保存到作用域中,而 modelAndView 是通过方法参数或返回值来传递数据。
    • MVC 架构:modelAndView 通常与 MVC 架构一起使用,更适合于大型应用程序的开发和维护。
    • 数据封装:modelAndView 将数据封装在一个对象中,提供了更好的数据组织和管理。

    总结: 如果只是在同一个请求中传递数据,可以使用请求作用域;如果是在 MVC 架构中进行数据传递和视图展示,可以选择使用 modelAndView。具体选择哪种方式取决于项目需求和架构设计。

     

    三、将请求数据直接绑定到参数上

    1、使用默认参数名
    1. @PostMapping("/add2")
    2. public ModelAndView add2(String userName , Integer userAge,
    3. String[] tel, Date birth
    4. ){
    5. // 通过 modelAndView 将参数放入请求作用域
    6. ModelAndView index = new ModelAndView("index");
    7. // 将参数保存到请求作用域
    8. index.addObject("username",userName);
    9. index.addObject("age",userAge);
    10. index.addObject("tel1",tel[0]);
    11. index.addObject("tel2",tel[1]);
    12. index.addObject("birth",birth);
    13. return index;
    14. }

    该方法将接收到的参数数据保存到请求作用域中,并将请求重定向到名为 "index" 的视图。

     2、使用 @RequestParam 注解
    1. @PostMapping("/add2")
    2. public ModelAndView add2(@RequestParam(value = "username" ,required = true,defaultValue = "aaaa") String userName , @RequestParam("age") Integer userAge,
    3. String[] tel, Date birth
    4. ){
    5. // 通过 modelAndView 将参数放入请求作用域
    6. ModelAndView index = new ModelAndView("index");
    7. // 将参数保存到请求作用域
    8. index.addObject("username",userName);
    9. index.addObject("age",userAge);
    10. index.addObject("tel1",tel[0]);
    11. index.addObject("tel2",tel[1]);
    12. index.addObject("birth",birth);
    13. return index;
    14. }

    将请求数据直接绑定到参数上,默认参数名与请求中的 name 保持一致即可映射。否则使用 @RequestParam 注解

    1. required = true:必须提交
    2. defaultValue = "aaaa":设置默认值
    1) 这里需要对日期时间进行处理
    1. /**
    2. * 注册自定义转换器,@InitBinder 注解标注的方法会在执行
    3. * 任何 controller 的方法之前先执行,spring 会传入
    4. * 一个 webBinder 的参数,使用这个参数可以注册任意的 Formatter
    5. * @param binder 数据绑定器,用于注册各种格式化类
    6. */
    7. @InitBinder
    8. public void regFormatter(WebDataBinder binder){
    9. binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    10. }

     该 regFormatter 方法用于注册一个自定义的日期格式化器,将日期字符串按照格式 "yyyy-MM-dd" 进行解析和格式化。这样,在处理请求时,如果遇到需要将日期字符串转换为 Date 类型的情况,就会使用该自定义的格式化器进行处理。

    3 运行效果
     1)在 index.html 中完成提交
    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Titletitle>
    6. head>
    7. <body>
    8. <h1>添加用户h1>
    9. <form action="../add" method="post">
    10. Name:<input type="text" name="username" value="user"><br>
    11. Age:<input type="text" name="age" value="2000"><br>
    12. Tel1:<input type="text" name="tel" value="123123213213"><br>
    13. Tel2:<input type="text" name="tel" value="1231231233"><br>
    14. brith:<input type="text" name="birth" value="2000-05-03"><br>
    15. <input type="submit" value="提交">
    16. form>
    17. body>
    18. html>
    2) 在 index.jsp 获取 index.html 提交的数据
    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <html>
    3. <head>
    4. <title>Titletitle>
    5. head>
    6. <body>
    7. <h1>首页h1>
    8. 用户名:${requestScope.username}<br>
    9. 年龄:${requestScope.age}<br>
    10. 电话1:${requestScope.tel1}<br>
    11. 电话2:${requestScope.tel2}<br>
    12. 生日:${requestScope.birth}<br>
    13. body>
    14. html>
    3)运行

     

     四、获取 list 集合中的数据

    1、完成控制器
    1. @PostMapping("/add3")
    2. public ModelAndView add3(User user){
    3. // 通过 modelAndView 将参数放入请求作用域
    4. ModelAndView index = new ModelAndView("index");
    5. // 将参数保存到请求作用域
    6. index.addObject("username",user.getUserName());
    7. index.addObject("age",user.getAge());
    8. index.addObject("tel1",user.getTel().get(0));
    9. index.addObject("tel2",user.getTel().get(1));
    10. index.addObject("birth",user.getBirth());
    11. index.addObject("cardNum",user.getCard().getCardNum());
    12. log.info(user.getCard().getCardNum() + "========");
    13. index.addObject("addr1",user.getAddresses().get(0).getAddr());
    14. index.addObject("addr2",user.getAddresses().get(1).getAddr());
    15. return index;
    16. }

    // 一对多关联
    private List

    addresses; 实体类封装的是一个集合类型的实体,所这里获取就通过 addresses.get(0).getAddr();取获取第一个参数,以此类推。

      2、在 index.html 中完成提交
    1. "en">
    2. "UTF-8">
    3. Title
    4. 添加用户

    5. "../add2" method="post">
    6. Name:"text" name="username" value="user">
    7. Age:"text" name="age" value="2000">
    8. Tel1:"text" name="tel" value="123123213213">
    9. Tel2:"text" name="tel" value="1231231233">
    10. brith:"text" name="birth" value="2000-05-03">
    11. idCard:"text" name="card.cardNum" value="440990191929293939">
    12. addr1:"text" name="addresses[0].addr" value="珠海">
    13. addr2:"text" name="addresses[1].addr" value="霞山">
    14. "submit" value="提交">

     需要使用对象嵌套和集合嵌套的方式来处理。在表单元素中,可以通过 [0][1] 等索引来访问集合中的元素,如果有多个号码,也可以通过 .tel1.tel2 等属性名来访问对象中的属性。

    3、在 index.jsp 中获取 index.html 提交的数据
    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <html>
    3. <head>
    4. <title>Titletitle>
    5. head>
    6. <body>
    7. <h1>首页h1>
    8. 用户名:${requestScope.username}<br>
    9. 年龄:${requestScope.age}<br>
    10. 电话1:${requestScope.tel1}<br>
    11. 电话2:${requestScope.tel2}<br>
    12. 生日:${requestScope.birth}<br>
    13. 身份证:${requestScope.cardNum}<br>
    14. 住址1:${requestScope.addr1}<br>
    15. 住址2:${requestScope.addr2}<br>
    16. body>
    17. html>
     4、运行效果

    五、路径参数绑定

    1、完成控制器
    1. /**
    2. * 路径参数绑定
    3. * 请求格式:/url地址/(变量)
    4. * 并且使用 @PathVariable 注解
    5. * @param uid
    6. * @return
    7. */
    8. @GetMapping("/user/{id}")
    9. public ModelAndView getUser(@PathVariable("id") String uid){
    10. String aa = "";
    11. ModelAndView mav = new ModelAndView("index");
    12. mav.addObject("uid",uid);
    13. return mav;
    14. }

    创建了一个ModelAndView对象,并将逻辑视图名("index")作为构造函数的参数传入。然后,使用ModelAndView的addObject()方法将路径变量"uid"添加到ModelAndView对象中,以便在返回视图时能够在页面上显示该参数。

    @PathVariable注解的value属性用于指定路径变量名,如果方法参数名和路径变量名一致,则可以省略value属性。另外,@PathVariable注解还有其他可选属性,例如required、defaultValue等,用于指定路径变量是否必需,以及默认值等。 

     2、在 index.jsp 中获取路径传递的参数
    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <html>
    3. <head>
    4. <title>Titletitle>
    5. head>
    6. <body>
    7. <h1>首页h1>
    8. 路径参数:${requestScope.uid}<br>
    9. body>
    10. html>
    3、运行效果

    六、总结

     参数绑定是指将HTTP请求中的参数值绑定到方法的参数上,以便在方法中使用这些参数进行业务逻辑处理。在Spring MVC框架中,参数绑定可以通过多种方式实现,包括使用@RequestParam注解、使用@PathVariable注解、使用HttpServletRequest对象等。

    总结参数绑定的几个关键点如下:

    1. @RequestParam注解:用于将请求参数绑定到方法的参数上。可以指定参数名、是否必需、默认值等属性。适用于GET和POST请求。

    2. @PathVariable注解:用于将路径变量绑定到方法的参数上。可以指定路径变量名,并通过@PathVariable注解的value属性指定参数名。适用于RESTful风格的URL。

    3. HttpServletRequest对象:可以通过HttpServletRequest对象获取请求参数。适用于需要对请求参数进行更加复杂的处理或访问其他请求相关信息的情况。

    参数绑定的优势在于简化了开发过程,避免了手动解析请求参数的繁琐操作。同时,参数绑定也提供了一定的灵活性,可以根据具体业务需求选择不同的参数绑定方式。

    需要注意的是,在进行参数绑定时,应该考虑安全性和可靠性。对于用户输入的参数,应该进行合法性验证和防御性编程,以避免潜在的安全漏洞和错误。此外,还应该注意参数类型的匹配和转换,确保参数能够正确地绑定到方法的参数上。

    总而言之,参数绑定是Spring MVC框架中非常重要的功能之一,可以方便地获取和处理HTTP请求中的参数值,提高开发效率和代码可读性。在使用参数绑定时,需要注意安全性和可靠性,并根据具体业务需求选择合适的参数绑定方式。

    七、gitee 案例

    地址:ch04 · qiuqiu/SpringMVC - 码云 - 开源中国 (gitee.com)

  • 相关阅读:
    Linux控制---进程程序替换
    input输入路径,读取图片尺寸,移动手机截图“满屏”相同尺寸图片到别的文件夹
    AI工程化—— 如何让AI在企业多快好省的落地?
    开发 Diffusers 库的道德行为指南
    ObjectProvider学习
    创建型设计模式- C++实现
    《2022国民抑郁症蓝皮书》:94%的患者接受线上问诊
    蓝桥杯算法训练-共线
    2023最新PS(photoshop)Win+Mac免费下载安装包及教程内置AI绘画-网盘下载
    Java面试题之迭代器Iterator是什么?
  • 原文地址:https://blog.csdn.net/zhiqiuqiu2/article/details/134069198