spirng 数据绑定

Posted shi_zi_183

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spirng 数据绑定相关的知识,希望对你有一定的参考价值。

数据绑定

数据绑定介绍

在执行程序时,Spring MVC会根据客户端请求参数的不同,将请求消息中的信息以一定的方式转换并绑定到控制器类的方法参数中。这种将请求消息数据与后台方法参数建立连接的过程就是Spring MVC中的数据绑定。
在数据绑定过程中,Spring MVC框架会通过数据绑定组件将请求参数串的内容进行类型转换,然后将转换后的值赋给控制器类中方法的形参,这样后台方法就可以正确绑定并获取客户端请求携带的参数了。
1)Spring MVC将ServletRequest对象传递给DataBinder。
2)将处理方法的入参对象传递给DataBinder。
3)DataBinder调用ConversionService组件进行数据类型转换、数据格式化等工作,并将ServletRequest对象中的消息填充到参数对象中。
4)调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验。
5)校验完成后会生成数据绑定结果BindingResult对象,Spring MVC会将BindingResult对象中的内容赋给处理方法的相应参数。
根据客户端请求参数类型和个数的不同,我们将Spring MVC中的数据绑定主要分为简单数据绑定和复杂数据绑定

简单数据绑定

绑定默认数据类型

当前端请求的参数比较简单时,可以在后台方法的形参中直接使用Spring MVC提供的默认参数类型进行数据绑定。
常用的默认参数类型
1、HttpServletRequest:通过request对象获取请求信息
2、HttpServletResponse:通过response处理响应信息
3、HttpSession:通过session对象的得到session中存储的对象
4、Model/ModelMap:Model是一个接口,ModelMap是一个接口实现,作用是将model数据填充到request域。
1)在Eclipse中,创建一个名为chapter13的Web项目,然后将Spring MVC相关JAR包添加到项目的lib目录下,并发布到类路径中。添加JAR包后的lib目录。
2)在web.xml中,配置Spring MVC的前端控制器等信息。
3)在src目录下,创建SpringMVC的核心配置文件springmvc-config.xml,在该文件中配置组件扫描器和视图解析器。
springmvc-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="com.ex.controller"/>
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/WEB-INF/jsp/"/>
	<property name="suffix" value=".jsp"/>
</bean>
</beans>

4)在src目录下,创建一个com.ex.controller包,在该包下创建一个用于用户操作的控制器类UserController

package com.ex.controller;

import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {
	@RequestMapping("/selectUser")
	public String selectUser(HttpServletRequest request){
		String id=request.getParameter("id");
		System.out.println("id="+id);
		return "success";
	}
}

5)在WEB-INF目录下,创建一个名为jsp的文件夹,然后在该文件夹中创建页面文件success,jsp,该界面只作为正确执行操作后的响应页面,没有其他业务逻辑

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
  ok
</body>
</html>

6)将项目发布到Tomcat中并启动,在浏览访问。

绑定简单数据类型

简单数据类型的绑定,就是指Java中几种基本数据类型的绑定,如int、String、Double等类型。
1)首先修改控制器类,将控制器中的方法的参数修改为使用简单数据类型的形式

	@RequestMapping("/selectUser")
	public String selectUser(int id){
		System.out.println("id="+id);
		return "success";
	}

与默认数据类型案例中的selectUser()方法相比,此方法中只是将HttpServletRequest参数替换为了Integer类型。
启动项目,用浏览器打开查看

需要注意的是,有时候前端请求中的参数名和后台控制器类方法中的形参名不一样,这就会导致后台无法正确绑定并接收到前端请求的参数。为此,Spring MVC提供了RequestParam注解来进行间接数据绑定。
@RequestParam注解主要用于对请求中的参数进行定义,在使用时可以指定它的4个属性

属性说明
valuename属性的别名,这里指参数的名字,即入参的请求参数名字,如value="item_id"表示请求的参数中名字为item_id的参数的值将传入。如果只使用value属性,则可以省略value属性名
name指定请求头绑定的名称,同value
require用于指定参数是否必须,默认是true,表示请求中一定要有相应的参数
defaultValue默认值,表示如果请求中没有同名参数时的默认值
	@RequestMapping("/selectUser")
	public String selectUser(@RequestParam(value="user_id")Integer id){
		System.out.println("id="+id);
		return "success";
	}

绑定POJO类型

在使用简单数据类型绑定时,可以很容易地根据具体需求来定义方法中地形参类型和个数,然而在实际应用中,客户端请求可能会传递多个不同类型地参数数据,如果还使用简单数据类型进行绑定,那么就需要手动编写多个不同类型地参数,这种操作显然比较繁琐。此时就可以使用POJO类型进行数据绑定。
POJO类型的数据绑定就是将所有关联的请求参数封装在一个POJO中,然后在方法中直接使用该POJO作为形参来完成数据绑定。
1)在src目录下,创建一个com.ex.po包,在包下创建一个User类来封装用户注册的信息参数
User.java

package com.ex.po;
public class User {
	private Integer id;
	private String username;
	private Integer password;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public Integer getPassword() {
		return password;
	}
	public void setPassword(Integer password) {
		this.password = password;
	}
}

2)在控制器UserController类中,编写接受用户注册信息和向注册页面跳转地方法

	@RequestMapping("/toRegister")
	public String toRegister(){
		return "register";
	}
	@RequestMapping("/registerUser")
	public String registerUser(User user){
		String username=user.getUsername();
		Integer password=user.getPassword();
		System.out.println("username="+username);
		System.out.println("password="+password);
		return "success";
	}

3)在/WEB-INF/jsp目录下,创建一个用户注册页面register.jsp,在该界面中编写用户注册表单,表单需要以POST方式提交,并且在提交时会发送一条以"/registerUser"结尾地请求消息。
register.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="${pageContext.request.contextPath}/registerUser" method="post">
		用户名:<input type="text name="username"/><br/> 
		密码:<input type="password" name="password"/><br/>
		<input type="submit" value="注册"/>
	</form>
</body>
</html>

4)将项目发布到Tomcat服务器并启动,浏览器访问



解决请求参数中文乱码


可以看到,密码信息已正确显示,用户名却是乱码。
为了防止前端传入的中文出现乱码问题,我们可以使用Spring提供的编码过滤器来统一编码,要使用编码过滤器,执行在web.xml中添加如下代码

<filter>
  	<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

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

绑定包装POJO

使用简单POJO类型已经完成多数的数据绑定,但有时客户端请求中传递的参数会比较复杂。例如,在用户查询订单时,页面传递的参数可能包括订单编号、用户名等信息,这就包括了订单和用户两个对象的信息,如果将订单和用户的所有查询条件都封装在一个简单POJO中,显然会比较混乱,这时就可以考虑使用包装POJO类型的数据绑定。
1)在chapter13项目的com.ex.po包中,创建一个订单类,Orders,该类用于封装订单和用户信息
Orders.java

package com.ex.po;
public class Orders {
	private Integer ordersId;
	private User user;
	public Integer getOrdersId() {
		return ordersId;
	}
	public void setOrdersId(Integer ordersId) {
		this.ordersId = ordersId;
	}
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
}

在上述包中装类POJO类中,定义了订单号和用于POJO的属性及其对应的getter/setter方法。这样订单类中不仅可以封装订单的基本属性参数,还可以封装User类型的属性参数。
2)在com.ex.controler包中,创建一个订单控制器类OrdersController,在该类中编写一个跳转到订单查询页面的方法和一个查询订单及用户信息的方法
OrdersController.java

	@RequestMapping("findOrdersWithUser")
	public String findOrdersWithUser(Orders orders){
		Integer orderId=orders.getOrdersId();
		User user=orders.getUser();
		String username=user.getUsername();
		System.out.println("ordersId="+ordersId);
		System.out.println("username="+username);
		return "success";
	}

3)在/WEB-INF/jsp目录下,创建一个用户订单查询页面orders.jsp,在页面中编写通过订单编号和所属用户作为查询条件来查询订单信息的代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="${pageContext.request.contextPath }/findOrdersWithUser" method="post">
		订单编号:<input type="text" name="ordersId"/><br>
		所属用户:<input type="text" name="user.username"/><br>
		<input type="submit" value="查询">
	</form>
</body>
</html>

4)浏览器访问

自定义数据绑定

在一般情况下,使用基本数据类型和POJO类型的参数数据,然而有些特殊类型的参数是无法在后台进行直接转换的,例如日期数据就需要开发自定义转换器或格式化来进行数据绑定。
1、Converter
Spring框架提供了一个Converter用于将一种类型的对象转换为另一种类型的对象。例如,用户输入的日期形式可能是"2017-04-08"或"2017/04/08"的字符串,而要Spring将输入的日期与后天的Date进行绑定,则需要将字符串转换为日期,此时就可以自定义一个Converter类来进行日期转换。
自定义Converter类需要实现org.springframework.core.convert.converter.Converter接口

public interface Converter<S,T>{
	T convert (S source);
}

在上述接口代码中,泛型中的S表示源类型,T表示目标类型,而convert(S source)表示接口中的方法。
在src目录下,创建一个com.ex.convert包,在该包下创建日期转换类DataConverter,并在该类接口中编写将String类型转化成Date类型的代码,
DateConverter.java

package com.ex.convert;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
public class DateConverter implements Converter<String,Date>{
	private String datePattern="yyyy-MM-dd HH:mm:ss";
	@Override
	public Date convert(String source) {
		SimpleDateFormat sdf=new SimpleDateFormat(datePattern);
		try{
			return sdf.parse(source);
		}catch (ParseException e){
			throw new IllegalArgumentException("无效的日期格式,请使用这种格式:"+datePattern);
		}
	}
	
}

在上述代码中,DateConverter类实现了Converter接口,该接口中第一个类型String表示需要被转换的数据类型,第二个类型Date表示需要转换成的目标类型。
为了让Spring MVC知道并使用这个转换器类,还需要在其配置文件中编写一个id为conversionService的Bean
springmvc-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
	<context:component-scan base-package="com.ex.controller"/>
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/WEB-INF/jsp/"/>
	<property name="suffix" value=".jsp"/>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	<property name="conversion">
		<set>
			<bean class="com.ex.convert.DateConverter"/>
		</set>
	</property>
</bean>
</beans>

首先添加了3个mvc的schema信息;然后定义了组件扫描器和视图解析器;接下来显示装配了自定义的类型转换器;最后编写了自定义类型转换器的配置,其中Bean的类名称必须为org.springframework.context.support.ConversionServiceFactoryBean,并且Bean中还需要包含一个converters属性,通过该属性列出程序中自定义的所有Converter。
为了测试转换器的使用,可以在com.ex.controller包中创建一个日期控制类DateController,并在类中编写绑定日期数据的方法。

package com.ex.controller;

import java.util.Date;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class DateController {
	@RequestMapping("/customDate")
	public String CustomDate(Date date){
		System.out.println("date="+date);
		return "success";
	}
}


注意:日期数据之间的空格。
2、Formatter
除了使用Converter进行转换外,我们还可以使用Formatter来进行类型转换。Formatter与Converter的作用相同,只是Formatter的源类型必须是一个String类型,而Converter可以是任意类型。
使用Formatter自定义转化器类需要实现org.springframework.format.Formatter

以上是关于spirng 数据绑定的主要内容,如果未能解决你的问题,请参考以下文章

后端Mybatis操作数据库 & Spirng整合Mybatis

如何初始化片段中的绑定属性以使双向数据绑定工作

有没有更聪明的方法将布局绑定到片段?

Spirng 分层,增加数据访问对象层

Spirng 分层,增加数据访问对象层

如何用 Android 数据绑定替换 androidx.fragment.app.FragmentContainerView 中的片段