SpringMVC系列数据绑定

2022-08-26 14:37:55

数据绑定概述

在执行程序时,SpringMVC根据客户端请求参数的不同将请求消息中的消息以一定的方式转换并绑定到控制器类的方法参数中。

在数据绑定过程中,SpringMVC会通过数据绑定组件(DataBinder)将请求参数串的内容进行类型转换,然后将转换后的值赋给控制器类中方法的形参。具体处理步骤如下:

  1. Spring MVC将ServletRequest对象传递给DataBinder
  2. 将处理方法的入参对象传递给DataBinder
  3. DataBinder调用ConversionService组件进行数据类型转换、数据格式化等工作,并将ServletRequest对象中的消息填充到参数对象中。
  4. 调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验。
  5. 校验完成后会生成数据绑定结果BindingResult对象,SpringMVC会将BindingResult对象中的内容赋给处理方法的相应参数。

根据客户端请求参数类型和个数的不同,将SpringMVC中的数据绑定主要分为简单数据绑定和复杂数据绑定。

项目的目录结构如下:
在这里插入图片描述

简单数据绑定

简单数据绑定包括绑定默认数据类型、绑定简单数据类型、绑定POJO类型、绑定包装POJO等。

绑定默认数据类型

常用的默认参数类型如下:

  • HttpServletRequest:通过request对象获取请求消息。
  • HttpServletResponse:通过response对象处理响应信息。
  • HttpSession:通过session对象得到session中存储的对象
  • Model/ModelMap:Model是一个接口,ModelMap是一个接口实现,作用是将Model数据填充到request域。

代码实现

下面以HttpServletRequest类型的使用为例:

1.创建一个Maven项目,并在pom.xml中添加相关的坐标,代码如下:

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!-- 版本锁定--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency></dependencies>

2.在web.xml中配置SpringMVC的前端控制器等消息。代码如下:

<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd"><web-app
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0"><display-name>Archetype Created Web Application</display-name><servlet><!--配置前端过滤器--><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--初始化时加载配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-config.xml</param-value></init-param><!--表示容器来启动时立即加载Servlet--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>

3.在springmvc-config.xml中配置组件扫描器和视图解析器

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd"><!--定义扫描器--><context:component-scan base-package="com.ssm.controller"/><!--视图解析器--><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"></property><property name="suffix" value=".jsp"></property></bean></beans>

4.编写控制类UserContoller

package com.ssm.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;@ControllerpublicclassUserController{@RequestMapping("/selectUser")public StringhandleRequest(HttpServletRequest request)throws Exception{//获取请求地址中的参数id的值
        String id= request.getParameter("id");
        System.out.println("id="+id);return"success";}}

在方法中使用了HttpServletRequest对象的getParameter()方法获取指定的参数,并返回了一个名为“success”的视图,SpringMVC会通过视图解析器在"WEB-INF/jsp"路径下寻找"success.jsp"文件。

5.success.jsp,该页面作为正确执行操作后的响应页面,没有其他业务逻辑,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java"%><html><head><title>入门程序</title></head><body>
OK! 执行成功.</body></html>

6.启动项目,在浏览器中访问地址http://localhost:8081/selectUser?id=2,我们可以在控制台看到,后台方法已从请求地址最终正确地获取到了id的参数信息。
在这里插入图片描述

绑定简单数据类型

简单数据类型的绑定是指Java中几种基本数据类型的绑定,如int、String、Double等类型

我们只需要将控制器类UserController中的selectUser()方法的参数修改为使用简单数据类型的形式即可,代码如下:

@RequestMapping("/selectUser")public StringhandleRequest(Integer id)throws Exception{
        System.out.println("id="+id);return"success";}

注意:
有时前台请求中参数名和后台控制器类方法中的形参名不一样,就会导致后台无法正确绑定并接收到前端请求的参数,我们可以通过Spring MVC提供的@RequestParam注解来进行间接数据绑定。

@RequestParam注解主要用于定义请求中的参数,属性参数如下所示:
在这里插入图片描述
@RequestParam注解的使用非常简单,假设浏览器的请求地址为http://localhost:8081/selectUser?user_id=2,那么在后台selectUser()方法中使用如下:

@RequestMapping("/selectUser")public StringhandleRequest(@RequestParam("user_id") Integer id)throws Exception{
        System.out.println("id="+id);return"success";}

需要注意的是:@RequestParam中的value属性需与前台传递过来的参数名一致。

绑定POJO类型

POJO类型的数据绑定就是将所有关联的请求参数封装在一个POJO中,然后在方法中直接使用该POJO作为形参来完成数据绑定。

我们将使用一个用户注册案例来演示POJO类型数据的绑定

User.java

用来封装用户注册的消息参数

package com.ssm.po;publicclassUser{private  Integer id;private  String username;private  String password;public IntegergetId(){return id;}publicvoidsetId(Integer id){this.id= id;}public StringgetUsername(){return username;}publicvoidsetUsername(String username){this.username= username;}public StringgetPassword(){return password;}publicvoidsetPassword(String password){this.password= password;}}

UserController.java

在控制器UserController类中编写向注册页面跳转和接收用户注册信息的方法,代码如下:

//向注册页面跳转@RequestMapping("/toRegister")public StringtoRegister(){return"register";}//接收用户注册信息@PostMapping("/registerUser")public  StringregisterUser(User user){
        System.out.println("username="+user.getUsername());
        System.out.println("password="+user.getPassword());return"success";}

register.jsp

在register.jsp编写用户注册表单,表单需要以POST方式提交,并且在提交时会发送一条以"registerUser"结尾的请求消息,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java"%><html><head><title>注册</title></head><body><form action="${pageContext.request.contextPath}/registerUser" method="post">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="text" name="password"><br/><input type="submit" value="注册"></form></body></html>

注意: 在使用POJO类型数据绑定时,前端请求的参数名(本例中指form表单内各元素的name属性值)必须要与绑定的POJO类中的属性名一样,这样才会自动将请求数据绑定到POJO对象中,否则后台接收的参数值为null

启动项目,在浏览器访问地址"http://localhost:8081/toRegister",就会跳转到注册页面register.jsp
在这里插入图片描述
输入用户名和密码,点击注册,浏览器会跳转到"success.jsp"页面,此时控制台输出成功如下:
在这里插入图片描述

注意:如果我们在用户名输入中文的时候,虽然浏览器可以正确跳转到success.jsp页面,但是在控制台输出中文信息的时候会出现乱码,我们只需要在web.xml中配置Spring提供的过滤编码器就可以解决中文乱码问题,代码如下:

<!--配置编码过滤器--><filter><filter-name>CharacterEncodeingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>CharacterEncodeingFilter</filter-name><url-pattern>/*</url-pattern>
  </filter-mapping>

上述代码中,通过< filter-mapping >元素的配置会拦截前端页面中的所有请求,并交由名称为CharacterEncodingFilter的编码过滤器类进行处理,我们在< filter >元素中通过初始化参数设置统一的编码为UTF-8。这样所有的请求信息都会以UTF-8的编码格式进行解析。

绑定包装POJO

所谓包装POJO,就是在一个POJO中包含另一个简单POJO,例如,在学生对象中包含班级对象。这样在使用时,就可以通过学生查询到班级信息。

班级类Banji和学生类Student

Student类用于封装学生和班级信息。

Banji.java

package com.ssm.po;publicclassBanji{private  Integer banji_id;//班级idprivate  String banji_name;//班级名public IntegergetBanji_id(){return banji_id;}publicvoidsetBanji_id(Integer banji_id){this.banji_id= banji_id;}public StringgetBanji_name(){return banji_name;}publicvoidsetBanji_name(String banji_name){this.banji_name= banji_name;}}

Student.java

package com.ssm.po;publicclassStudent{private  Integer stu_id;//学生idprivate  String stu_name;//学生姓名private  Banji banji;//学生所在班级public IntegergetStu_id(){return stu_id;}publicvoidsetStu_id(Integer stu_id){this.stu_id= stu_id;}public StringgetStu_name(){return stu_name;}publicvoidsetStu_name(String stu_name){this.stu_name= stu_name;}public BanjigetBanji(){return banji;}publicvoidsetBanji(Banji banji){this.banji= banji;}}

StudentContoller

在StudentContoller中编写一个跳转到学生查询页面的方法和一个查询学生及班级信息的方法,代码如下:

package com.ssm.controller;import com.ssm.po.Student;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;@ControllerpublicclassStudentController{//向学生查询页面跳转@RequestMapping("/tofindStudentWithBanji")public  StringtofindStudentWithBanji(){return"Student";}//查询学生和班级信息@PostMapping("/findStudentWithBanji")public  StringfindStudentWithBanji(Student student){
        System.out.println("stu_id="+student.getStu_id());
        System.out.println("banji_name="+student.getBanji().getBanji_name());return"success";}}

Student.jsp

在页面中编写通过学生编号和所属班级作为查询条件来查询学生信息,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java"%><html><head><title>学生查询</title></head><body><form action="${pageContext.request.contextPath}/findStudentWithBanji" method="post">
        学生编号:<input type="text" name="stu_id"><br/>
        所属班级:<input type="text" name="banji.banji_name"><br/><input type="submit" value="查询"></form></body></html>

注意:在使用包装POJO类型数据绑定时,前端请求的参数名编写必须符号以下两种情况:

  1. 如果查询条件参数是包装类的直接基本属性,参数名就直接用对应的属性名,如上述代码中的stu_id
  2. 如果查询条件参数是包装类中POJO的子属性,参数名就必须为【对象.属性】,其中【对象】要和包装POJO中的对象属性名称一致,【属性】要和包装POJO中的对象子属性一致,如上述代码中的banji.banji_name;

启动项目,访问地址http://localhost:8081/tofindStudentWithBanji,显示如下:
在这里插入图片描述

点击查询按钮后,浏览器会跳转到success.jsp,此时控制台输出为:
在这里插入图片描述

除了上述几种简单数据绑定外,有些特殊类型的参数无法在后台进行直接转换的,例如日期数据需要我们自定义转换器(Converter)或格式化(Formatter)进行数据绑定。

自定义类型转换器

我们自定义日期数据类型转换器

1.实现Converter接口

定义一个类,实现Converter接口,该接口有两个泛型

package com.ssm.converter;import org.springframework.core.convert.converter.Converter;import org.springframework.util.StringUtils;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;publicclassStringToDateConverterimplementsConverter<String,Date>{@Overridepublic Dateconvert(String s){
        DateFormat format= null;try{if(StringUtils.isEmpty(s)){thrownewNullPointerException("请输入要转换的日期");}
            format=newSimpleDateFormat("yyyy-MM-dd");
            Date date= format.parse(s);return  date;}
  • 作者:冬瓜闯世界
  • 原文链接:https://blog.csdn.net/qq_43404873/article/details/109876190
    更新时间:2022-08-26 14:37:55